diff --git a/app/assets/javascripts/discourse/components/small-action.js.es6 b/app/assets/javascripts/discourse/components/small-action.js.es6
index 54ef41b9f..567436348 100644
--- a/app/assets/javascripts/discourse/components/small-action.js.es6
+++ b/app/assets/javascripts/discourse/components/small-action.js.es6
@@ -1,4 +1,5 @@
-import { relativeAge } from 'discourse/lib/formatter';
+import { autoUpdatingRelativeAge } from 'discourse/lib/formatter';
+import computed from 'ember-addons/ember-computed-decorators';
 
 const icons = {
   'closed.enabled': 'lock',
@@ -13,16 +14,20 @@ const icons = {
   'pinned_globally.disabled': 'thumb-tack unpinned',
   'visible.enabled': 'eye',
   'visible.disabled': 'eye-slash',
-  'split_topic': 'sign-out'
+  'split_topic': 'sign-out',
+  'invited_user': 'plus-circle',
+  'removed_user': 'minus-circle'
 };
 
-export function actionDescription(actionCode, createdAt) {
+export function actionDescription(actionCode, createdAt, username) {
   return function() {
     const ac = this.get(actionCode);
     if (ac) {
       const dt = new Date(this.get(createdAt));
-      const when =  relativeAge(dt, {format: 'medium-with-ago'});
-      return I18n.t(`action_codes.${ac}`, {when}).htmlSafe();
+      const when = autoUpdatingRelativeAge(dt, { format: 'medium-with-ago' });
+      const u = this.get(username);
+      const who = u ? `<a class="mention" href="/users/${u}">@${u}</a>` : "";
+      return I18n.t(`action_codes.${ac}`, { who, when }).htmlSafe();
     }
   }.property(actionCode, createdAt);
 }
@@ -31,18 +36,19 @@ export default Ember.Component.extend({
   layoutName: 'components/small-action', // needed because `time-gap` inherits from this
   classNames: ['small-action'],
 
-  description: actionDescription('actionCode', 'post.created_at'),
+  description: actionDescription('actionCode', 'post.created_at', 'post.action_code_who'),
 
-  icon: function() {
-    return icons[this.get('actionCode')] || 'exclamation';
-  }.property('actionCode'),
+  @computed("actionCode")
+  icon(actionCode) {
+    return icons[actionCode] || 'exclamation';
+  },
 
   actions: {
-    edit: function() {
+    edit() {
       this.sendAction('editPost', this.get('post'));
     },
 
-    delete: function() {
+    delete() {
       this.sendAction('deletePost', this.get('post'));
     }
   }
diff --git a/app/controllers/topics_controller.rb b/app/controllers/topics_controller.rb
index b049438b6..4a9c0fec3 100644
--- a/app/controllers/topics_controller.rb
+++ b/app/controllers/topics_controller.rb
@@ -347,7 +347,7 @@ class TopicsController < ApplicationController
     topic = Topic.find_by(id: params[:topic_id])
     guardian.ensure_can_remove_allowed_users!(topic)
 
-    if topic.remove_allowed_user(params[:username])
+    if topic.remove_allowed_user(current_user, params[:username])
       render json: success_json
     else
       render json: failed_json, status: 422
diff --git a/app/models/topic.rb b/app/models/topic.rb
index 5f470c509..022efc498 100644
--- a/app/models/topic.rb
+++ b/app/models/topic.rb
@@ -524,7 +524,8 @@ class Topic < ActiveRecord::Base
                               no_bump: opts[:bump].blank?,
                               skip_notifications: opts[:skip_notifications],
                               topic_id: self.id,
-                              skip_validations: true)
+                              skip_validations: true,
+                              custom_fields: opts[:custom_fields])
     new_post = creator.create
     increment!(:moderator_posts_count) if new_post.persisted?
 
@@ -557,11 +558,19 @@ class Topic < ActiveRecord::Base
     changed_to_category(cat)
   end
 
-  def remove_allowed_user(username)
+  def remove_allowed_user(removed_by, username)
     if user = User.find_by(username: username)
       topic_user = topic_allowed_users.find_by(user_id: user.id)
       if topic_user
         topic_user.destroy
+        # add small action
+        self.add_moderator_post(
+          removed_by,
+          nil,
+          post_type: Post.types[:small_action],
+          action_code: "removed_user",
+          custom_fields: { action_code_who: user.username }
+        )
         return true
       end
     end
@@ -575,6 +584,14 @@ class Topic < ActiveRecord::Base
       # If the user exists, add them to the message.
       user = User.find_by_username_or_email(username_or_email)
       if user && topic_allowed_users.create!(user_id: user.id)
+        # Create a small action message
+        self.add_moderator_post(
+          invited_by,
+          nil,
+          post_type: Post.types[:small_action],
+          action_code: "invited_user",
+          custom_fields: { action_code_who: user.username }
+        )
 
         # Notify the user they've been invited
         user.notifications.create(notification_type: Notification.types[:invited_to_private_message],
diff --git a/app/serializers/post_serializer.rb b/app/serializers/post_serializer.rb
index 259c781d2..2fd245c45 100644
--- a/app/serializers/post_serializer.rb
+++ b/app/serializers/post_serializer.rb
@@ -62,7 +62,8 @@ class PostSerializer < BasicPostSerializer
              :user_custom_fields,
              :static_doc,
              :via_email,
-             :action_code
+             :action_code,
+             :action_code_who
 
   def initialize(object, opts)
     super(object, opts)
@@ -313,6 +314,14 @@ class PostSerializer < BasicPostSerializer
     object.action_code.present?
   end
 
+  def action_code_who
+    post_custom_fields["action_code_who"]
+  end
+
+  def include_action_code_who?
+    include_action_code? && action_code_who.present?
+  end
+
   private
 
     def post_actions
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 80f7a596f..f8df19ae1 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -121,6 +121,8 @@ en:
 
     action_codes:
       split_topic: "split this topic %{when}"
+      invited_user: "invited %{who} %{when}"
+      removed_user: "removed %{who} %{when}"
       autoclosed:
         enabled: 'closed %{when}'
         disabled: 'opened %{when}'
diff --git a/lib/topic_view.rb b/lib/topic_view.rb
index 7db989d45..9072610f5 100644
--- a/lib/topic_view.rb
+++ b/lib/topic_view.rb
@@ -16,6 +16,10 @@ class TopicView
     20
   end
 
+  def self.default_post_custom_fields
+    @default_post_custom_fields ||= ["action_code_who"]
+  end
+
   def self.post_custom_fields_whitelisters
     @post_custom_fields_whitelisters ||= Set.new
   end
@@ -25,7 +29,8 @@ class TopicView
   end
 
   def self.whitelisted_post_custom_fields(user)
-    post_custom_fields_whitelisters.map { |w| w.call(user) }.flatten.uniq
+    wpcf = default_post_custom_fields + post_custom_fields_whitelisters.map { |w| w.call(user) }
+    wpcf.flatten.uniq
   end
 
   def initialize(topic_id, user=nil, options={})
diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb
index 6a8eb9d76..b5d15f36e 100644
--- a/spec/models/topic_spec.rb
+++ b/spec/models/topic_spec.rb
@@ -378,7 +378,7 @@ describe Topic do
             expect(topic.invite(topic.user, walter.username)).to eq(true)
             expect(topic.allowed_users.include?(walter)).to eq(true)
 
-            expect(topic.remove_allowed_user(walter.username)).to eq(true)
+            expect(topic.remove_allowed_user(topic.user, walter.username)).to eq(true)
             topic.reload
             expect(topic.allowed_users.include?(walter)).to eq(false)
           end
@@ -386,6 +386,11 @@ describe Topic do
           it 'creates a notification' do
             expect { topic.invite(topic.user, walter.username) }.to change(Notification, :count)
           end
+
+          it 'creates a small action post' do
+            expect { topic.invite(topic.user, walter.username) }.to change(Post, :count)
+            expect { topic.remove_allowed_user(topic.user, walter.username) }.to change(Post, :count)
+          end
         end
 
         context 'by email' do