$ git worktree list▊

One agent, one worktree

Nine AI agents in one checkout gave us a build that was red most of the time. One git worktree per agent fixed it. A short note on why parallel agents need separate working trees, how we set them up, and the three things that still go wrong.

Andrii Siuta · July 2026 · ~5 min read git worktree Claude Code Nx

01. The problem with one checkout

When components are independent, the obvious move is to port them in parallel. While porting a design system to Angular (the full story), one wave ran up to nine implementer agents at once, all in the same working tree. Each agent's last step is a verification run: type-check, tests, lint, a production build. Each run saw every other agent's half-written files.

The result, in the wave's own run report: the shared build was red most of the time.

  • False failures. Agent A's verification fails on agent B's unfinished component. A either wastes tokens investigating, or learns to ignore red, which is worse.
  • Races on shared state. Two agents committing at once fight over git's index lock. Two production builds write to the same output folder.
  • Commits that carry the wrong files. A bare git commit -a picks up a neighbour's edits. We forced pathspec commits (git commit --only -- <paths>), which helps with the commit but not with the build.
  • One agent's git surgery is everyone's. An implementer that "tidied" history with low-level ref commands rewrote the branch under eight colleagues.
  • Ports. Every agent's end-to-end run wants the same dev-server port.

It is not only agents. The main checkout was also shared with other Claude sessions switching branches in it, and one git reset --hard moved the wrong branch. A checkout is shared mutable state, and parallel writers on shared mutable state is a bug whoever the writers are.

02. What a worktree gives you

git worktree add creates a second working directory attached to the same repository: its own checked-out branch, its own index, its own files, but the same object store and the same refs. Creating one is cheap: no clone, no network, seconds.

one task, one worktreegit worktree add .claude/worktrees/wave2-task-7 -b wave2/task-7 feature/ui-kit
ln -s ../../../node_modules .claude/worktrees/wave2-task-7/node_modules
# the agent works, verifies and commits only in here
# the dispatcher lands it:
git -C .claude/worktrees/wave2-task-7 rebase feature/ui-kit
git switch feature/ui-kit && git merge --ff-only wave2/task-7
git worktree remove .claude/worktrees/wave2-task-7

From the next wave on, every implementer got its own worktree under .claude/worktrees/. An agent's verification now sees exactly the code it wrote on top of the last landed state, and nothing else. A red build means that agent broke something.

03. How we run it

  • Symlink node_modules. A fresh install per worktree costs minutes and gigabytes. Claude Code has a setting for exactly this (worktree.symlinkDirectories: ["node_modules"]), and subagents can be declared with isolation: worktree so the platform creates and cleans up the tree itself.
  • A port per agent. Agent N runs its e2e server on 4400 + N. Wave gates run on their own fixed port, after another project's dev server took the default one in the middle of a gate.
  • Only the dispatcher lands. Finished tasks are rebased onto the integration branch and fast-forwarded, one at a time, never while a gate is running. Agents never touch the integration branch.
  • Gates run on the integration branch, not in a task tree. A task proves itself; the wave gate proves the combination.
  • A long-lived worktree for a long-lived branch. The whole UI kit lived on one branch in one worktree for weeks, so the main checkout stayed free for reviews, hotfixes and other tickets.
  • Remove when landed. A finished task's worktree is removed the moment it lands. git worktree remove is allowed for agents; rm -rf is not.
Shared checkoutWorktree per agent
Verificationsees every agent's half-editssees one agent's work on landed code
Commitspathspec discipline, index-lock racesown index, plain commits
Builds and dev serversone output folder, one portper tree, port 4400 + N
Git mistakeshit everyonehit one branch
Integrationimplicit and continuousexplicit: rebase, fast-forward, gate

04. What still goes wrong

stale dependencies

A symlinked node_modules belongs to whichever branch installed it. One worktree was cut from a branch on the next framework major while the shared modules were still the old one: every first verification failed until someone ran a clean install. When the branch's lockfile differs from the one that installed the modules, the tree needs its own install.

background processes

Nx starts a daemon per workspace. Removing a worktree whose daemon is still alive leaves its cache folder behind, and a daemon whose graph went stale after a library rename silently skips the new library. Our verification script runs with the daemon off.

sprawl

Worktrees are cheap to create and easy to forget. Six weeks in, 46 were registered and about 20 belonged to merged or abandoned work, plus hundreds of megabytes of build copies. One cleanup took it to 7. Now a worktree is removed when its task lands, and a worktree for a human branch is created only when someone asks for isolation.

05. The takeaway

Parallel agents are parallel writers. Give each one its own working tree, its own port and its own branch; let exactly one actor integrate, in order, with a gate on the result. Git has had the primitive since 2015. The agents are what made it necessary.

A red build should mean one thing: the agent that ran it broke something.