diff --git a/Gemfile b/Gemfile
index 1c5d41ed5d182ae7d779c1bf65a5b2fcfb1ad8ca..f348350941ce4f5ebf2821ee35151bb694e14b5e 100644
--- a/Gemfile
+++ b/Gemfile
@@ -13,6 +13,8 @@ gem 'ohai', '0.5.8', :require => false #Chef dependency
 gem 'nokogiri'
 gem 'settingslogic', '2.0.6'
 
+gem 'vanna', :git => "git://github.com/MikeSofaer/vanna.git"
+
 #Security
 gem 'devise', '~> 1.3.1'
 gem 'devise_invitable', '0.5.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 8e0de7ceb6b4267fb44ac26af6cc38912c196790..0a68e9119571f511f04a28512aa588bebc55c279 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -14,6 +14,14 @@ GIT
     sod (0.0.1)
       net-scp
 
+GIT
+  remote: git://github.com/MikeSofaer/vanna.git
+  revision: 334eec220dbfddcc6bd3108e6e6c77fec8484dc4
+  specs:
+    vanna (0.1.1)
+      json
+      rails (>= 3.0.0)
+
 GIT
   remote: git://github.com/diaspora/acts-as-taggable-on.git
   revision: c3592fe1a906f6ff1cd12766c5cf1152c51eec40
@@ -454,6 +462,7 @@ DEPENDENCIES
   thin (= 1.2.11)
   twitter (= 1.5.0)
   typhoeus
+  vanna!
   webmock
   will_paginate (= 3.0.pre2)
   yard
diff --git a/app/controllers/notifications_controller.rb b/app/controllers/notifications_controller.rb
index 729c7b882f5c106859c5b1e6490353c3ed33c959..c52bac4ff9cd8f0a5f7a2c2a1128e365f98c6cf6 100644
--- a/app/controllers/notifications_controller.rb
+++ b/app/controllers/notifications_controller.rb
@@ -2,9 +2,7 @@
 #   licensed under the Affero General Public License version 3 or later.  See
 #   the COPYRIGHT file.
 
-class NotificationsController < ApplicationController
-  before_filter :authenticate_user!
-  respond_to :html, :json
+class NotificationsController < VannaController
 
 
   def update
@@ -21,7 +19,7 @@ class NotificationsController < ApplicationController
     @aspect = :notification
     conditions = {:recipient_id => current_user.id}
     page = params[:page] || 1
-    @notifications = WillPaginate::Collection.create(page, 25, Notification.where(conditions).count ) do |pager|
+    notifications = WillPaginate::Collection.create(page, 25, Notification.where(conditions).count ) do |pager|
       result = Notification.find(:all,
                                  :conditions => conditions,
                                  :order => 'created_at desc',
@@ -33,8 +31,8 @@ class NotificationsController < ApplicationController
       pager.replace(result)
     end
 
-    @group_days = @notifications.group_by{|note| I18n.l(note.created_at, :format => I18n.t('date.formats.fullmonth_day')) }
-    respond_with @notifications
+    group_days = notifications.group_by{|note| I18n.l(note.created_at, :format => I18n.t('date.formats.fullmonth_day')) }
+    {:group_days => group_days, :current_user => current_user, :notifications => notifications}
   end
 
   def read_all
diff --git a/app/controllers/vanna_controller.rb b/app/controllers/vanna_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..42545f8b392e39d4f9d7dc032d5473f943589f0d
--- /dev/null
+++ b/app/controllers/vanna_controller.rb
@@ -0,0 +1,120 @@
+#   Copyright (c) 2010, Diaspora Inc.  This file is
+#   licensed under the Affero General Public License version 3 or later.  See
+#   the COPYRIGHT file.
+
+class VannaController < Vanna::Base
+  include Devise::Controllers::Helpers
+  include AspectGlobalHelper
+  helper :layout
+  helper_method :current_user
+  helper_method :flash
+  config.stylesheets_dir = "public/stylesheets"
+  layout "application"
+  include ActionController::Flash
+  default_url_options[:host] = "localhost"
+  include ActionController::MobileFu::InstanceMethods
+  helper_method :is_mobile_device?
+
+  protect_from_forgery :except => :receive
+
+  before_filter :authenticate_user!
+  before_filter :ensure_http_referer_is_set
+  before_filter :set_header_data, :except => [:create, :update]
+  before_filter :set_invites
+  before_filter :set_locale
+  before_filter :set_git_header if (AppConfig[:git_update] && AppConfig[:git_revision])
+  before_filter :which_action_and_user
+  prepend_before_filter :clear_gc_stats
+  before_filter :set_grammatical_gender
+
+  def ensure_http_referer_is_set
+    request.env['HTTP_REFERER'] ||= '/aspects'
+  end
+
+  def set_header_data
+    if user_signed_in?
+      if request.format.html? && !params[:only_posts]
+        @aspect = nil
+        @notification_count = Notification.for(current_user, :unread =>true).count
+        @unread_message_count = ConversationVisibility.sum(:unread, :conditions => "person_id = #{current_user.person.id}")
+      end
+      @object_aspect_ids = []
+      @all_aspects = current_user.aspects
+    end
+  end
+
+  def ensure_page
+    params[:page] = params[:page] ? params[:page].to_i : 1
+  end
+
+  def set_invites
+    if user_signed_in?
+      @invites = current_user.invites
+    end
+  end
+
+  def set_git_header
+    headers['X-Git-Update'] = AppConfig[:git_update]
+    headers['X-Git-Revision'] = AppConfig[:git_revision]
+  end
+
+  def which_action_and_user
+    str = "event=request_with_user controller=#{self.class} action=#{self.action_name} "
+    if current_user
+      str << "uid=#{current_user.id} "
+      str << "user_created_at='#{current_user.created_at.to_date.to_s}' user_created_at_unix=#{current_user.created_at.to_i} " if current_user.created_at
+      str << "user_non_pending_contact_count=#{current_user.contacts.size} user_contact_count=#{Contact.unscoped.where(:user_id => current_user.id).size} "
+    else
+      str << 'uid=nil'
+    end
+    Rails.logger.info str
+  end
+
+  def set_locale
+    if user_signed_in?
+      I18n.locale = current_user.language
+    else
+      I18n.locale = request.compatible_language_from AVAILABLE_LANGUAGE_CODES
+    end
+
+    WillPaginate::ViewHelpers.pagination_options[:previous_label] = "&laquo; #{I18n.t('previous')}"
+    WillPaginate::ViewHelpers.pagination_options[:next_label] = "#{I18n.t('next')} &raquo;"
+  end
+
+  def clear_gc_stats
+    GC.clear_stats if GC.respond_to?(:clear_stats)
+  end
+
+  def redirect_unless_admin
+    unless current_user.admin?
+      redirect_to root_url, :notice => 'you need to be an admin to do that'
+      return
+    end
+  end
+
+  def set_grammatical_gender
+    if (user_signed_in? && I18n.inflector.inflected_locale?)
+      gender = current_user.profile.gender.to_s.tr('!()[]"\'`*=|/\#.,-:', '').downcase
+      unless gender.empty?
+        i_langs = I18n.inflector.inflected_locales(:gender)
+        i_langs.delete  I18n.locale
+        i_langs.unshift I18n.locale
+        i_langs.each do |lang|
+          token = I18n.inflector.true_token(gender, :gender, lang)
+          unless token.nil?
+            @grammatical_gender = token
+            break
+          end
+        end
+      end
+    end
+  end
+
+  def grammatical_gender
+    @grammatical_gender || nil
+  end
+
+  def after_sign_in_path_for(resource)
+      stored_location_for(:user) || aspects_path(:a_ids => current_user.aspects.where(:open => true).select(:id).all.map{|a| a.id})
+  end
+end
diff --git a/app/views/notifications/index.html.haml b/app/views/notifications/index.html.haml
index a77472fcee8b9cf5ce577638fc91e6cf02c57fd9..bf1141c3cedda813221ec5187cf50234eecdb891 100644
--- a/app/views/notifications/index.html.haml
+++ b/app/views/notifications/index.html.haml
@@ -1,3 +1,6 @@
+-self.extend AspectGlobalHelper
+-self.extend AspectsHelper
+-self.extend ApplicationHelper
 .span-13
   %h2
     %span.notification_count{:class => ('unread' if @notification_count > 0)}
@@ -8,7 +11,7 @@
 
 .span-24.last
   .stream.notifications
-    - @group_days.each do |day, notes|
+    - group_days.each do |day, notes|
       .day_group.span-24.last
         .span-3
           .date
@@ -28,4 +31,4 @@
               %br
               %time= timeago(note.created_at)
         .span-13.last
-    = will_paginate @notifications
+    = will_paginate notifications