docs: add Channels spec (chat for people and agents)
- Claude-Session:
- https://claude.ai/code/session_011tBfr1Kv6Bbf7dhvf3zo9c
1 file+127−00/1 viewed
| 1 | + | # Channels | |
| 2 | + | ||
| 3 | + | People and agents talk in the same place the code lives. A workspace gets | |
| 4 | + | channels and direct messages, the way a team chat app has them, and every | |
| 5 | + | channel can be linked to a project so its pull requests, issues, checks and | |
| 6 | + | deploys arrive there as cards a person can act on. Agents are members of | |
| 7 | + | channels like anyone else. | |
| 8 | + | ||
| 9 | + | Design canvas: the "g1t Channels" artifact (v2 row is the target). | |
| 10 | + | ||
| 11 | + | ## The point | |
| 12 | + | ||
| 13 | + | Today a person reads g1t in two places: g1t itself, and a chat app where | |
| 14 | + | the team talks about what g1t is doing. Links get pasted across, approvals | |
| 15 | + | wait in the wrong window, and an agent's question goes unseen. Channels put | |
| 16 | + | the talk next to the work, and make one thing true everywhere: a thread | |
| 17 | + | about a pull request *is* that pull request's conversation. | |
| 18 | + | ||
| 19 | + | ## Product model | |
| 20 | + | ||
| 21 | + | - **Modes.** The shell gets a rail: Home, Code, Chat, Agents, Inbox. Code | |
| 22 | + | keeps today's sidebar exactly. Chat has a sidebar of its own. Inbox is | |
| 23 | + | shared by both. No mode's sidebar ever lists the other mode's things. | |
| 24 | + | - **Channel.** Belongs to a workspace. Public or private. Optionally linked | |
| 25 | + | to one or more projects, and optionally to a team. Has members: people | |
| 26 | + | and agents. | |
| 27 | + | - **Message.** Text by a person or an agent, or a card posted by g1t for an | |
| 28 | + | event (pull request opened, checks failed, deployed, an agent asking for | |
| 29 | + | approval). | |
| 30 | + | - **Thread.** Replies under a message. A card about an issue or pull | |
| 31 | + | request opens that issue's or pull request's own timeline: replying there | |
| 32 | + | is commenting on it. Other threads belong to the channel. | |
| 33 | + | - **Direct message.** A channel with no name, between two or more members, | |
| 34 | + | any of whom may be agents. | |
| 35 | + | - **Project chat.** In Code mode, a project page shows a dock with only the | |
| 36 | + | channels linked to that project. | |
| 37 | + | ||
| 38 | + | ## Scaling the sidebar | |
| 39 | + | ||
| 40 | + | Workspaces will have hundreds of channels. The Chat sidebar never lists | |
| 41 | + | them all: | |
| 42 | + | ||
| 43 | + | - **Starred** first, chosen by the person. | |
| 44 | + | - **Active projects:** channels linked to projects the person worked on | |
| 45 | + | this week, computed, not chosen. | |
| 46 | + | - **Teams:** one collapsed section per team the person is on, showing a | |
| 47 | + | count and what is unread. | |
| 48 | + | - **Direct messages**, newest first. | |
| 49 | + | - **All / Unread / Mentions** filter, and a jump box. Everything else is | |
| 50 | + | behind *Browse channels* and *Muted*. | |
| 51 | + | ||
| 52 | + | ## How it fits what exists | |
| 53 | + | ||
| 54 | + | | Need | Already in g1t | What changes | | |
| 55 | + | | --- | --- | --- | | |
| 56 | + | | Live delivery | Durable Objects (runner, models) | One Durable Object per channel holds the open WebSockets, with hibernation. D1 keeps the messages. | | |
| 57 | + | | Cards for events | `services/events` bus and per-subscriber queues (`g1t_contracts::subscribers`) | `chat` subscribes to pull, issue, check run, deployment and agent run types, and posts a card in each linked channel. | | |
| 58 | + | | Mentions and unread | `services/events` inbox, threads and reasons | A message that mentions someone publishes `chat.message.created`; the inbox tells them with reason `mention`. Thread keys reuse `<repo_id>#<number>`. | | |
| 59 | + | | Steering an agent | `agent_messages` in `services/work` | `@agent` in a pull request's thread becomes a steering message on that pull request. | | |
| 60 | + | | One timeline | Issue and pull request timelines in `services/work` | The card's thread reads and writes that timeline. Chat stores only a pointer. | | |
| 61 | + | | Navigation | `workspace-nav.ts`, `shell.tsx` | A rail, a `mode` beside `SidebarKey`, and a Chat sidebar. | | |
| 62 | + | | Search | `services/search` | Index channel names and messages people can see. | | |
| 63 | + | ||
| 64 | + | ## Data | |
| 65 | + | ||
| 66 | + | A new service, `services/chat` (TypeScript, like `services/projects`, | |
| 67 | + | because the Durable Object and WebSocket code is simplest there), with its | |
| 68 | + | own D1 database: | |
| 69 | + | ||
| 70 | + | - `channels`: id, workspace, name, kind (`channel` | `dm`), private, topic, | |
| 71 | + | team_id, created_by, archived_at. | |
| 72 | + | - `channel_links`: channel_id, project_id. What makes a channel a | |
| 73 | + | project's chat, and where cards go. | |
| 74 | + | - `channel_members`: channel_id, principal (person or agent), role, | |
| 75 | + | starred, section, muted, last_read_id, joined_at. | |
| 76 | + | - `messages`: id (time-sortable), channel_id, author, kind (`text` | | |
| 77 | + | `card`), body, card (JSON: subject key, state, actions), thread_root, | |
| 78 | + | reply_count, edited_at, deleted_at. | |
| 79 | + | - `reactions`: message_id, principal, emoji. | |
| 80 | + | ||
| 81 | + | Unread counts come from `last_read_id` against the newest message id, kept | |
| 82 | + | in the channel's Durable Object, so the sidebar needs one read per | |
| 83 | + | section, not per channel. | |
| 84 | + | ||
| 85 | + | ## Agents in channels | |
| 86 | + | ||
| 87 | + | - An agent is added to a channel like a person, with the agent's own | |
| 88 | + | credentials, guardrails and audit log. Private channels exclude agents | |
| 89 | + | unless added by name. | |
| 90 | + | - A mention in a pull request's thread steers that pull request's agent | |
| 91 | + | (`agent_messages`). A mention anywhere else starts an agent run whose | |
| 92 | + | replies post in the thread. | |
| 93 | + | - Asking a person for approval (merge past branch protection, deploy to | |
| 94 | + | production) posts a card with the actions on it, and the same item lands | |
| 95 | + | in the person's inbox. Acting in either place resolves both. | |
| 96 | + | ||
| 97 | + | ## Build order | |
| 98 | + | ||
| 99 | + | 1. **Contracts.** Channel, message and card types in `packages/contracts` | |
| 100 | + | and `crates/contracts`; the RPC methods; the new event types. | |
| 101 | + | 2. **Channels.** `services/chat`, its migrations, a Durable Object per | |
| 102 | + | channel, and `deploy/stack.jsonc` entries. Create, join, post, edit, | |
| 103 | + | threads, reactions, read state. | |
| 104 | + | 3. **Chat mode.** The rail in `shell.tsx`; the Chat sidebar with starred, | |
| 105 | + | sections, filters and browse; the channel page; the composer with | |
| 106 | + | mentions. Code mode is unchanged apart from the rail. | |
| 107 | + | 4. **Mentions to the inbox.** `chat.message.created` and inbox rows with | |
| 108 | + | reason `mention`. | |
| 109 | + | 5. **Project links and cards.** Link a channel to a project; the events | |
| 110 | + | subscriber; cards for pull requests, issues, checks and deploys; the | |
| 111 | + | project chat dock in Code mode. | |
| 112 | + | 6. **One timeline.** A card's thread is the issue's or pull request's | |
| 113 | + | timeline, both ways, with "also send to channel". | |
| 114 | + | 7. **Agents.** Agents as members, steering by mention, approval cards, | |
| 115 | + | direct messages with agents. | |
| 116 | + | 8. **Scale.** Team sections, computed active-project section, muting, | |
| 117 | + | browse, search. | |
| 118 | + | ||
| 119 | + | Steps 1 to 4 are a usable chat; 5 and 6 are what no chat app can do. | |
| 120 | + | ||
| 121 | + | ## Open questions | |
| 122 | + | ||
| 123 | + | - Must every channel belong to a project or team? Requiring one makes the | |
| 124 | + | sidebar's sections better and orphans fewer channels. | |
| 125 | + | - Do agents get their own mode, or only appear as direct messages? | |
| 126 | + | - Retention and export for workspaces that need it. | |
| 127 | + | - Does a self-hosted install ship chat, or is it hosted only at first? |