Strategist · Designer · Operator

Launch
with Ben



Claude Code

Three Agents, One Repo, Nobody Steps on Anybody

Running several Claude Code agents against one repository without them colliding, and the four setup gaps that make the default arrangement quietly wrong.

The short version

Worktrees let several Claude Code agents share one repo without colliding, but the default branches from origin, and 6 of my 7 repos were ahead of it, one by 35 commits. Four setup fixes close the gaps.

What you will learn

  • Why a branch collides and a worktree does not
  • The four settings that make worktrees work
  • How a fresh worktree gets node_modules in 3 seconds
  • What goes wrong with per-checkout state and unmerged worktrees

Who it is for

Anyone running several Claude Code agents on one repository from a laptop where commits are frequent and pushes are rare.

Skip it if

Your team pushes continuously, or you work in a monorepo, which I did not test.

You leave with

A four-item setup checklist to apply to your repos before dispatching parallel agents.


On 2026-08-20 I had three Claude Code agents working one repository at the same time, plus two more on another. Nothing collided. The part that took a day to get right was not worktrees, which have been in git since 2.5 shipped in July 2015. It was four pieces of setup around them, and the most expensive one is a default that quietly branches every agent off code that is behind what I have locally.

6 of 7of my repos are ahead of origin right now
35commits, on the furthest one
0warnings the default setup gives you about that

Two agents, one repo, one broken checkout

The situation is ordinary once you dispatch more than one agent. Two of them are working the same repository. Agent A is halfway through editing a service. Agent B finishes its task, switches branch, and the files under Agent A change identity mid-edit. Agent A carries on against a file that is no longer the file it read.

That is not a rare race. It is the expected outcome, because of what a branch is.

Why a branch cannot do this

A branch is a pointer to a commit. One working directory holds one branch at a time, so moving the pointer moves the files in that directory. Every consumer of that directory sees the new files, whether or not it was ready to.

That makes branches a way to do work in sequence. Worktrees are the same repository checked out into more than one directory at once, sharing a single object store and a single set of refs, which makes them a way to do work in parallel. Git’s own git worktree documentation is the primary reference and it is a decade old.

I want to be careful about how strong a claim that is. It is a statement about mechanism, checkable in a minute, not a verdict about which tool is better. There are cases below where a clone beats both.

What does suggest the collision problem is genuinely hard, rather than a matter of my personal tidiness, is Anthropic’s own fix history. Three separate releases in five weeks patched agents escaping their isolation and reaching the shared checkout: v2.1.210 for subagents running git-mutating commands against the main repo, v2.1.216 for subagents redirecting git with git -C, --git-dir or GIT_DIR, and v2.1.222 for destructive git commands against the main checkout. Nobody ships three fixes for a problem that does not happen.

The setup I run

Claude Code creates and manages the worktrees itself. Anthropic’s worktrees documentation covers the surface: claude --worktree <name> from the main checkout puts a session in an isolated copy, EnterWorktree does it mid-session, and subagents take isolation: "worktree". I could not find the release that added the flag, incidentally. It is not in any of the 194 published releases going back to v2.0.73 in December 2025, so it predates the archive.

None of that is the interesting part. This is:

The four settings that made it actually work

Do

  • worktree.baseRef: "head" in ~/.claude/settings.json
  • A SessionStart hook that supplies node_modules to a fresh worktree
  • A .worktreeinclude in every repo, listing the gitignored config a worktree needs
  • .claude/worktrees/ in every .gitignore

Each one is a gap I hit, in the order the pain arrived.

Gap 1: the default base is origin, not what you have

worktree.baseRef shipped in v2.1.133 with two values, fresh and head, and the default is fresh. That branches a new worktree from origin/<default>. Not from your local HEAD.

If you push as often as you commit, this costs nothing. I do not. I measured every active repository on my machine the day I found this:

RepoCommits ahead of origin
launchwithben35
uxxray27
numerology20
vpn-editor9
itbroke-v47
layerview1
vpn-astro0

Six of seven. An agent starting in a worktree was starting up to 35 commits behind the code I thought I was handing it, and nothing said so. The worktree gets created, the build runs, the agent works. The only symptom is that the base was older than you assumed.

The number itself is not the finding, because it moves. Earlier the same day I recorded a different set: 8, 6, 15, 18, 19, 9. Hours apart, on one machine, every figure changed. The gap is not a constant to design around. It is whatever you have not pushed yet.

Gap 2: a fresh worktree cannot run your gate

A new worktree has no node_modules. The project’s own build command fails on arrival, and an agent that cannot run the gate starts inventing workarounds for it, which is worse than not running it.

.worktreeinclude is the wrong tool here: it copies file by file, and node_modules on these projects runs 300MB to 425MB. So this is a SessionStart hook that clones the directory with cp -c -R, an APFS copy-on-write clone. Measured on vpn-astro’s 425MB tree: 3 seconds, near-zero real disk, because the blocks stay shared until something writes to them.

Symlinking would be faster still. I rejected it, and this is the reasoning rather than a rule:

Symlink: instant, and shared. One agent running npm install some-package mutates every other agent’s dependencies mid-task.

Copy-on-write clone: 3 seconds, and isolated. Each agent’s npm install affects only itself.

The symlink survives as a fallback for filesystems without copy-on-write, and the session message says plainly that it is shared when it fires.

The reason this is a hook and not a line in a config file is the same reason instructions get ignored while enforcement does not. A fresh worktree session has no memory of needing node_modules. An instruction it must remember unprompted is exactly the class that fails. A hook fires itself.

Gaps 3 and 4: the boring ones that still cost an afternoon

.env is gitignored, so it does not exist in a new worktree, so the application does not boot. .worktreeinclude is what carries gitignored config across, and I had it in zero repositories out of seven. One of them needed api/.env, nested a level down, which is the kind of thing you find by watching a boot fail rather than by reading a doc.

And .claude/worktrees/ was in one .gitignore out of seven, so six repositories were one git add -A away from committing an entire second checkout of themselves.

Scoping tasks so agents do not collide

Isolation stops two agents corrupting one directory. It does not stop them writing incompatible changes to the same file and handing you the merge.

This next part is what I do, not a finding. I have not tested it against alternatives.

I scope by ownership rather than by size. One agent owns a directory or a subsystem for the length of its task, and tasks that would touch the same files go in sequence instead of in parallel, even when that is slower. I also keep deployment out of the agents entirely: they commit, run the gate, and stop, and the deploy happens once from the main checkout after everything has merged. Two agents deploying the same site from two worktrees is a problem isolation cannot help with, because the collision is on the server.

The other rule I hold to is that an agent never merges its own work. When it finishes it reports and stops, ending with the exact command I run from the main checkout. Merging stays a thing I say, not a thing an agent decides. This is the same instinct as keeping a strategist model out of the judge’s seat: the model is good at the work and should not also be the one grading whether the work lands.

main checkout→claude --worktree feature-a→commit + gate→report, stop
main checkout→claude --worktree feature-b→commit + gate→report, stop
main checkout→/land each branch, one at a time→deploy once

What breaks

Two failures, both real, both from this month.

Anything tracked that holds per-checkout position gets duplicated. I run unattended batches whose position lives in .agent/plan.json and .agent/cursor.json. In the repository where this happened those files were committed rather than ignored, so creating a worktree copied a snapshot of a live run into it. In another repository of mine the same directory is gitignored and the problem cannot arise, which is the whole distinction. A worktree session scoped to one issue was handed a subtask belonging to a completely different run in the main checkout, which had already finished that subtask, because the copy read its own frozen cursor:

CheckoutCursor
mainsubtask 3, completed 1.1, 1.2, 2.1, 2.2, 2.3
the worktree’s copysubtask 2, completed 1.1, 1.2, 2.1, 2.2

Nothing executed. The session stopped at its verify step and I caught it. Unnoticed, it would have been a second worker redoing committed work and then claiming credit against a run it was never part of. The fix was to stamp the plan with the path of the checkout that owns it, so a copy carries the original’s path and the mismatch is what identifies it as a copy.

That is not a worktree bug. It is what copying a working tree means, and it will find any file you keep that answers “where am I up to.”

A finished worktree is invisible until you look. Nothing native merges one back. I found an agent worktree that had been sitting for five days with one unmerged commit and thirteen modified files. The pull request existed. The commit was confirmed absent from main. The work was done and nothing was wrong with it, and it had simply never been put back.

This is the same failure the agent memory measurement turned up in a different disguise: the thing you are not logging is the thing that quietly is not happening. In that case it was worktree paths breaking the memory lookup, so the agents most in need of context were the ones receiving none.

When a clone is the better call

Sometimes it is, and dismissing that would be dishonest. Worktrees share one .git, which is the whole point and also the whole limitation.

SimultaneousShares .gitDiskCosts you
BranchNoSame checkoutNoneOne folder, one branch; a checkout moves files under whoever is using them
WorktreeYesYesOne working tree eachGitignored files do not come along; per-checkout state gets duplicated
CloneYesNoFull history eachHooks and config set up again per copy

Reach for a clone when the isolation has to cover git config or hooks themselves, when the copy needs to outlive your current repository layout, when the second worker is not yours to trust, or when the filesystem cannot give you a cheap copy. On a machine without copy-on-write, most of the speed argument for worktrees is gone.

What this doesn’t cover

One operator, one machine, macOS on APFS, seven single-author repositories, none of them a monorepo. The 3-second dependency clone is an APFS result and does not transfer to a filesystem without copy-on-write. worktree.sparsePaths exists because large monorepos behave differently, and I have not tested one.

The ahead-of-origin measurement comes from someone who commits constantly and pushes rarely. On a team that pushes continuously, the default baseRef costs close to nothing, and gap 1 would not have been my most expensive finding.

And nothing here measures whether parallel agents produce better work than sequential ones. Every claim above is about collision and setup. Whether three agents at once is a good idea is a separate question, and I do not have a number for it. What it does cost is straightforward: agents in parallel draw on your allowance in parallel, which is the thing that actually decides your plan, not the monthly price.


Related:

Sources

  • Git, git worktree: the primary reference. Shipped in Git 2.5, July 2015.
  • Claude Code docs, Worktrees: the vendor’s own guidance on parallel sessions.
  • Claude Code release v2.1.133 (2026-05-07): added worktree.baseRef, and the note itself flags that the default branches from origin/<default>.
  • Claude Code release v2.1.143 (2026-05-15): added worktree.bgIsolation: "none" as an opt-out, which is how you can tell isolation is the default for background sessions.
  • Claude Code releases v2.1.210, v2.1.216 and v2.1.222: three separate fixes for isolated agents reaching the shared checkout.
  • Measurements and configuration behind this post: docs/content/seeds/worktree-receipts-2026-08-20.json in this site’s repository, collected 2026-08-20.
  • Claude Code Subagents: Delegating Is 3x Cheaper: which tier of agent belongs in a worktree, and what a dispatch costs.
Ben Peetermans

Ben Peetermans

I build MVPs and run ad campaigns with AI, and I write these notes from real projects. Twenty years shipping for the web. If you want someone who works with these tools every day to build yours, that is what I do.