Skip to content

Your first session

From the UI, or:

Terminal window
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.

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.

The session pauses to needs_input when the agent’s turn ends. Send a follow-up:

Terminal window
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 stateResultStatus
needs_input or waitingdelivered immediately, session resumes200
runningqueued as an EnqueuedMessage, delivered when the turn ends202
running + force_immediate: truethe process is interrupted and the message delivered now200

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.”

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 (most often one the merge gate has held for you), 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 holds it — asleep on a bounded self-wake while the merge gate rates it, here in the queue once the gate has held it for you — and archives on its own when the PR merges. 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.

If something takes materially longer than this, the problem is probably the system:

OperationExpected
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

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, or delivering the follow-up it was blocked on if you had already sent one. See MCP server OAuth.

ActionWhat it does
Pauserunning → needs_input
SleepGo dormant; a one-time trigger will wake you
RestartRe-run from the start; falls back to restart-from-scratch if there’s no clone
ForkBranch a new session from a specific message index
RefreshRe-read the transcript from disk (never shortens the stored one)
HeartbeatAuto-nudge this session every N seconds while it’s in needs_input
ArchiveMove to trash; the clone is reaped after an undo window

Archiving leaves a toast with an Undo button on it. The button works for as long as the toast is up — 30 seconds — and the two are the same number by construction, so one cannot outlive the other (see the undo window). After that, Restore does the same thing with no time limit.