Where sessions come from
- A trigger fires with
routing: { kind: spawn }— the normal case in a running factory. The session’s input is the triggering event, and the trigger’smessagetemplate becomes its first instruction. - A person starts one — from the agent’s page in the web app, with an optional kickoff message.
- Another agent spawns it with the
auto.sessions.spawntool, passing the kickoff message and optionally the human requester on whose behalf the work runs. - The platform replaces a pool member — for
replace: autoagents, a failed singleton session, or one stopped with respawn intent, gets a successor spawned by the pool reconciler (see runtime controls).
- Status starts at
queued, and the session’s dispatch workflow ID is derived from its session ID. - The agent spec, its environment, and its tool wiring are snapshotted onto the session. A later apply changes future sessions only; an in-flight session never silently gains or loses tools.
- The agent’s
maxPerSessionUsdspend cap is frozen into the session record, so editing the agent cannot rewrite a live session’s spend contract. - For a
concurrency: 1agent, the creation transaction claims the agent’s singleton slot. If another live session already holds it, the spawn is refused with409and the live session’s ID (AgentSlotConflictError), so you always know which session absorbed the work. - Git mounts are validated up front: a payload-templated
refthat cannot resolve, or a repository with no active GitHub connection grant, fails the spawn immediately instead of queueing a session that can never stage.
Lifecycle
A session is always in exactly one status:queued, running, and awaiting are the resumable statuses; failed and stopped are terminal, and commands sent to a terminal session are rejected.
While a session is being provisioned, a runtimePhase field narrates progress beneath the status: building_image → booting_container → preparing_environment → starting_runtime → running. The phases are written by the sandbox provisioning path and cleared once the session settles.
Status is derived from turn facts, not set by hand: a turn reaching waiting_for_input, completed, or stale puts the session at awaiting; a turn failing with failureScope: "turn" also lands at awaiting (the session survives its turn’s failure), while failureScope: "session" fails the whole session. A concurrent stopped always wins — the transition is guarded so a stop cannot be overwritten.
Archived is orthogonal to status. archivedAt hides a session from the default list; it does not declare the work complete, terminate the session or release its bindings or concurrency slot. An archived session in a resumable status can receive new work — see Ending a session.
Turns and commands
All work enters a session as a command and executes as a turn.Commands
A command is a durable row: it is created (pending), claimed by the session’s dispatch workflow (dispatching), and settles accepted, failed, or canceled. Creation is idempotent, and the sender is stamped server-side so operator attribution cannot be spoofed — whether the command came from the web app composer, a chat thread, or another agent.
The command vocabulary:
start and startWithMessage are platform-created: every session gets exactly one idempotent start command that boots the runtime. When a kickoff message resolves — the manual start’s message, the trigger’s rendered message, or the agent’s initialPrompt — the start carries it and opens the first turn; when none resolves, the bare start boots the runtime and the session awaits its first message.
Message senders are typed — operator (a person, with identity), agent (another session), or system — and the transcript shows each message’s sender and, for trigger deliveries, the originating event key and a link to the external artifact behind it.
Turns
Each dispatched command opens a turn with its own status ladder:How events reach a live session
Each session has a loop that consumes its inbox — every pending command, in the order it will be delivered — one injection at a time. Four delivery rules matter when events and people talk to the same session:- Nothing interrupts implicitly. A message that arrives while a turn is running waits in the inbox and starts the next turn; on a harness that supports steering (Codex today) human and agent messages are folded into the current turn instead, without ending it. Trigger deliveries always wait for the next turn. Only an explicit
interruptorstopends a turn early, and answers, interrupts, and stops are delivered immediately on every harness. - Trigger debounce. Trigger deliveries wait in a held lane and become eligible once 2.5 seconds have passed since the newest held delivery or 5 seconds since the oldest. A burst of related events (a push plus its check runs) becomes one coherent turn instead of five. Human messages and controls never wait on this window. The transcript renders each delivery as its own entry.
- Message batching. When several messages are eligible at the same turn boundary, up to 32 are combined into one runtime turn. Answers and controls never join a batch.
- The inbox is shared and visible. The session page shows the inbox exactly as the loop will consume it — other people’s messages, inter-agent sends, held triggers with their countdown, and pending controls. A queued message can be edited, deleted, or promoted with “Interrupt and run this next” until it is delivered. A command the runtime definitively rejects stays visible with retry and delete controls until it is dismissed.
queued (runtime provisioning) wait in the inbox and deliver in order once the runtime is up. A newly admitted message or answer to an archived resumable session clears its archive metadata and updates its activity in the admission transaction. A delayed initial prompt also reopens the same session when first admitted. Existing continuation bindings still route follow-ups to it.
Idempotent command retries, control commands and suppressed-event audit records do not reopen the session or reset its inactivity clock. Reopening consumes legacy archive-release markers on still-active bindings; it does not recreate released ownership. Failed and stopped sessions still reject new input. Presentation revival is not durable sandbox checkpoint/restore or an indefinite filesystem-retention guarantee.
Parked sessions
Some failures should pause a session, not kill it. A park keeps the session resumable without introducing a new status: the failed turn settles turn-scoped (session atawaiting), a held recovery command is recorded, and a park row bounds how long the pause may last.
While parked, the sandbox may be paused to stop the meter. When the resume condition arrives, the held recovery command becomes due and the session picks up where it stopped; if the TTL expires first, the park resolves as
expired and the session settles terminally.
Ending a session: stop, fail, archive
Stop is the terminal command.{ reason? } is recorded; respawn asks the pool reconciler to spawn a replacement on the latest agent spec (for replace: auto agents); handoff persists wind-down state on the stopped session. Stop is the only lifecycle command that accepts these options.
Failure happens when a turn fails session-scoped or provisioning cannot complete. The session record carries the structured error, and the sessions list surfaces a distilled failureReason. A failed session can be retried — a retry creates a fresh session for the same input, idempotently.
Archive changes visibility, not execution or ownership. Three paths archive a session:
- The agent explicitly uses
auto.sessions.archive_currentfor presentation archiving. This does not complete its turn or release its bindings or slot; compatibility guards can still reject a self-archive for non-owner-releasable held targets. - An operator archives it from the web app.
- The auto-archive sweeper archives eligible
awaitingsessions after the agent’s configuredsession.archiveAfterInactiveinterval. Commands inqueuedorinjectingand turns inacceptedorin_progressblock inactivity archiving. Passive bindings, including held bindings, and managed-check projections do not. The sweep preserves bindings and slot ownership.
Handoff
Sessions are disposable; their knowledge should not be. A handoff is a trimmed note of up to 20,000 characters persisted on the session record (archiveHandoff) when the session winds down — passed by the agent to auto.sessions.archive_current { handoff }, or carried on a stop command’s handoff option.
For concurrency: 1 agents the handoff completes the replacement loop: when a successor session’s kickoff command is created, the platform attaches the predecessor’s persisted handoff to it, so the new session starts knowing what the old one knew. Combined with the agent’s onReplace prompt and onUnmatched: spawn routing, this is how singleton agents survive replacement without shared memory — see runtime controls.
Observing sessions
Every session is observable live, from wherever you already are:- Web app — the session page streams the transcript ledger over SSE, shows the shared inbox, structured questions, bindings, and per-session usage; the sessions list live-updates with each session’s
displayTitle, status, and anambientStatusline summarizing what the agent is doing right now. - Agents themselves — the
auto.sessions.*introspection tools (summary,conversation,search,tools,triggers,bindings,commands) give any agent read access to any project session, which is what makes supervisor patterns work. See auto tools. - Chat — a session bound to a Slack thread converses where your team already is; the thread is an observation surface and a steering channel at once. See chat tools.
displayTitle (at most 64 characters, rendered from the agent’s displayTitle template against the event payload, or inferred when the agent declares displayTitle: infer) and ambientStatus, a periodically refreshed one-line description of current activity maintained by the dispatch workflow while the session runs.
Where to go next
Agents
The YAML that defines what a session runs.
Triggers and events
How events spawn sessions and route into live ones.
Concurrency
concurrency: 1, replace: auto, onReplace, and onUnmatched: spawn for orchestrators.
Runtime controls
Concurrency slots, replacement, spend caps, and model fallback.
auto.sessions.* tools
How agents themselves spawn, message, and introspect sessions.