Per-worktree pipelines
Every worktree - every agent, every branch, every parallel line of work - gets its own pipeline instance, so parallel agents do not serialise behind each other on a single shared runner.
- Agent CI runs are isolated from untrusted input: no event data interpolated into shell steps, and agent passes run as separate jobs with separately scoped tokens
- Parallel agents get per-worktree pipelines rather than serialising on one runner
- CI completes in under 5 minutes (median)
- P95 CI duration is under 8 minutes
- Build system supports hermetic builds (reproducible outputs regardless of machine)
- CI run duration dashboard showing median under 5 minutes
- Remote cache configuration and cache hit rate metrics
- Build configuration showing incremental/changed-only targeting
- Infrastructure L2 (Build System) - basic build caching must be in place before remote caching is meaningful
What It Is
Every worktree - every agent, every branch, every parallel line of work - gets its own pipeline instance, so parallel agents do not serialise behind each other on a single shared runner. The pipeline is no longer a scarce, shared resource that work queues for; it is something instantiated per unit of work and torn down when that work is done.
This is a statement about orchestration. The question it answers is "who is allowed to run right now, and against what", not "how long does the run take". Making the run itself fast - caching, incremental compilation, the dependency graph, remote execution - belongs to the Build System, and a team that has not solved that will find per-worktree pipelines expensive rather than liberating. The two capabilities compound: a fast build makes parallel pipelines cheap, and parallel pipelines make a fast build visible.
The pressure comes from agent fleets. A human developer pushes a handful of times a day and rarely notices that CI is a single lane. Five agents working five worktrees in parallel notice immediately: each one waits behind the others, feedback latency for every agent becomes the sum of the queue rather than the length of its own run, and the parallelism that was the whole point of running a fleet evaporates at the pipeline boundary. The failure is easy to misread as "CI is slow" when it is really "CI is serial".
Concretely, per-worktree pipelines mean concurrency scoped to the worktree rather than the repository, ephemeral resources named per worktree rather than shared fixtures that two runs would fight over, and no global mutex on databases, test accounts, staging slots or artifact paths. The commonest blocker is not the runner pool at all - it is a shared piece of test infrastructure that two concurrent runs cannot both use, which quietly reimposes a queue no matter how many runners you buy.
Why It Matters
- Agent parallelism survives contact with CI - a fleet of agents that serialises at the pipeline gives you the cost of parallelism and the latency of a single lane
- Feedback latency stops depending on other people's work - a run's wall-clock time becomes a property of that run, not of how busy the repository was that afternoon
- Failures stay attributable - when two branches share a database or a staging slot, a failure in one shows up in the other, and debugging becomes an exercise in proving your change was innocent
- Queue depth stops being a hidden capacity signal - once runs no longer wait on each other, the remaining bottleneck is visible as an actual resource limit rather than as an emergent traffic jam
- Branch-scoped environments make review meaningful - a reviewer can exercise a change against infrastructure that belongs to that change alone, rather than against a shared environment that reflects several changes at once
Getting Started
- Find where runs actually serialise - Instrument queue time separately from run time. If a 4-minute pipeline has a 12-minute wall clock, the problem is contention, and the next question is what it is contending for: runner capacity, a concurrency group, or a shared fixture. Teams routinely buy runners to fix what turns out to be a shared test database.
- Scope concurrency groups to the worktree, not the repository - Most CI providers default to sensible-looking repository-wide concurrency settings that become a global lock under agent load. Key concurrency on the branch or worktree identifier, and use cancel-in-progress only within a single worktree's own runs, never across worktrees.
- Make every shared fixture per-run - Databases, message queues, object storage buckets, test user accounts, seeded fixtures: each of these must be created per run with a name derived from the worktree, and destroyed at the end. This is usually the largest piece of work and the one that actually unblocks parallelism.
- Give agents real worktrees rather than a shared checkout -
git worktreelets several agents work on the same repository in separate directories with separate branches and no shared index. Agents sharing one checkout will collide on state long before they collide on CI, and the collisions are harder to diagnose. - Let the pipeline shape follow the change - Dynamic or parent-child pipelines let a run decide which jobs it needs based on what the worktree touched, so a docs change does not queue behind the same jobs as a schema change. This is orchestration, not incrementality: the build system still decides what to rebuild, the pipeline decides what to run at all.
- Set a per-worktree resource ceiling - Unbounded parallelism is its own outage. Cap the number of concurrent worktree pipelines, make the cap explicit and visible, and treat hitting it as a capacity signal rather than something to silently absorb. Autoscaling that capacity is a later level; knowing where the ceiling is comes first.
The diagnostic that settles the argument is to launch several agents at once on unrelated changes and plot each run's queue time against its execution time. If queue time rises with the number of concurrent agents, the pipeline is serial no matter what the architecture diagram says.
Common Pitfalls
Adding runners to fix a contention problem. More runners help only if runners were the constraint. When the real constraint is a shared staging environment or a concurrency group set at repository scope, extra runners sit idle while runs still queue, and the team concludes that CI cannot be made parallel. Always identify what the queue is waiting for before buying capacity.
Building a caching layer into the pipeline to make serial runs bearable. Slow runs make serialisation hurt more, so teams often attack the symptom by hand-rolling cache steps in the pipeline definition. That is the Build System's job, done in the wrong place and with weaker correctness guarantees. Fix the build tool, and let the pipeline concern itself with what runs concurrently.
Cancel-in-progress applied too widely. Cancelling superseded runs is sensible within one branch and destructive across branches. Under agent load, an over-broad cancellation rule turns into agents killing each other's pipelines, which reads as flakiness and is almost impossible to attribute after the fact.
Ephemeral resources that are not actually ephemeral. Per-run databases and buckets that are created but never reliably destroyed accumulate until quotas run out, usually at the worst moment. Teardown must run on failure and on cancellation, not just on success, and something must sweep the leftovers that escape anyway.
Assuming per-worktree isolation extends to the outside world. Runs may be isolated from each other and still share a rate-limited third-party API, a single sandbox account with an external provider, or one set of credentials. Under parallel agent load these become the new serialisation point, and they are outside the CI system where nobody is looking for them.
How Different Roles See It
Bob authorised a pilot with five agents working in parallel and the throughput gain was far smaller than the pilot's business case assumed. The agents produce changes quickly and then all five sit waiting for CI, one at a time. His platform lead wants to triple the runner pool.
Bob should ask for the queue-time breakdown before approving the spend, because the two possible causes have very different price tags. If runs are waiting on runner availability, more runners is the right answer and the cost is predictable. If runs are waiting on a concurrency group or a shared staging database, more runners changes nothing and the actual work is making test infrastructure per-run - cheaper in money, more expensive in engineering time, and invisible unless someone asks. Bob should also reset expectations on the pilot: a fleet's throughput is bounded by the narrowest serial point in the delivery path, so the honest measure of the pilot is not how fast agents produce changes but how many changes reach a verdict per day.
Sarah's CI dashboard reports a healthy median pipeline duration, and yet developers and agents both experience CI as slow. The two facts are not in conflict: she is measuring execution and they are experiencing wall clock.
Sarah should split the metric in two and report queue time separately from run time, then chart both against the number of concurrent runs. The shape of that chart is the whole diagnosis - flat queue time means capacity is adequate, queue time rising with concurrency means something is serialising. She should then attribute the queue time to a specific waiting reason, because "waiting for a runner", "waiting for a concurrency slot" and "waiting for the shared integration database" are three different projects. Sarah should present the result as a ceiling rather than a complaint: the number of agents the current pipeline architecture can support before feedback latency degrades. That number tends to be smaller than anyone expects, and it makes the case for per-worktree isolation without needing to argue about it.
Victor runs several agents against the same repository and has watched them interfere in ways that look like flaky tests. Two agents' integration runs both migrate the same test database; whichever finishes second fails, and the agent then spends its next turn confidently debugging a failure that has nothing to do with its change.
Victor should make the isolation boundary the worktree and enforce it everywhere the run touches state. That means each agent gets its own git worktree, the pipeline provisions its own database and its own external test accounts keyed on the worktree name, and the concurrency group is scoped so that two worktrees can never be each other's problem. He should verify it adversarially rather than optimistically: launch several agents on deliberately conflicting changes and confirm each gets an independent verdict. Victor should also feed the isolation model back into the agents' instructions, because an agent that knows its environment is private will stop writing defensive retry logic around collisions it can no longer have - and an agent that does not know will keep inventing workarounds for a problem you have already fixed.
Further Reading
From the Field
Recent releases, projects, and discussions relevant to this maturity level.
How This Guide Changed
What each edition changed in this guide, newest first.
- V1.6September 2026LATEST
Per-worktree pipelines replaced Bazel and remote caching at this rung: what L3 asks is whether parallel agents each get their own pipeline instance instead of serialising behind one another. The old criterion failed twice over. Content-addressed and remote caching are Build System capabilities and now live there, and naming a specific build tool and a specific vendor made the product the requirement rather than the property the requirement was meant to describe.
- V1.0March 2026
Shipped in the first edition for codebases where caching and parallelism have already been spent. Its argument was about correctness rather than speed: Bazel can serve a build action out of a shared remote cache because every action declares its exact inputs and outputs, which is what makes that cache trustworthy where other build systems' caches are merely fast.
Where does your team actually sit on this?
This guide describes one level of one area. Run the assessment to place your team across all 16 areas, see which gates you have passed, and get a report you can take to your stakeholders.