Skip to main content
The quickstart gets one agent working. This page is the difference between that and something you can leave running: which token to give which process, the loop that survives a dropped connection, and how to take files out when a turn produced more than one. Nothing here is needed to see the thing work. All of it is needed before a second person depends on it.

Which token for which process

A call missing its scope is 403 permission_denied, and the message names the scope it wanted — so you never have to guess which one you left out. sessions:read + artifacts:read is the read-only shape, and it really is read-only: nothing it holds can delete, cancel or write. sessions:read + tools:respond is a worker: it can watch a session and answer its function calls, and it cannot send a message, cancel a turn or delete anything. That is the token to give a fleet of tool handlers. The two scopes are exact in both directions — sessions:write alone does not answer a tool call, and tools:respond alone does not drive a session. A call missing its scope is 403 permission_denied, and the message names the scope it wanted — so you never have to guess which one you left out.

Reading one turn

One turn, by id, when you have kept one and want its current state without a list around it:
It carries the same fields as the list entry — including artifacts, which is what step 8 waits on.

The session loop

Everything above is one call each. In practice you want the loop: subscribe, send, answer whatever the agent asks you, resume if the connection drops. That loop is run-session.ts — copy it into your project and use it:
It is not a package, on purpose — see design-decisions.md. It is also not a transcription: the same file is what pnpm e2e:v1:minimax runs against production, so it cannot rot without a test going red. The tool is declared in two halves, and both are required: agent.tools is what the model is told about, and handlers is what your process answers with. Declaring without a handler parks the turn on a call nobody answers; handling without a declaration means the call never happens. To work on a repository, add environment: { repo: "acme/site" } — your organization needs a GitHub connection first, or the request is refused up front. Three things it does that are easy to get wrong by hand, and wrong silently:
  • Subscribes before sending. The other order loses the opening events whenever the agent starts quickly — which is to say sometimes.
  • Answers required actions. Left unanswered, a turn stays working and the session stays requires_action for as long as the workspace lives — nothing times it out, and nothing else moves until you answer.
  • Never sends a thrown handler’s message to the model. A stack trace is an excellent way to put your database host into a model’s context, so a failing handler yields a fixed string instead.
And one thing a generated client would not: it resumes. A dropped connection continues from Last-Event-ID rather than starting over or losing the middle. See events.md.

Taking many files at once

When a turn produced more than one file, take them all at once:
A tar, streamed. Add ?turn_id=… to narrow it to one turn, and the entries carry the workspace’s own paths. Without it you get the whole session, and each entry is prefixed with the turn that published it — two turns writing report.md are two files, and a flat archive would extract as one.

Artifacts

Anything the agent writes under /workspace/outputs is published as an artifact — a durable copy that outlives the workspace. Publishing happens after the turn settles, so that a storage problem can never delay or fail your work. That means status: "completed" is not yet a promise that GET /v1/sessions/{id}/artifacts will list anything. The turn tells you which it is:
The turn.completed webhook already waits for you: it is sent once publication settles, so an unattended integration can fetch artifacts the moment it is called. If publication is still running after 30 seconds the notification is sent anyway, with the turn still reading pending — a late answer being better than none.

What to reach for next

The pieces this page assumes, each on its own page: And the guides put them together: six complete programs, each one a scenario rather than an endpoint.