git checkout -b feature-a while the other is mid-edit; one runs pnpm install while the other reads node_modules; both write to the same file and the last save wins. The failure isn’t hypothetical — it’s the default outcome of naive fan-out, and it’s why most agent tools serialize everything and call it a day.
Serializing is the wrong fix. Agent work is embarrassingly parallel in shape — N tickets, N reviewers, N research angles — and agents are slow enough (minutes per task) that parallelism is the difference between an hour and a night. What you actually need is three separate mechanisms: concurrency control (how many lanes run at once), filesystem isolation (each lane gets its own working copy), and fan-in (a fold step that can see every lane’s result). Smithers ships each as a first-class primitive: <Parallel>, <Worktree>/<Sandbox>, and deps-driven fold tasks.
Be honest about the costs before reaching for this. Anthropic’s own multi-agent research system write-up measured that multi-agent runs burn roughly 15x the tokens of a single chat — parallelism multiplies spend linearly with lane count, plus the orchestrator’s overhead. And the hard part is rarely the fan-out; it’s the merge. Ten agents that each finish a feature in their own lane produce ten branches that touch overlapping files, and reconciling them is where runs actually die.
How the industry solves it
Fan-out/fan-in is the oldest pattern in distributed computing — MapReduce is literally named after it — and every orchestration system has a version.
Two industry conclusions worth stealing. First, git worktrees have become the standard local isolation primitive for coding agents — Conductor and Crystal are built entirely around them, because a worktree shares the object store (cheap, instant) while giving each agent a private index, HEAD, and working copy. Second, for untrusted or destructive work, filesystem isolation isn’t enough and the industry reaches for microVMs (Firecracker underpins both AWS Lambda and E2B).
Smithers does both: worktrees for parallel lanes on your machine, provider-backed sandboxes when you need a real boundary.
How Smithers does it
<Parallel>: concurrency without chaos
<Parallel> runs children concurrently with two independent caps (full reference):
maxConcurrencycaps leaf tasks in the group’s innermost scope.subtreeConcurrencycaps direct children as whole subtrees — the right cap when each child is a sequence (implement → review → land), because a nested<Parallel>escapes the outer leaf cap.
SMITHERS_AUTO_MAX_CONCURRENCY_CEILING (default 16); --max-concurrency N pins it. A task runs only if the leaf cap, subtree cap, and run cap all pass. Admission is deterministic in document order, so a resumed run re-admits the same lanes.
<Worktree>: one working copy per lane
<Worktree path="..."> roots its subtree in an isolated git or jj worktree; descendants inherit the absolute worktreePath as their cwd (full reference). Worktree creation is serialized per VCS root because concurrent git worktree add / jj workspace add calls mutate the shared .git state (see packages/engine/src/engine.js).
Merging: the real bottleneck
Smithers does not auto-resolve conflicts — nobody credibly does. What it gives you is structure:<MergeQueue> serializes landing (default maxConcurrency: 1, priority 1000 so ready landing work jumps the queue), which converts an N-way conflict free-for-all into N sequential rebase-and-resolve steps, each performed by an agent that can see what landed before it. Cheap discipline that removes most conflicts: partition lanes by file ownership up front, and land early and often rather than letting ten lanes drift for hours. Note that jj-backed worktrees continuously snapshot the working copy onto the lane’s bookmark, so merge steps should diff against the base branch (git diff main...HEAD), not trust git status dirty-state.
<Sandbox>: when a worktree isn’t enough
Worktrees isolate the working copy, not the machine — a lane can still rm -rf ~, read your env, or hit the network. For untrusted or destructive work, <Sandbox> runs a child workflow through a provider (bubblewrap, docker, or any object registered via registerSandboxProvider, including microVM backends like the @smithers-orchestrator/daytona and microsandbox packages), with allowNetwork, egress proxy/CA controls, resource limits, and diff review (reviewDiffs defaults to true) before changes touch your tree. See <Sandbox> and sandbox providers.
Guarantees and limits
- Guaranteed: deterministic lane admission on resume; serialized worktree creation; worktree
cwdinheritance; caps enforced at leaf, subtree, and run level;DEPENDENCY_DEADLOCK(not a hang) when adepskey names a task that never produces. - Not guaranteed: conflict resolution (an agent or a human does it); dependency installation in fresh worktrees (lanes must
pnpm installthemselves — the isolation preamble tells agents this); cost control (N lanes ≈ N× tokens; cap concurrency and lane count deliberately). - Cleanup is yours to run: finished runs leave worktrees behind until pruned.
Operating it
See also
<Parallel>·<Worktree>·<MergeQueue>·<Sandbox><GatherAndSynthesize>— packaged fan-out/fold for research-shaped work- Common footguns — the output-pool and
outputMayberules fold tasks depend on - Why: durable open orchestration — the Dynamic Workflows comparison in full