Skip to main content
The agent fleet is the flagship example for long-horizon engineering work, and the shape auto runs on its own repository. A human tags @chief in Slack with a list of tasks. The chief splits the list into well-scoped briefs, dispatches one staff-engineer session per task, shepherds every session until its PR has green CI and clean review feedback, escalates only the decisions that belong to a human, and delivers one collated packet back in the thread when the batch is done. Between them, the two agents exercise nearly the entire trigger, routing, and lifecycle vocabulary — this page is worth reading even if you never deploy a fleet.

How it works

  1. Intake. A mention delivers into the chief’s single live session (spawning it if none exists). The chief reacts to the message, subscribes to the thread, splits the request into tasks that each land as one focused PR, raises ambiguities as crisp questions with a recommended answer, and posts a roster.
  2. Dispatch. For each clear task the chief calls auto.sessions.spawn — agent staff-engineer, an idempotency key of thread + task slug, and a message that is the brief: slug, statement, acceptance criteria, constraints, the chief’s session id, and the reporting protocol.
  3. Execution. Each staff engineer works in its own sandbox: branch, test-drive the change, open a PR with a Review Map, then bind the PR to its session with auto.bind and end its turn. Check failures, review comments, and merge conflicts on that PR wake the same session.
  4. Shepherding. Staff engineers report milestones (started, pr-opened, fixing-ci, blocked, ready) into the chief’s session with auto.sessions.message. A 15-minute heartbeat has the chief sweep the fleet: nudge stalled sessions, respawn dead ones, answer questions it can resolve itself, escalate the rest.
  5. The packet. When every task’s PR is green, reviewed, and reported ready — verified through introspection, not taken on faith — the chief posts one packet in the originating thread: per task, the PR link, what changed, what verification ran, and residual risks. Merging stays with humans.

The configuration

Three files: a shared runtime fragment, the orchestrator, and the worker.
.auto/fragments/environments/agent-runtime.yaml
.auto/agents/chief-of-staff.yaml
.auto/agents/staff-engineer.yaml
The example assumes a GitHub connection named github-acme and a Slack connection named slack.

Walkthrough

Division of labor is enforced by capabilities, not prompts

Both agents mount acme/widgets, but the chief’s mount is all-read (contents: read, pullRequests: read) with a depth: 1 shallow clone, and the chief has no github tool at all — it cannot write code, whatever a prompt injection or a confused turn might want. The staff engineer’s mount can push (contents: write, pullRequests: write) and its brokered GitHub tool names exactly five operations: read PRs, open them, update them, comment, search. Neither agent can merge — merge_pull_request would require both naming it and a mount merge: write capability, and this fleet grants neither. commitAuthor on the staff engineer’s mount sets the author on every commit the fleet pushes.

The chief is one durable slot with automatic replacement

Four fields turn the chief from “an agent” into “a service”:
  • concurrency: 1 caps the chief at one live session and makes bare deliver triggers resolve to that slot member. All four triggers deliver: mentions and subscribed replies use onUnmatched: spawn (a human message must never drop — it starts a fresh chief if none is live), while reactions and the heartbeat use onUnmatched: drop (cron and emojis never resurrect a finished chief).
  • replace: auto enrolls the slot in the platform’s pool reconciler. If the live chief’s session fails, or its agent definition changes underneath it, the reconciler replaces it: a definition change first delivers a five-minute wind-down warning so the session can checkpoint and archive itself cleanly, then a replacement spawns on the latest spec. Failure replacements are crash-loop guarded (at most three per 30 minutes).
  • onReplace is the replacement’s start message — the rebuild recipe. This chief’s recipe is a checklist against durable external state: session lists, open PRs, Slack threads. It works because the chief keeps no private state worth losing.
  • manages grants the chief authority to stop sessions of the named agent types via auto.sessions.stop — how it reaps dead staff engineers before respawning their task. A session can always stop itself (with respawn: true to cycle onto the latest spec deliberately); listing chief-of-staff additionally lets a replacement chief stop a lingering predecessor session.
See runtime controls for the field-level reference.

Dispatch and reporting are tool calls between sessions

The fleet’s nervous system is three auto.* tools (see auto tools):
  • auto.sessions.spawn creates one staff-engineer session per task. The idempotencyKey (thread id + task slug) makes dispatch replay-safe: re-running intake after a crash returns the existing session (created: false) instead of double-spawning an implementation.
  • auto.sessions.message carries traffic both ways — milestone reports up to the chief’s session id, steering and answers down to a worker — by injecting a message into the target session’s transcript.
  • auto.sessions.list plus the read-only introspection tools (auto.sessions.summary, auto.sessions.conversation, auto.sessions.triggers) let the chief verify “ready” claims against reality before assembling the packet.
The milestone vocabulary (started / pr-opened / fixing-ci / blocked / ready, each prefixed with the task slug) is pure prompt convention — but it is the convention that makes a fleet legible from one roster.

Staff engineers wait by ending their turn

After opening its PR, a staff engineer calls auto.bind (target type github.pull_request) and stops. From then on its four bind-routed triggers deliver everything that matters about its PR into its session: individual check failures, the aggregate roll-up success, conversation updates, and the synthetic github.pull_request.merge_conflict event from auto’s mergeability tracking. Check-completion deliveries defer until the session is idle, so a burst of CI results never interrupts a fix in progress. The check triggers use the same aggregate/individual split and headIsCurrent staleness guard explained in the handoff example.
The PR-conversation trigger deliberately has no $.github.auto.authored: false filter. The staff engineer must hear the pr-review agent’s comments — which are also auto-authored — so its own PR comments cost one no-op wake-up each. “Fixing” this filter makes the fleet deaf to its reviewer.

Composes with the code-review example

The staff engineer’s definition of done includes reading the pr-review comment for the latest commit — that reviewer is the code review example. Deploy both for the full loop: the fleet writes, the reviewer gates, the chief only reports ready when both agree. Without a reviewer agent, drop the pr-review clauses from the staff-engineer prompt and the aggregate-CI trigger message.

Install from the consolidated agent package

The retained Chief of Staff and Staff Engineer roles are published in @auto/agents — one thin file per agent:
.auto/agents/chief-of-staff.yaml
.auto/agents/staff-engineer.yaml
Under GitHub Sync both variables default from the Sync binding. In the template’s current revision the chief also works through direct sessions with Slack optional (its chat tool and chat triggers declare optional: true, so applies succeed with no Slack connection), and it may merge a ready PR when the requester explicitly says so — read the template before assuming the exact behavior above. Override any field locally; drop inherited entries with remove:. See managed templates.

Adapt it

  • Replace acme/widgets, github-acme, slack, and the staff engineer’s commitAuthor (your GitHub App’s bot login and noreply email).
  • Set the aggregate check name (All checks) to your repository’s real roll-up check, or remove that filter to react to every check.
  • Tune the heartbeat to batch volume — 15 minutes suits an active repository.
  • Point both prompts at your real contribution docs and test commands.
  • Add spend caps before large batches: maxPerSessionUsd on the staff engineer bounds a runaway task; dailyUsd on either agent bounds the fleet.

Try it

Merge the PR, let GitHub Sync apply, then tag the chief with one trivial task:
Confirm the intake reaction and roster reply, watch the staff-engineer session in the web app, and wait for the packet in the thread once the PR is green. Then try a two-task batch and watch the roster track both.