Skip to main content
This is the shape of an app like Comet, laptop-agent, or T3 Code: a thread list on the left, a chat on the right, a settings menu, and a usage page. Follow the steps in order; each one is a few lines of glue over the Core API.

1. Find the agents and pick one

discover is instant and gives you both lists: installed, and missing with install hints. Show both.

2. Check login, show the login command

probe asks the agent itself. If it is logged out you get the exact command or env var to show; anyagent never runs a login flow.
Keep details: its capabilities and config_options drive the next steps.

3. Open a session

Build the options from the thread’s state. This is the whole decision table an app needs:

4. One task per session, persist before render

Hand Events to its own task. Keep a Session clone wherever the UI sends commands. Store every event first; replay needs nothing else because each carries sequence and occurred_at.

5. Render the events

One match covers every agent. Skip nested events for the main transcript and render them under their parent tool.
background lists tools still running after the turn (subagents, backgrounded shells). Their completion usually shows up as a later turn with TurnOrigin::Agent.

6. Permissions and questions

Render exactly the choices the agent offered. Answer once. Clear the dialog on RequestClosed, which also fires when a cancelled turn withdraws the request.
While a request is open the thread’s status is NeedsInput, so the thread list badge comes for free from step 5.

7. Send, steer, cancel

The send box calls prompt no matter what the session is doing. The Delivery tells you whether it started a turn, steered the running one, or queued.
Show attachments inline only when capabilities.supports(Capability::Images); otherwise the agent reads them by path.

8. Settings menu

Render config_options as-is: each Select is a dropdown, each Boolean a toggle. Rebuild the menu from every SessionUpdated, because switching model changes which other options exist.
Feature buttons are gated the same way, never by agent name:

9. Persist and resume

Two things per thread: the event log (step 4) and the latest SessionInfo (step 3 and every SessionUpdated). The info carries the resume_token.
Resume brings back the agent’s context, not your transcript, so render the stored events first, then attach the new stream. The token is opaque; store it as-is.

10. Titles, commit messages, PR bodies

These need text, not a conversation. generate opens a throwaway session with tools off, returns the reply, and closes.

11. Usage page

Two gauges. Per thread: the ContextUsage event from step 5. Per account:

12. Headless and background runs

A worker that runs unattended (a kanban card, a scheduled task) is the same code with two option changes and no dialogs:
Questions still arrive as RequestOpened; a headless worker should answer them with a default or cancel the turn. Watch Diagnostic events for stall warnings (stall_after, default 120 s of silence).

13. Test it without an agent installed

Run the same code over a scripted agent with the mock feature. The engine, turn rules, and event shapes are real.

What your app never does