Parallel Agent Delivery across Worktrees: the Throughput Bottleneck Is Isolation, Not the Model
Background: after one person runs a fleet of agents, where the bottleneck moves
Over the past two-plus months, 400+ PRs were merged across two product repositories, with five to ten Claude Code sessions open at peak, each session working its own task. That throughput was not a free gift of stronger models — the model merely removed "writing code" as the bottleneck, and the bottleneck immediately moved elsewhere: parallel sessions stepping on each other, review loops that never converge, CI queues. In retrospect, what actually worked was four kinds of isolation — all ordinary engineering, none of it about prompts.
Workspace isolation: worktree as session, governance first
One git worktree and one branch per task, sessions bound to worktrees, PRs as the only merge channel. Everyone knows this layer. What gets skipped is governance first: in the repo's first week, put down the agent conventions (AGENTS.md written as an index, not a manual — pointing to specific docs per task), ADRs, CI gates and guard scripts, and state the skeleton status plainly in the README — a service that compiles and passes health checks but has unwired capabilities does not count as capable, and must not be reported as available. Agent output quality is extremely sensitive to "how the repository describes itself": these files are not etiquette for humans; they are runtime constraints for parallel agents. Without them, scaling up means scaling chaos.
Runtime isolation: ports go from convention to allocation
With several worktrees booting the full local stack at once, the first collision is ports. The scheme is slots: slot N shifts every application port by 10×N as a block, and slot 0 equals the historical port table exactly, so single-checkout users notice nothing; a script auto-claims the lowest slot that "no sibling worktree holds and whose ports are actually free" and pins it into a local file, overridable by environment variable when needed. Alongside it, one idempotent make up: slot → render config → database → migrations → infrastructure → services, returning only when everything is ready. The personal-site repo had long since hit the miniature version of the same problem (audit's fixed port 3000 taken by another worktree), worked around by hand-switching to 3001 — the comparison makes the conclusion obvious: before parallelism rises, turn ports from "convention" into "allocation", once and for all.
Fact isolation: requirements mirrored into the repo, anchored by revision
Requirement docs live on the collaboration platform (Feishu); agents work in the repo; carrying context by hand guarantees drift. The approach is whole-corpus archiving: all ten-odd PRDs mirrored into docs/product/, each file header recording the revision number at sync time; the collaboration platform stays the single source of truth for requirements, and the repo copy is a read-only mirror with an anchor. Markdown export drops Feishu's embedded spreadsheets (109 of them); the normative tables — numbers, status enums, acceptance criteria, exception boundaries — were exported and cross-checked back in one by one. A by-product of this grunt work: it caught several places where the prose and the tables contradicted each other — the requirement docs didn't know they were wrong; the mirroring pass was a free requirements audit. Delivery tracking uses GitHub epics + sub-issues, splitting PRDs down to acceptance-item granularity so a session starts work directly against an acceptance item.
Bounded review: agent cross-review needs a termination condition
Using another agent for PR review does not converge by default: fix → push → request review → another round of low-priority findings → fix again, with no step being an endpoint. The rule was changed to count in "completed review rounds": two consecutive rounds with only P2/P3 findings terminate general review, with one narrow exception reserved for "high-risk P2 with concrete impact evidence"; "no findings" ends the review outright instead of triggering a confirmation round. The policy itself ships with eight decision evals — review policy is code too, and changing it requires regression the same way.
CI: save time on caches, never on coverage
With many parallel PRs, CI latency becomes the throughput ceiling directly. Two time-saving traps: first, the Go build cache pointed at a freshly created gitignored directory, i.e. two fully cold compilations every run; second, GitHub Actions cache scope is "the writing branch + the default branch" — if CI hangs only on pull_request events, every PR's first run is forever cold. You need a warm job that writes the cache from main; it gates nothing and exists only so every PR has a cache to read. Coverage moved the other way, shrinking: full-stack smoke went from every-PR to on-demand, and the CI database stack boots a single Postgres. Fast checks run all the time, slow checks run on demand — the same trade-off as the personal site's audit (quick/deep tiers).
Transferable judgments
The bottleneck ordering for parallel agent delivery: isolation > review termination conditions > CI latency > model capability. The four isolations are independent and none can be skipped: workspace (worktree + governance files), runtime (port slots), facts (requirement mirror + revision anchors), review (bounded convergence). Once these are in place, the human's job turns from writing code into scheduling and acceptance — and the single step contributing most to throughput is splitting PRDs to acceptance-item granularity: it decides whether each session can start work without asking a human.