| name | avo-collaboration |
| description | Add comments, emoji reactions, and an automatic change-log timeline to an Avo record through the avo-collaboration add-on. Use when the user wants a team discussion or notes thread next to a record's data, emoji reactions on comments, a timeline/activity feed on a record's page, to automatically log when a field changes (e.g. status), to let users delete their own comments, or team collaboration inside the admin. Covers installing the add-on, enabling it per resource with `self.collaboration` (author name, watchers, reactions), placing the timeline with `collaboration_timeline`, the three authorization policy methods, and extending the collaboration models. |
| allowed-tools | Read, Edit, Write, Glob, Grep, Bash, WebFetch |
| metadata | {"requires-gem":"avo-collaboration — paid add-on, Beta (https://avohq.io/addons/collaboration)"} |
Avo Collaboration
Collaboration is a paid Avo add-on (currently Beta) that drops a timeline onto a record's Show page: users post comments, react with emoji, and see automatic entries whenever a watched attribute changes. It keeps the discussion next to the data instead of scattered across Slack, email, and tickets. Enable it per resource with the self.collaboration hash, render it with collaboration_timeline inside def fields, and gate access through three policy methods on the resource's Pundit policy. It builds on Avo's authorization layer, so comments, reactions, and auto-entries all flow through your existing policies — see the sibling avo-authorization skill. The timeline itself is a field-level DSL call, so placement follows the same rules as any other field — see avo-fields.
Docs
Authoritative docs — fetch on demand rather than guessing, and verify every option name against the docs or the app's installed avo-collaboration source before writing it:
When this applies
Explicit (Avo / collaboration named): "enable collaboration on the Project resource", "add the collaboration timeline", "configure self.collaboration", "customize the collaboration reaction emoji", "add the collaboration policy methods", "extend Avo::Collaboration::Comment".
Implicit (feature-shaped, no mention of the add-on): "let the team discuss a record in the admin", "add comments to a record", "a notes / discussion thread next to the data", "emoji reactions on comments", "a timeline / activity feed on a record's page", "automatically log when a record's status changes", "record a note whenever a field changes", "let users delete their own comments but not the auto-generated log", "team collaboration inside the admin panel".
Install
The add-on ships as a private gem and installs its migrations (there is no install generator — it's a Rails engine migration task):
gem "avo-collaboration", source: "https://packager.dev/avo-hq"
bundle
bin/rails avo_collaboration:install:migrations
bin/rails db:migrate
This creates the avo_collaboration_entries, avo_collaboration_comments, avo_collaboration_actions, and avo_collaboration_reactions tables. After migrating, enable the feature on a resource (below). A valid Avo license that includes the add-on is required; the gem source is private, so bundle fails without credentials for packager.dev/avo-hq.
Workflow
1. Enable collaboration on a resource
Add self.collaboration to the resource. This one attribute turns on the timeline; the model gets an after_update hook that records automatic entries for watched attributes.
class Avo::Resources::Project < Avo::BaseResource
self.collaboration = {
author: {
name_property: :name
},
watchers: [
{
property: :name,
message: -> { "#{property} changed: #{old_value} -> #{new_value}" }
},
{
property: :status,
i18n_message_key: "avo.collaboration.custom_property_changed_html"
},
{
property: :stage
}
]
}
def fields
field :id, as: :id
field :name, as: :text
field :status, as: :text
field :stage, as: :select, options: ["Not Started", "In Progress", "Completed"]
collaboration_timeline
end
end
The hash has three top-level keys, all optional individually — but self.collaboration must be present (even {}) for the timeline to appear:
author — display only. The author of every comment, reaction, and auto-entry is always Avo::Current.user; name_property just tells the timeline which attribute on that user holds the display name (author: { name_property: :name }).
watchers — an array; see step 2.
reactions — emoji customization; see step 3.
2. Watch attribute changes (automatic log entries)
Each watcher records an entry when its property changes on the record (fires on update, reading record.previous_changes). Every watcher needs a property; the message is optional:
message: proc — full control. Executed with resource, record, property, old_value, and new_value in scope (via Avo::ExecutionContext), so -> { "#{property}: #{old_value} -> #{new_value}" } works.
i18n_message_key: String — a translation key instead of a proc. Interpolates %{property}, %{old_value}, and %{new_value}. If the key ends in _html, Rails renders it as safe HTML (markup allowed without escaping).
- Neither — Avo falls back to the
avo.collaboration.property_changed translation.
en:
avo:
collaboration:
custom_property_changed_html: changed %{property} to %{new_value} <span class="font-bold">[Custom]</span>
With no watchers (or an empty array), the timeline still works for comments and reactions — there just won't be any automatic property-change entries.
3. Customize reactions
Reactions are always enabled. Omit the reactions key and Avo uses its default 10-emoji set: 👍 👎 😀 🎉 😕 ❤️ 🚀 👀 💡 🔥. Supply options to replace that list wholesale:
self.collaboration = {
author: { name_property: :name },
watchers: [{ property: :status }],
reactions: {
options: %w[👍 👎 ❤️ 🚀 👀]
}
}
4. Place the timeline
Call collaboration_timeline (no arguments) inside def fields to render the timeline where you want it. Because it's a field-level DSL call, it honors the surrounding layout — you can drop it in a sidebar, a panel, or inline among other fields:
def fields
field :id, as: :id
field :name
sidebar do
collaboration_timeline
end
end
5. Add the authorization policy methods
Collaboration adds three boolean methods to the resource's Pundit-style policy (app/policies/<model>_policy.rb). Without them, Avo's authorization defaults apply. This depends on Avo's authorization system being set up — see the avo-authorization skill.
class ProjectPolicy < ApplicationPolicy
def collaboration_view_timeline?
show?
end
def collaboration_create_entry?
current_user.team_member? && show?
end
def collaboration_destroy_entry?
return true if current_user.admin?
record.is_a?(Avo::Collaboration::Comment) && record.author == current_user
end
end
The record passed to collaboration_destroy_entry? is the entry's underlying model — an Avo::Collaboration::Comment for a user comment, or an Avo::Collaboration::Action for an automatic entry. Both respond to author (delegated to the entry). The type check is what lets you allow deleting own comments while blocking deletion of the auto-generated log.
6. (Optional) Extend the collaboration models
To hook domain logic (associations, validations, callbacks) onto collaboration events, reopen the models inside Rails.configuration.to_prepare so it survives code reloading:
Rails.configuration.to_prepare do
Avo::Collaboration::Action.class_eval do
after_create { SlackNotificationService.notify(message: "New action: #{body}") }
end
Avo::Collaboration::Comment.class_eval do
validates :body, presence: true, length: { maximum: 5000 }
end
Avo::Collaboration::Entry.class_eval do
after_create { DiscordNotificationService.notify(message: "New entry: #{body}") }
end
end
The three models: Avo::Collaboration::Comment (user comment), Avo::Collaboration::Action (auto-generated watcher entry), and Avo::Collaboration::Entry (the delegated_type wrapper over both, plus reactions). Add only what your app needs.
7. (Optional) Eager-load the timeline to avoid N+1
On the Show view the timeline loads every entry with its author and target. On busy records, eager-load them via the resource's Show-only includes:
self.single_includes = [avo_collaboration_entries: [:entryable, :author, :target]]
Gotchas
- Beta + paid add-on. Flag both to the user. The gem source (
packager.dev/avo-hq) is private — bundle fails without Avo license credentials.
- Install is a migrations task, not a generator. It's
bin/rails avo_collaboration:install:migrations (a Rails engine task), then db:migrate. There is no avo:collaboration generator.
- The author is always
Avo::Current.user. author.name_property only controls the display name — it does not choose who the author is. There's no way to attribute an entry to a different user via config.
- A watcher needs a
property. With no watchers the timeline still does comments and reactions — you just get no automatic change-log entries. Watchers fire on record update (from previous_changes), not on create.
message proc scope is fixed: resource, record, property, old_value, new_value. i18n_message_key interpolates %{property}, %{old_value}, %{new_value}; a key ending in _html renders as safe HTML. With neither, it falls back to avo.collaboration.property_changed.
- Reactions are always on. You can't disable them — you can only replace the emoji list via
reactions: { options: [...] }. The default set is 10 emoji.
collaboration_destroy_entry? receives a Comment OR an Action. Type-check with record.is_a?(Avo::Collaboration::Comment) to allow deleting only user comments while protecting auto-generated entries. Both types respond to author.
- Depends on Avo authorization (Pundit). The three policy methods live on the resource's policy and run through Avo's authorization layer. If authorization isn't configured, set it up first (avo-authorization).
- Extend models via
Rails.configuration.to_prepare + class_eval, not a bare reopen in the initializer — otherwise your changes get dropped on reload in development.
- Option names drift between versions — check the docs URLs above or the app's installed source rather than trusting memory.
Report
When done, tell the user:
- Whether you ran the install (gem added,
avo_collaboration:install:migrations, db:migrate) or assumed it was already installed.
- Which resource file(s) you edited and the
self.collaboration config you set (author name property, which properties are watched and how their messages are built, any custom reaction emoji).
- Where you placed
collaboration_timeline in def fields.
- Which policy file(s) you added the three
collaboration_* methods to, and the access rule each encodes (especially the own-comments-only delete logic).
- Remind them it's a Beta, paid add-on, that the author is always the current Avo user, and any follow-ups still needed: run pending migrations, set up Avo authorization if absent, or add the eager-load includes for busy records.