> ## Documentation Index
> Fetch the complete documentation index at: https://docs.auto.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Concurrency

> How concurrency: 1, replace: auto, onReplace, and onUnmatched: spawn work together for long-lived orchestrators.

`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:

```yaml .auto/agents/chief-of-staff.yaml (excerpt) theme={null}
concurrency: 1
replace: auto
triggers:
  - event: chat.message.subscribed
    connection: slack
    where:
      $.chat.provider: slack
      $.auto.authored: false
    message: |
      A user replied to the orchestration thread:

      {{message.text}}

      Continue coordinating as Chief of Staff and reply in the same thread.
    routing:
      kind: deliver
      # A human reply during a replace window must never drop: it spawns the
      # successor carrying the message instead.
      onUnmatched: spawn
```

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](/reference/runtime-controls) for slot, drain, and replacement mechanics, and [agent fleet](/examples/agent-fleet) for the orchestrator workflow in practice.
