Main context decides.
Workers execute.
Parallel agents go wrong when each one is allowed to make its own design calls. Swarm mode splits the two jobs. The main session decides everything, writes each decision into a recipe, then hands identical workers a task that is already settled.
One subagent, by design
The baseline ships exactly one subagent, called swarm-worker, and the constitution fixes that number at one (Article II). This page is about why one is the number, and why it is not a setting you can raise.
A subagent gets its own context, sealed at both ends: what the main session knows stays outside it, and how the subagent reasoned stays inside. If you hand it a decision, the judgement moves somewhere nobody can review. Do that four times over and four choices made in isolation all land in one repository, each of them defensible on its own terms.
So every decision stays upstream of the worker. Before dispatch the main session writes two documents for each task: a scenario recipe naming exactly which failing tests to write, and an implementation contract naming exactly which files may be touched and what they must do. The worker's prompt carries both of them word for word.
The worker then runs two skills and reports back as JSON. Its job is the recipe as written and it ends there, because every call worth an argument was settled while there was still somebody able to argue about it.
Waves and write sets
/swarm-plan turns an approved spec into one task per component, and every task declares up front which files it will write.
That declared write_set is what makes the rest work. A scheduler sorts tasks into waves under a single rule: within a wave, every write set must be disjoint from every other. Two workers therefore always hold different files, and the usual reason parallel agents corrupt one another is gone before the run starts.
"id": "T-001" "component": "auth-token-store" from the C4 diagram "acs": ["AC-001", "AC-002"] "write_set": ["src/auth/store.py", "tests/auth/test_store.py"] "read_set": ["src/common/http.py"] "depends_on": []
The plan is built entirely from documents that already exist. Components come from the spec's C4 diagram, acceptance criteria from its table, and dependency edges from its graph, while the file paths come from the scout report which mapped components to files earlier in the workflow.
Waves are computed rather than chosen: the validator sorts by dependency with the no-overlap rule folded in, so the same plan will always yield the same schedule.
If a worker reaches outside its declared set, the write is blocked at the tool boundary, whichever isolation mode the run is using. While a wave is live, swarm_boundary_guard inspects every write (both modes, no exceptions), which is what turns the declaration into a promise the guard can keep.
Two ways to keep workers apart
Each worker gets its own git worktree, a separate checkout of the same repo. Work reaches your tree only after a merge audit compares each worktree against the recorded baseline commit and confirms it stayed inside its write set.
Workers run against your working tree, kept apart by the boundary guard alone. Cheap to start, with the guard as the single layer.
Shared mode is what ships by default, so swarm runs with the boundary guard as its only barrier unless you change it. Worktree mode is opt-in through swarm.isolation, and it buys a real second layer: a worker that somehow slips past the boundary guard still has to survive the merge audit before its work can land. Swarm now fires on any spec with an independent component, so that layer is worth turning on before you lean on parallel runs.
If a tree has no git at all, swarm mode is simply unavailable: /triage strips the swarm phases as it sets up the workflow, and a later request for swarm is refused. Worktrees need git, which is the whole reason swarm mode does. Shared mode stays a choice for git projects that want the speed (it is never a fallback for a tree without git).
The single-wave limit
Worktree mode handles one wave per run, and the reason is worth stating plainly.
The base commit a worktree forks from is chosen by the tool that creates it, outside the baseline's control, and wave output is applied to your tree without being committed. Put those two facts together and a second wave will fork from a commit predating everything the first wave did.
So the baseline refuses that combination rather than engineering around it. Before dispatch, a safety check compares the plan's wave count and the worktree's real merge base against what was recorded. A multi-wave plan under worktree isolation aborts before a single worker starts, and the plan is then steered to shared mode.
This limit was found the hard way, on a real run that forked from a stale ref. Some limits resist engineering, and those are generally better documented than rediscovered.
When solo wins
Swarm is now the default route: any spec with at least one independent component goes through planning, dispatch and the merge audit, and only a spec with no independent component falls back to /tdd solo. The threshold sits in project.json, so raise it if your specs are usually small enough that planning costs more than parallelism returns.
Components have to be genuinely independent, and the write sets are what tell you whether they are. Two tasks that keep reaching for the same file are really one task; force them apart and the plan will simply run them in order anyway.
Swarm mode parallelises inside one session. Several sessions working one spec between them is the org track, which answers a different question altogether: how a group of peers shares a single body of work.