Ended · 19 subagents
Agent sessions you can watch and answer from the web
Rebuild how people see and drive agent sessions on the web. The goal is a first-class experience for knowing what every session is doing and for answering it while it runs. We adopt the best open-source building blocks rather than invent our own, and we may revisit that later.
Direction
The two screenshots below show the target feel:
- A "Needs attention" rail. Sessions that are waiting on a person sit at the top of the sidebar. Each opens a card with Review / Check / Dismiss, and you act from the card itself, not from a link that leads somewhere else.
- A session page that reads as an answer. It opens with a summary sentence, then a few key metrics, then Highlights with numbered citations pointing back into the transcript or evidence, then Deliverables (artifacts, pull requests, docs). The raw transcript is there but folded behind "Worked for 34s", not the main event.
Where we are today
- Listing and reading (
/:owner/-/work/sessions,/:id, the pull request Session tab, the work item panel):- The pages re-run their loaders when a WebSocket ping arrives from
services/notify(useLive, debounced 1–5s). - The ping doesn't say which session changed, so any session activity in the repository reloads the page.
- Nothing is streamed.
- The pages re-run their loaders when a WebSocket ping arrives from
- Web actions: you can only stop, end or rename a session (
session.tsx:120-146). - No input after start:
- Nothing sends a prompt, reply or approval to a running session.
- Hosted sessions automatically decline tool approvals: "nobody was watching" (
services/integrations/src/agent_sessions.rs:1348). - The only input ever sent is
user.messageat start (:213) anduser.interrupton stop.
- Inbox and chat cards:
- Inbox "Waiting on you" cards only link out (
notify-store.ts:112). - Session chat cards already have a "Needs approval" chip (
session-card.ts:9), but nothing behind it.
- Inbox "Waiting on you" cards only link out (
- Transcript model:
SessionEntrykinds areprompt | message | tool_call | tool_result | note | skill. There are no diffs, plans, permission requests or terminal output as structured data.
What to adopt (research, Oct 2026)
There is no single open-source project covering the whole stack for bring-your-own-agent sessions, so we put these layers together.
Event model: Agent Client Protocol (ACP). We use ACP's session-update shapes as our internal schema:
- message and thought
tool_call/tool_call_update, each with kind, status, diff, terminal andlocations- plan
session/request_permissionwith allow_once, allow_always, reject_once and reject_always
ACP adapters already exist for Claude Code, Codex, Goose, OpenCode and Gemini. Only stdio is normative; the HTTP/WS transport RFD is still a draft, so we carry ACP over our own socket. Links: https://agentclientprotocol.com/protocol/tool-calls · https://agentclientprotocol.com/rfds/streamable-http-websocket-transport
Two other options:
- Rivet Sandbox Agent SDK (Apache-2.0): a daemon that normalizes Claude Code, Codex, OpenCode and Amp into one HTTP+SSE schema, with a Cloudflare target. A candidate ingest layer where we control the sandbox. https://github.com/rivet-dev/sandbox-agent
- AG-UI (CopilotKit): only for interop. It has no diff, permission-option or terminal primitives.
Transcript and tool UI:
- assistant-ui (MIT): headless React.
ExternalStoreRuntimereads from any store, and tool parts have arequires_actionstatus for approvals. https://www.assistant-ui.com - @pierre/diffs (Apache-2.0): Shiki-based and virtualized, split or stacked, multi-file, with annotations and accept/reject hooks. https://diffs.com
- shadcn AI Elements patterns, copied in and restyled (Tool, Confirmation, Plan, Terminal, Subagent, Checkpoint).
- We already depend on shadcn,
streamdownanduse-stick-to-bottom. - Don't depend on the
elements.ai-sdk.devregistry: it is deprecated at the end of Nov 2026 and moving into shadcn/ui.
- We already depend on shadcn,
Live interaction: Cloudflare Agents SDK (agents, MIT).
- One Durable Object per session; browsers subscribe with
useAgent/AgentClient. - Prompts, cancels and permission replies flow back through the DO to the harness adapter (ACP, Codex app-server, or Managed Agents for hosted sessions).
- This fits the DOs we already run in
services/notify. - Use
useAgentChatonly for agents we host ourselves: it assumes the AI SDK message model. - Links: https://github.com/cloudflare/agents · https://github.com/cloudflare/agents-starter (reference only, Kumo design system).
Examples to learn from:
- claude-code-viewer (start, resume and watch Claude Code from the browser)
- agentsview (multi-harness, SSE)
- the ACP web clients Codeg and Gonggong Space
Rejected as embeds (they are full apps): OpenHands, Goose desktop, LibreChat, Open WebUI. Langfuse and Phoenix suit after-the-fact tracing, not steering.
Rough slices
Each slice is its own pull request; this item tracks the whole.
- Event model. Extend
SessionEntry/contracts to the ACP shapes: diff, terminal, plan, permission request and reply. Keep the old kinds readable. - Live per-session channel. A session DO that streams entries to viewers (no more full-page revalidation), with change events that carry the session id.
- Session page rebuild. Summary, then highlights with citations, then deliverables, with the transcript folded underneath. Built on assistant-ui and @pierre/diffs.
- Two-way.
- Send a message to a running session.
- Answer permission requests from the web; stop auto-declining hosted approvals when someone can be told.
- Cancel and steer.
- Needs attention. The sidebar rail and actionable inbox cards (Review / Check / Dismiss), on web and mobile (
apps/mobilesession screens). - Harness adapters. Claude Code via its ACP adapter or plugin hooks, Codex, and hosted Managed Agents.
Billing: who pays for what
Since e6fa6230 (Oct 12), g1t sells no AI. Model tokens are always paid on the workspace's own provider key, and this work keeps it that way.
Model tokens: the customer's provider, never g1t.
- Hosted sessions already run on the workspace's Anthropic connection (
agent_sessions.rs:1-8). Codex goes on its OpenAI key the same way. - The Cloudflare Agents SDK is used only as transport: a Durable Object per session and the sockets to browsers. No Workers AI and no g1t-held model key. That means no AI credit to allot and no token meter to revive.
- If we ever run a model on our own key, that is a separate decision. It would reintroduce metering through
reserve/settle, and it is out of scope here.
Sandbox time we host: metered like runner minutes.
- This covers a harness we run for the customer, for example Claude Code or Codex in a Sandbox SDK container (possibly via Rivet's daemon).
- Each session
reserves before it starts andsettles viarecord_sandboxat the machine's rate: cost plus 20%, drawn from included usage, then the trial, then the OSS pool, then prepaid credit, then owed. It is bounded by the owner's spend limit and the trust ceiling. - A session the customer runs on their own machine (Claude Code locally, reported through the plugin) costs $0, just as self-hosted runners do.
- Waiting costs money. A hosted sandbox paused on a permission request still burns minutes, so:
- The "Needs attention" card shows what it is costing while it waits.
- After an idle limit, the sandbox is snapshotted and stopped instead of left running. It resumes when someone answers.
Session Durable Objects and live sockets: platform spend, not metered per workspace.
- This matches how
services/notifyis treated today. - Add them to
platform.rsmonitoring andmargin.rsreconciliation. Only meter them if the margin shows they matter.
What the customer sees.
- The session page separates the two kinds of cost:
- "Billed by Anthropic/OpenAI to your account": the existing
cost_usdestimate, or the provider cost report where an admin key is connected. - "Billed by g1t": sandbox minutes.
- "Billed by Anthropic/OpenAI to your account": the existing
- Neither is ever shown as the other.
- Workspace usage lists hosted-session sandbox time on its own line, not under "Other usage".
Done when
- Anyone in the workspace can open a running session and watch it stream live.
- That person can reply to it and approve or deny its tool calls from the browser.
- Every session waiting on a person shows up in "Needs attention", and it can be resolved there.
- Model tokens never reach g1t's bill; hosted sandbox time reaches it exactly, within the spend limit; and the session page tells the two apart.
Work
Repositories and pull requests
- g1tOrigin
- An app bar across the top, Needs attention, and session pages that read as answers #306Merged by syntaqx· syntaqx49 files+1541−574
- Artifacts are the Library's, and sessions are Chat's #309Merged by syntaqx· syntaqx80 files+339−235
- Chat's first page draws Home again, with Home's own data #316Merged by syntaqx· syntaqx2 files+15−3
- ? shows the keyboard's shortcuts, and the account menu says so, not Ctrl K #317Closed without merging· syntaqx12 files+102−50
- / is search, and Ctrl K (⌘K on a Mac) shows the keyboard's shortcuts #321Merged by syntaqx· syntaqx12 files+102−50
- Chat's sidebar has one way into sessions, and the page has a Yours toggle #322Merged by syntaqx· syntaqx3 files+41−66
- New starts with g1t, work items start agents from the browser, and switching workspaces works #323Merged by syntaqx· syntaqx4 files+205−33
- g1t.sh sends no analytics: HeyCatch and its consent banner are gone #324Merged by syntaqx· syntaqx18 files+36−595
- A running hosted session can be allowed, denied and messaged from the web #328Closed without merging· syntaqx
- A running hosted session can be allowed, denied and messaged from the web #329Merged by syntaqx· syntaqx15 files+1424−36
It may also need
- hello2 work items with like titles landed there.
On it
Sessions
In Chat- s
Untitled sessionClaude CodeEnded
syntaqx· ended
- s
Untitled sessionClaude CodeEnded
syntaqx· ended
Why the work is the way it is, and how sure that is