Skip to main content
A session is one durable execution of an agent: a sandbox running the agent’s harness, a transcript, and a command queue, all backed by a Temporal workflow so nothing is lost when processes restart. Sessions are the thing you watch — every one is observable live from the web app and through agents’ own introspection tools. This page covers the full arc: spawn, lifecycle, turns and commands, event delivery, parking, ending, and handoff.

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’s message template 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.spawn tool, passing the kickoff message and optionally the human requester on whose behalf the work runs.
  • The platform replaces a pool member — for replace: auto agents, a failed singleton session, or one stopped with respawn intent, gets a successor spawned by the pool reconciler (see runtime controls).
Creation pins everything the session will run with, in one transaction:
  • 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 maxPerSessionUsd spend cap is frozen into the session record, so editing the agent cannot rewrite a live session’s spend contract.
  • For a concurrency: 1 agent, the creation transaction claims the agent’s singleton slot. If another live session already holds it, the spawn is refused with 409 and the live session’s ID (AgentSlotConflictError), so you always know which session absorbed the work.
  • Git mounts are validated up front: a payload-templated ref that 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_imagebooting_containerpreparing_environmentstarting_runtimerunning. 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 and marks it semantically done, but an archived session in a resumable status is not dead — 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 long-lived dispatch workflow that drains its command queue in order. Three delivery behaviors matter when events and people talk to the same session:
  • Interrupt vs. defer. Delivered trigger messages interrupt the in-flight turn immediately so steering lands right away — except GitHub check and workflow-run completions (github.check_run.completed, github.workflow_run.completed), which defer until the session is idle so a CI verdict never aborts a turn mid-tool-call.
  • Trigger debounce. Trigger deliveries wait in a held lane and flush as one aggregated command once 5 seconds have passed since the oldest held delivery or 2.5 seconds since the newest. A burst of related events (a push plus its check runs) becomes one coherent update instead of five interruptions. Human messages and lifecycle commands never wait on this window. The transcript still renders each absorbed delivery as its own entry inside the bundled message.
  • Message batching. When several message commands are pending at delivery time, up to 32 are combined into one runtime turn. The batch stops at the first non-message command, so answers and stops keep their own turns.
Commands sent while the session is still queued (runtime provisioning) simply wait in the queue and deliver in order once the runtime is up. And a work-injecting command aimed at an archived session in a resumable status revives it: the same transaction that records the command clears archivedAt, so routed events can wake a session that had archived itself as done.

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 at awaiting), 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 is softer than both: it marks the session done-for-now while leaving it revivable. Three paths archive a session:
  • The agent archives itself with the auto.sessions.archive_current tool when its work is complete. The self-archive path is rejected while the session holds active held-policy bindings — an agent bound to an open PR cannot declare itself done; the closed-PR trigger’s release: true must free the binding first.
  • An operator archives it from the web app.
  • The auto-archive sweeper runs every 10 minutes: it archives awaiting sessions whose agent declares session.archiveAfterInactive and whose inactivity exceeds it (skipping sessions with active commands, turns, or checks), and repairs stale queued/running rows with no active work back to awaiting. Archiving releases the session’s bindings in the same transaction.

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 over SSE, shows queued messages, structured questions, bindings, and per-session usage; the sessions list live-updates with each session’s displayTitle, status, and an ambientStatus line 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.
Two display fields do the heavy lifting in lists: 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.