Problem
Self-hosted Canvas conversations can be born from many surfaces besides the browser: Slack automations, GitHub triggers, cron automations, or arbitrary API clients hitting the agent-server directly. In the conversation panel today there is no way to tell where a conversation came from or which automation/user it belongs to — API-born conversations all look alike.
The server half of a solution already exists: agent-server stores tags: Record<str, str> on every conversation (settable at creation and via PATCH /api/conversations/{id}), and the Canvas frontend already normalizes them (normalizeTags in agent-server-conversation-service.api.ts). But the UI only ever consumes the single reserved acpserver tag; every other tag is invisible.
Proposal
Surface conversation tags in the conversation panel:
- Show non-reserved tags as small chips on the conversation card (e.g.
origin: slack, owner: alice). Reserved/internal keys (acpserver) stay hidden.
- Match tags in the existing "Filter conversations" text filter, so typing
slack or owner:alice narrows the list.
- (Possible follow-up, out of scope here) an "Organize → By tag" grouping mode alongside the existing By workspace / By repository modes.
No new server concepts, no schema changes — this is purely making already-stored, already-fetched metadata visible.
Motivating use case
We run a self-hosted Canvas + agent-server for a small team. A glue service births conversations from Slack threads and from an automated PR-review pipeline, over the agent-server REST API. We stamp tags like origin=slack, origin=review, owner=<engineer> at creation — but nobody can see them in the UI, so review runs, Slack runs, and browser runs are indistinguishable in the panel. With chips + filter, any team member could instantly see "started from Slack by alice" or filter to just review conversations — using data the server already returns.
This is adjacent to the created_by_user_id field that exists for Cloud conversations, but deliberately narrower: tags are already a self-hosted, API-writable concept, so no auth/identity machinery is implied.
Implementation sketch
- Expose the already-normalized
tags map on AppConversation (it's currently dropped after acpserver extraction in agent-server-adapter.ts).
- Render filtered chips in the conversation card footer next to the existing repo/model metadata, behind the existing hover-metadata setting.
- Extend the filter predicate in
conversation-panel.tsx to match key, value, and key:value forms.
I have a working branch for 1–2 and am happy to open a PR if this direction is acceptable.
Problem
Self-hosted Canvas conversations can be born from many surfaces besides the browser: Slack automations, GitHub triggers, cron automations, or arbitrary API clients hitting the agent-server directly. In the conversation panel today there is no way to tell where a conversation came from or which automation/user it belongs to — API-born conversations all look alike.
The server half of a solution already exists:
agent-serverstorestags: Record<str, str>on every conversation (settable at creation and viaPATCH /api/conversations/{id}), and the Canvas frontend already normalizes them (normalizeTagsinagent-server-conversation-service.api.ts). But the UI only ever consumes the single reservedacpservertag; every other tag is invisible.Proposal
Surface conversation tags in the conversation panel:
origin: slack,owner: alice). Reserved/internal keys (acpserver) stay hidden.slackorowner:alicenarrows the list.No new server concepts, no schema changes — this is purely making already-stored, already-fetched metadata visible.
Motivating use case
We run a self-hosted Canvas + agent-server for a small team. A glue service births conversations from Slack threads and from an automated PR-review pipeline, over the agent-server REST API. We stamp
tagslikeorigin=slack,origin=review,owner=<engineer>at creation — but nobody can see them in the UI, so review runs, Slack runs, and browser runs are indistinguishable in the panel. With chips + filter, any team member could instantly see "started from Slack by alice" or filter to just review conversations — using data the server already returns.This is adjacent to the
created_by_user_idfield that exists for Cloud conversations, but deliberately narrower: tags are already a self-hosted, API-writable concept, so no auth/identity machinery is implied.Implementation sketch
tagsmap onAppConversation(it's currently dropped afteracpserverextraction inagent-server-adapter.ts).conversation-panel.tsxto matchkey,value, andkey:valueforms.I have a working branch for 1–2 and am happy to open a PR if this direction is acceptable.