Your first session
Create it
Section titled “Create it”From the UI, or:
curl -X POST http://localhost:3000/api/v1/sessions \ -H "X-API-Key: $YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "agent_root": "general-agent", "prompt": "Add a health check endpoint at /healthz that returns 200 OK.", "goal": "open-reviewed-green-pr" }'What you get back is a session in waiting, with an AgentSessionJob enqueued.
What happens next
Section titled “What happens next”Within a minute or so it should flip to running. If it doesn’t, treat that as a symptom and
see Expected timings below.
While it runs you’ll see the timeline stream in over Turbo: user messages, assistant messages, thinking blocks, tool calls, tool results, subagent accordions. That’s the transcript pipeline doing its job.
Follow up
Section titled “Follow up”The session pauses to needs_input when the agent’s turn ends. Send a follow-up:
curl -X POST http://localhost:3000/api/v1/sessions/$ID/follow_up \ -H "X-API-Key: $YOUR_KEY" \ -d '{"prompt": "Also add a test for it."}'Three things can happen, and the status code tells you which:
| Session state | Result | Status |
|---|---|---|
needs_input or waiting | delivered immediately, session resumes | 200 |
running | queued as an EnqueuedMessage, delivered when the turn ends | 202 |
running + force_immediate: true | the process is interrupted and the message delivered now | 200 |
The 202 case is the one that surprises people. A follow-up to a running session lines up behind
the current turn instead of interrupting it. Pass force_immediate if you mean “stop what
you’re doing.”
Reading the UI
Section titled “Reading the UI”The needs_input list is your to-do list, and it only works if it stays short. That’s the design
intent: agents are instructed to archive themselves when they run to completion, so a session still
sitting there is one that stopped because it genuinely needs you — it lacked the scope or tools to
finish, it is holding a PR whose merge disposition is unsettled, you invoked it yourself to explore
or ask something, or it hit an ambiguity too dangerous and irreversible to guess at. Those four
cases are spelled out in Goals and stop conditions.
The PR case is the one you will see most, and it clears itself: a session that opened a PR waits here until the PR merges, then archives on its own. What is left behind is the set of PRs the merge gate declined to merge for you — which is the list worth your attention.
A session showing “blocked on elicitation” is different: the agent process is still alive, and an MCP server is waiting for you to answer a question. See Elicitation.
Expected timings
Section titled “Expected timings”If something takes materially longer than this, the problem is probably the system:
| Operation | Expected |
|---|---|
Session waiting → running | ~1 minute |
| GitHub Actions CI (for the agent’s PR) | 5–10 minutes |
| Stuck-session auto-recovery | ~15 minutes |
| Catalog refresh (worker) | every 15 minutes |
| Catalog refresh (web) | every 5 minutes |
If it fails with oauth_required
Section titled “If it fails with oauth_required”The session went to failed because one of its MCP servers needs OAuth and has no valid credential.
The UI will show Authorize buttons. Click through the flow and the session resumes automatically,
replaying the original prompt. See MCP server OAuth.
Useful session controls
Section titled “Useful session controls”| Action | What it does |
|---|---|
| Pause | running → needs_input |
| Sleep | Go dormant; a one-time trigger will wake you |
| Restart | Re-run from the start; falls back to restart-from-scratch if there’s no clone |
| Fork | Branch a new session from a specific message index |
| Refresh | Re-read the transcript from disk (never shortens the stored one) |
| Heartbeat | Auto-nudge this session every N seconds while it’s in needs_input |
| Archive | Move to trash; the clone is reaped after an undo window |