Skip to main content
concurrency: 1 is the only supported cap (the schema rejects larger pools by design). It gives the agent a single slot: one live session receives everything addressed to the agent, trigger spawns convert to deliveries while a holder is live, and manual starts are refused with a 409 naming the live session. The load-bearing companion is onUnmatched: spawn on slot deliveries:
.auto/agents/chief-of-staff.yaml (excerpt)
A deliver trigger with no routeBy resolves the agent’s slot, and validation requires either concurrency: 1 on the agent or an onUnmatched: spawn that can claim the slot itself — otherwise the apply fails with “A deliver trigger without routeBy resolves the agent’s concurrency slot; set concurrency: 1 on the agent or name a routeBy strategy.” For long-lived orchestrators, complete the pattern with automatic replacement:
  • replace: auto (requires concurrency) asserts the agent’s state is externally reconstructable, so the platform may drain a session whose spec drifted and replace one that failed.
  • onReplace (requires replace: auto) is the rebuild prompt delivered to the platform-spawned successor. Write it as a recipe over external state — list predecessor sessions, reconcile against open PRs and live threads, back-read the swap window — because nothing written to sandbox memory survives replacement.
  • Keep durable facts outside the session. This repo’s chief of staff ends its onReplace with the rule that makes the whole approach sound: “keep durable cross-cycle facts in Slack threads and Linear, never in memory files — the next replacement starts from external state exactly as you just did.”
  • manages: grants stop/manage authority over named agent types, so a replacement orchestrator controls sessions its predecessor spawned.
See runtime controls for slot, drain, and replacement mechanics, and agent fleet for the orchestrator workflow in practice.