Skip to main content
Three groups of agent-file fields govern how an agent’s sessions run: concurrency (with replace, onReplace, and manages) caps and maintains a single live session; spendCaps bounds what sessions may spend; and model (with reasoningEffort) selects the model and its failover behavior. This page covers all three as implemented. For every other agent field, see Agent file.

Concurrency

integer
Cap on live sessions for this agent. Only 1 is accepted — the schema rejects anything else with “Only concurrency: 1 is supported; larger pools are a deliberate non-goal for now”. A concurrency-1 agent keeps at most one live session, called the slot member.
"auto"
Opts the agent into platform-managed slot replacement. auto is the only value, and it is an assertion by you: the agent’s state is fully reconstructable from external sources (chat threads, session lists, bindings), so the platform may stop a stale or failed member and spawn a replacement on the latest spec. Requires concurrency to be set.
string
The rebuild prompt delivered as a replacement session’s start message, trimmed, 1–20,000 characters. Supports file: references and the append: directive like other prompt fields. Requires replace: auto (nothing else consumes it); a generic fallback prompt is used when undeclared.
string[]
Agent-type names (max 64) whose sessions this agent may stop within its project. Authority belongs to the agent type, not to spawn provenance — a replacement session controls sessions its predecessor spawned. Self-control is always implicit, and unknown names are inert rather than invalid, so the managed agent can be applied or removed independently.

The slot at runtime

The slot is an agent.singleton session binding claimed inside every session-creation transaction. While a live member holds it:
  • A trigger routed kind: spawn converts to a delivery to the live member instead of creating a second session.
  • A manual start (UI or auto.sessions.spawn) is refused with a 409 naming the live session id.
  • Agent-addressed messages (auto.sessions.message with an agent name) resolve to the live bound member, so peers keep reaching the agent across replacements without tracking session ids.
  • A deliver trigger with no routeBy resolves the slot member; this shape is only valid on agents with concurrency: 1, or when a deliver-without-routeBy trigger on the agent declares onUnmatched: spawn — that spawn claims the slot itself.

Slot replacement

A platform reconciler (5-second cadence) keeps replace: auto agents healthy in three phases:
  1. Release. A member that archives itself leaves the pool at the end of its current turn; the slot frees within one sweep.
  2. Drain. When the applied agent spec drifts from the spec a live member was spawned with, the member receives one durable warning message: the definition changed, automatic replacement happens in five minutes, and it should checkpoint work and archive cleanly with a handoff — or stop itself with respawn intent to reload immediately. A member still live at the deadline is stopped with respawn intent. A spec that changes again mid-grace restarts the window against the new target; a spec that reverts cancels it.
  3. Replace. A member that failed (within a crash-loop budget of 3 failures per 30-minute sliding window) or was stopped with respawn intent gets a direct replacement: a slot-claiming spawn on the latest spec whose start message carries onReplace. A plain manual stop without respawn intent is the operator opt-out — nothing respawns.
Replacement is deliberately not replay: the successor shares no transcript, memory, or sandbox with its predecessor. Losslessness comes from the onReplace rebuild plus onUnmatched: spawn routing — during the brief window when no member is live, triggers routed onUnmatched: spawn (mentions, subscribed replies) spawn the successor carrying the event, while onUnmatched: drop deliveries (reactions, heartbeats) are dropped by design. A production example, condensed from this repo’s chief-of-staff agent:
.auto/agents/chief-of-staff.yaml

Spend caps

All three fields are optional; omitted values mean no cap. Values are exact nonnegative decimal strings with at most 10 integer and 10 fractional digits, matching the usage ledger’s numeric(20,10). YAML numbers, negatives, and exponent notation are rejected at authoring time — quote the value. Zero is valid and means a configured zero-dollar cap.
string
Agent-type cap on spend per UTC calendar day, summed across all of the agent’s sessions. Resolved from the active agent resource at enforcement time, so applying a spec change affects live sessions immediately.
string
Agent-type cap per UTC calendar month. Same resolution semantics as dailyUsd.
string
Lifetime cap for a single session. Copied into the session record at creation and immutable for that session — later spec changes apply only to new sessions.
Daily and monthly windows reset at UTC calendar boundaries (midnight UTC; the first of the month). There is no organization-timezone option.

Enforcement

When any cap is at or over its limit (an effective hit), the platform stops new spend without killing anything:
  • Session creation is refused while an agent daily/monthly cap (or a requester cap) is hit, with a message pointing at the admin override path.
  • Turn-starting commandsstart, startWithMessage, message, answer — on existing sessions are deferred rather than dropped: the command stays pending and is retried on a one-minute backoff until the cap clears. stop and interrupt are never deferred, so a capped session can always be terminated.
  • Idle capped sessions are parked with reason billing_spend_cap_exceeded and a resume condition tied to the cap: they wake automatically when the window resets or an override lands. A session mid-turn finishes its turn first — enforcement decisions happen between turns.
Organization admins can lift a cap without editing YAML: reversible overrides exist at the agent and session level (with a reason and optional expiry), granted from the web app or API. Requester-level spend caps — configured per human requester in organization settings, not in the agent file — are evaluated alongside agent and session caps in the same enforcement pass.
Spend caps bound model usage recorded to the session. They are a budget-control mechanism, not a security boundary: a capped agent’s session keeps its sandbox and pending state, and resumes exactly where it deferred once the window resets.

Model selection

object
Optional. When omitted, the harness default applies: claude-code runs anthropic/claude-opus-4-8; codex runs openai/gpt-5.6-sol. When present, id is required.
"anthropic" | "openai" | "openrouter"
Defaults to the harness’s default provider. Each harness accepts a fixed set: claude-codeanthropic only; codexopenai or openrouter.
string
required
The model to run. Curated per provider:OpenRouter ids are deliberately uncurated — the catalog is long-tail and changes independently of auto releases; the live service verifies existence against OpenRouter’s /models.
string
A top-level agent field (sibling of model, not nested in it). Allowed values and defaults are harness-scoped: claude-code accepts low | medium | high | xhigh | max (default high); codex accepts minimal | low | medium | high | xhigh (default medium). Some OpenRouter models narrow the set further (for example z-ai/glm-5.2 accepts only high | xhigh); an effort the resolved model does not support fails validation at apply time.
Model routing is snapshotted when a session launches: applying a model change affects new sessions only, and a session whose model was explicitly overridden at start has no fallback chain.

Fallbacks

Two mutually exclusive, opt-in fallback surfaces live on model. Both exist so a transient provider overload does not fail a turn; both are inert when absent.
array
Same-provider fallback, for any harness. An ordered chain of 1–2 entries, each { id } or { provider, id }:
Validation enforces: every entry resolves under the same harness rules as the primary; resolves to the same provider as the primary; ids are distinct from the primary and each other; and the agent’s reasoningEffort must be valid for every fallback (the gateway rewrites only the model, never the effort).At runtime, when a request naming the primary exhausts the gateway’s transient-retry budget (HTTP 429/529, roughly 20 seconds of cumulative backoff per model), the gateway rewrites the request to the next fallback and re-runs the loop. The first activation opens a 5-minute sticky window during which primary-named requests go straight to the fallback; after the window, the next request probes the primary again — fail-back is automatic, with no operator action. Requests for other models inside the session (subagents, title generation) pass through untouched.
object
OpenRouter-native fallback, valid only when the resolved provider is openrouter (codex agents today). Mutually exclusive with model.fallbacks.
  • models (required): 1–3 OpenRouter slugs, distinct, excluding the primary id (it is prepended automatically). OpenRouter fails over across the chain natively.
  • provider (optional) routing preferences: allowFallbacks (boolean), order (preferred upstream providers, in order), sort (price | throughput | latency), only / ignore (upstream provider allow/deny lists).

Observing a fallback

When a fallback serves a response, the platform is explicit about it: the response carries an x-auto-model-fallback: <id> header, the session’s conversation gets one status entry per activation (“Model fallback activated: running on fallback model … (primary … overloaded).”), and the auto.sessions.summary MCP tool reports a modelFallback object with the latest activation time and the fallback model. Usage is attributed to the model that actually served each request.
  • Agent file — the full agent field reference, including session policy (session.archiveAfterInactive)
  • Triggersrouting, routeBy, and onUnmatched, which concurrency semantics build on
  • Sessions — the session lifecycle these controls govern