August 25, 2026·7 min read

A worktree per agent, so they never step on each other

The moment you run more than one agent on the same repo, they start clobbering each other's files. The fix isn't cleverer coordination — it's giving each one its own copy of the working tree, so parallelism stops being a fight over shared state.

By Andrew Pyle

The first time I tried to run two coding agents at once on the same project, it went exactly as badly as it should have. They were both editing files in the same directory, and the result was the software equivalent of two people writing on the same page at the same time — half-finished edits from one landing in the middle of the other's work, a build that made no sense, and no clean way to tell whose change was whose.

My first instinct was to make them coordinate: locks, turns, a queue. That instinct was wrong, and recognizing why it was wrong is the whole point. The problem wasn't a lack of coordination. It was shared state. And the cleanest fix for shared state isn't to negotiate access to it — it's to stop sharing it.

01Isolate, don't referee

Coordination doesn't scale; isolation does

When two processes fight over the same files, you can try to referee — put a lock around the shared thing, make them take turns, build a protocol for who edits what when. This works for two and becomes a nightmare at ten. Every new agent is another party to the negotiation, another way for the coordination itself to deadlock or starve. You've turned a parallelism problem into a distributed-systems problem, and distributed-systems problems are where good weekends go to die.

Isolation flips it. If each agent has its own copy of the working tree, there's nothing to referee — they can all charge ahead at full speed because none of them can see, let alone corrupt, another's in-progress edits. The parallelism stops being a fight over one page and becomes a stack of separate pages that get collated at the end. Ten agents isn't ten times the coordination; it's ten independent workspaces and one merge step.

When parallel work fights over shared state, don't build a better referee. Remove the sharing. Isolation scales where coordination collapses.

02What it is

What a worktree actually is

Git has a built-in feature for exactly this, and it's underused. A worktree is a second (or third, or tenth) checkout of the same repository, living in its own directory, on its own branch — but sharing the one underlying object store. You're not cloning the whole repo ten times and eating ten times the disk and history. You're creating ten lightweight windows onto the same history, each of which can be on a different branch with a different set of uncommitted changes, none of them able to trample the others.

# give an agent its own isolated checkout on its own branch
git worktree add ../work-feature-a feat/thing-a

# a second agent, fully isolated from the first
git worktree add ../work-feature-b feat/thing-b

# each directory is a real working tree; edits in one
# are invisible to the other until they're merged.

The shared object store is doing quiet double duty here. It's why the setup is cheap, and it's also why the reunion at the end is trivial: because every branch lives in the same history, git can already see all of them and reconcile any two the moment their work is done. The economics are what make it practical at scale — standing up a worktree is a bit of disk and a moment of setup, precisely because the expensive part, the repository history, is shared. So the cost of adding one more parallel agent is close to nothing, which is the property you want when you're deciding whether to fan a task out across five workers or grind through it with one.

03Start clean

Start clean, from origin/main

There's a subtler failure the worktree fixes, and I only learned it by getting burned. When several agents are live on the same repo at once, the main checkout is almost never in a pristine state — it usually has uncommitted work sitting in it from whatever I was doing an hour ago. If a new agent branches off of that, it inherits a mess that has nothing to do with its task, and the mess rides along into its commits. So the rule isn't just 'a worktree per agent.' It's that each worktree branches from origin/main — a clean, known baseline — not from whatever happens to be checked out locally right now.

# fresh worktree, cut from a clean baseline, not from local state
git worktree add ../ajp-og-cards -b feat/per-page-og-cards origin/main

# I run this even for a one-character docs fix:
# ~1 second and a few megabytes buys a guaranteed clean start.

I run that one line even for a trivial change, because the isolation guarantee is always worth more than the second it costs. Every agent starts from the same defined point instead of from an accident of timing. This is the same instinct behind arranging the world so the unsafe thing can't happen rather than trusting myself to be careful — you don't earn safety with vigilance, you earn it with structure. A worktree cut from origin/main simply can't inherit a sibling's half-finished edit, because it never saw it.

04Isolate writers

The rule: isolate only what mutates

The discipline that keeps this from becoming its own kind of mess is to only reach for isolation when work actually collides. A worktree per agent is the right move when agents are editing files in parallel and would otherwise conflict. It is the wrong move — pure overhead — when the agents are only reading, or working on genuinely separate things that never touch the same tree. Read-heavy fan-out doesn't need isolation; it can all happen against one checkout because nobody's writing.

So the rule I follow is: isolate the writers, share among the readers. A sweep of agents auditing a codebase can all look at the same files at once — there's nothing to protect. A sweep of agents each transforming a different file needs a worktree apiece, because now there's real state to keep from tangling. Matching the isolation to whether the work mutates is what keeps the overhead honest instead of ceremonial.

05A fleet, named

A fleet, named by the task it holds

This isn't a hypothetical pattern for me. At one point this project had roughly thirty worktrees live at once, each one a directory named for the job it held — og-cards, net-thumbs, home-stats, turnstile, oz-sources — and each on its own branch: feat/per-page-og-cards, fix/oz-remove-source-names, investigate/home-stats. The naming does real work. When I run git worktree list, I'm reading a map of every parallel line of work in flight — which ones are features, which are fixes, which are investigations — without opening a single file.

That directory-per-task layout is what turns 'I can run one agent' into something an operator can actually hold in their head. The bottleneck stops being the machine — worktrees are cheap — and becomes my own ability to point work at the right slice of the repo and collect it when it's done. It's a big part of how one person can now keep a fleet of agents busy on genuinely separate problems at the same time, each isolated, each disposable, none of them able to reach into another's tree and break it.

06Merge pays off

Merge is where the parallelism pays off

The elegant part is that all the isolation collapses cleanly at the end, because git already knows how to reconcile separate branches — that's its entire job. Each agent worked on its own branch in its own tree; when the work is done, the branches merge back, and git handles the reconciliation with the same machinery it uses for any two people working apart. The wall-clock win is real: the whole batch finishes in the time of the slowest single agent, not the sum of all of them, because none of them ever had to wait their turn at a shared resource.

There's a quieter benefit too. Because each agent's work lives on its own branch, a bad run is trivially discardable — you throw away the branch and you're exactly where you started, with nothing half-applied to clean up. Isolation doesn't just make parallelism fast; it makes it safe to fail, which is the property that lets me set a fleet of agents loose on real work and sleep. The pattern is small — a built-in git feature most people skip — but it's the thing that turns "I can run one agent" into "I can run a fleet."