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)
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(requiresconcurrency) asserts the agent’s state is externally reconstructable, so the platform may drain a session whose spec drifted and replace one that failed.onReplace(requiresreplace: 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
onReplacewith 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.