# Agent Chat UI and Issue-Backed Conversations ## Context `PAP-475` asks two related questions: 1. What UI kit should Paperclip use if we add a chat surface with an agent? 2. How should chat fit the product without breaking the current issue-centric model? This is not only a component-library decision. In Paperclip today: - V1 explicitly says communication is `tasks + comments only`, with no separate chat system. - Issues already carry assignment, audit trail, billing code, project linkage, goal linkage, and active run linkage. - Live run streaming already exists on issue detail pages. - Agent sessions already persist by `taskKey`, and today `taskKey` falls back to `issueId`. - The OpenClaw gateway adapter already supports an issue-scoped session key strategy. That means the cheapest useful path is not "add a second messaging product inside Paperclip." It is "add a better conversational UI on top of issue and run primitives we already have." ## Current Constraints From the Codebase ### Durable work object The durable object in Paperclip is the issue, not a chat thread. - `IssueDetail` already combines comments, linked runs, live runs, and activity into one timeline. - `CommentThread` already renders markdown comments and supports reply/reassignment flows. - `LiveRunWidget` already renders streaming assistant/tool/system output for active runs. ### Session behavior Session continuity is already task-shaped. - `heartbeat.ts` derives `taskKey` from `taskKey`, then `taskId`, then `issueId`. - `agent_task_sessions` stores session state per company + agent + adapter + task key. - OpenClaw gateway supports `sessionKeyStrategy=issue|fixed|run`, and `issue` already matches the Paperclip mental model well. That means "chat with the CEO about this issue" naturally maps to one durable session per issue today without inventing a second session system. ### Billing behavior Billing is already issue-aware. - `cost_events` can attach to `issueId`, `projectId`, `goalId`, and `billingCode`. - heartbeat context already propagates issue linkage into runs and cost rollups. If chat leaves the issue model, Paperclip would need a second billing story. That is avoidable. ## UI Kit Recommendation ## Recommendation: `assistant-ui` Use `assistant-ui` as the chat presentation layer. Why it fits Paperclip: - It is a real chat UI kit, not just a hook. - It is composable and aligned with shadcn-style primitives, which matches the current UI stack well. - It explicitly supports custom backends, which matters because Paperclip talks to agents through issue comments, heartbeats, and run streams rather than direct provider calls. - It gives us polished chat affordances quickly: message list, composer, streaming text, attachments, thread affordances, and markdown-oriented rendering. Why not make "the Vercel one" the primary choice: - Vercel AI SDK is stronger today than the older "just `useChat` over `/api/chat`" framing. Its transport layer is flexible and can support custom protocols. - But AI SDK is still better understood here as a transport/runtime protocol layer than as the best end-user chat surface for Paperclip. - Paperclip does not need Vercel to own message state, persistence, or the backend contract. Paperclip already has its own issue, run, and session model. So the clean split is: - `assistant-ui` for UI primitives - Paperclip-owned runtime/store for state, persistence, and transport - optional AI SDK usage later only if we want its stream protocol or client transport abstraction ## Product Options ### Option A: Separate chat object Create a new top-level chat/thread model unrelated to issues. Pros: - clean mental model if users want freeform conversation - easy to hide from issue boards Cons: - breaks the current V1 product decision that communication is issue-centric - needs new persistence, billing, session, permissions, activity, and wakeup rules - creates a second "why does this exist?" object beside issues - makes "pick up an old chat" a separate retrieval problem Verdict: not recommended for V1. ### Option B: Every chat is an issue Treat chat as a UI mode over an issue. The issue remains the durable record. Pros: - matches current product spec - billing, runs, comments, approvals, and activity already work - sessions already resume on issue identity - works with all adapters, including OpenClaw, without new agent auth or a second API surface Cons: - some chats are not really "tasks" in a board sense - onboarding and review conversations may clutter normal issue lists Verdict: best V1 foundation. ### Option C: Hybrid with hidden conversation issues Back every conversation with an issue, but allow a conversation-flavored issue mode that is hidden from default execution boards unless promoted. Pros: - preserves the issue-centric backend - gives onboarding/review chat a cleaner UX - preserves billing and session continuity Cons: - requires extra UI rules and possibly a small schema or filtering addition - can become a disguised second system if not kept narrow Verdict: likely the right product shape after a basic issue-backed MVP. ## Recommended Product Model ### Phase 1 product decision For the first implementation, chat should be issue-backed. More specifically: - the board opens a chat surface for an issue - sending a message is a comment mutation on that issue - the assigned agent is woken through the existing issue-comment flow - streaming output comes from the existing live run stream for that issue - durable assistant output remains comments and run history, not an extra transcript store This keeps Paperclip honest about what it is: - the control plane stays issue-centric - chat is a better way to interact with issue work, not a new collaboration product ### Onboarding and CEO conversations For onboarding, weekly reviews, and "chat with the CEO", use a conversation issue rather than a global chat tab. Suggested shape: - create a board-initiated issue assigned to the CEO - mark it as conversation-flavored in UI treatment - optionally hide it from normal issue boards by default later - keep all cost/run/session linkage on that issue This solves several concerns at once: - no separate API key or direct provider wiring is needed - the same CEO adapter is used - old conversations are recovered through normal issue history - the CEO can still create or update real child issues from the conversation ## Session Model ### V1 Use one durable conversation session per issue. That already matches current behavior: - adapter task sessions persist against `taskKey` - `taskKey` already falls back to `issueId` - OpenClaw already supports an issue-scoped session key This means "resume the CEO conversation later" works by reopening the same issue and waking the same agent on the same issue. ### What not to add yet Do not add multi-thread-per-issue chat in the first pass. If Paperclip later needs several parallel threads on one issue, then add an explicit conversation identity and derive: - `taskKey = issue::conversation:` - OpenClaw `sessionKey = paperclip:conversation:` Until that requirement becomes real, one issue == one durable conversation is the simpler and better rule. ## Billing Model Chat should not invent a separate billing pipeline. All chat cost should continue to roll up through the issue: - `cost_events.issueId` - project and goal rollups through existing relationships - issue `billingCode` when present If a conversation is important enough to exist, it is important enough to have a durable issue-backed audit and cost trail. This is another reason ephemeral freeform chat should not be the default. ## UI Architecture ### Recommended stack 1. Keep Paperclip as the source of truth for message history and run state. 2. Add `assistant-ui` as the rendering/composer layer. 3. Build a Paperclip runtime adapter that maps: - issue comments -> user/assistant messages - live run deltas -> streaming assistant messages - issue attachments -> chat attachments 4. Keep current markdown rendering and code-block support where possible. ### Interaction flow 1. Board opens issue detail in "Chat" mode. 2. Existing comment history is mapped into chat messages. 3. When the board sends a message: - `POST /api/issues/{id}/comments` - optionally interrupt the active run if the UX wants "send and replace current response" 4. Existing issue comment wakeup logic wakes the assignee. 5. Existing `/issues/{id}/live-runs` and `/issues/{id}/active-run` data feeds drive streaming. 6. When the run completes, durable state remains in comments/runs/activity as it does now. ### Why this fits the current code Paperclip already has most of the backend pieces: - issue comments - run timeline - run log and event streaming - markdown rendering - attachment support - assignee wakeups on comments The missing piece is mostly the presentation and the mapping layer, not a new backend domain. ## Agent Scope Do not launch this as "chat with every agent." Start narrower: - onboarding chat with CEO - workflow/review chat with CEO - maybe selected exec roles later Reasons: - it keeps the feature from becoming a second inbox/chat product - it limits permission and UX questions early - it matches the stated product demand If direct chat with other agents becomes useful later, the same issue-backed pattern can expand cleanly. ## Recommended Delivery Phases ### Phase 1: Chat UI on existing issues - add a chat presentation mode to issue detail - use `assistant-ui` - map comments + live runs into the chat surface - no schema change - no new API surface This is the highest-leverage step because it tests whether the UX is actually useful before product model expansion. ### Phase 2: Conversation-flavored issues for CEO chat - add a lightweight conversation classification - support creation of CEO conversation issues from onboarding and workflow entry points - optionally hide these from normal backlog/board views by default The smallest implementation could be a label or issue metadata flag. If it becomes important enough, then promote it to a first-class issue subtype later. ### Phase 3: Promotion and thread splitting only if needed Only if we later see a real need: - allow promoting a conversation to a formal task issue - allow several threads per issue with explicit conversation identity This should be demand-driven, not designed up front. ## Clear Recommendation If the question is "what should we use?", the answer is: - use `assistant-ui` for the chat UI - do not treat raw Vercel AI SDK UI hooks as the main product answer - keep chat issue-backed in V1 - use the current issue comment + run + session + billing model rather than inventing a parallel chat subsystem If the question is "how should we think about chat in Paperclip?", the answer is: - chat is a mode of interacting with issue-backed agent work - not a separate product silo - not an excuse to stop tracing work, cost, and session history back to the issue ## Implementation Notes ### Immediate implementation target The most defensible first build is: - add a chat tab or chat-focused layout on issue detail - back it with the currently assigned agent on that issue - use `assistant-ui` primitives over existing comments and live run events ### Defer these until proven necessary - standalone global chat objects - multi-thread chat inside one issue - chat with every agent in the org - a second persistence layer for message history - separate cost tracking for chats ## References - V1 communication model: `doc/SPEC-implementation.md` - Current issue/comment/run UI: `ui/src/pages/IssueDetail.tsx`, `ui/src/components/CommentThread.tsx`, `ui/src/components/LiveRunWidget.tsx` - Session persistence and task key derivation: `server/src/services/heartbeat.ts`, `packages/db/src/schema/agent_task_sessions.ts` - OpenClaw session routing: `packages/adapters/openclaw-gateway/README.md` - assistant-ui docs: - assistant-ui repo: - AI SDK transport docs: