You're Running Five Agents on One Repo. Who Stops Them Overwriting Each Other?
Sometime in the last year the default way to use a coding agent quietly changed. You don't babysit one agent through one task any more — you fan out five, each on its own feature, and review the survivors. We run a fleet like this every day. It is genuinely faster. It also breaks in a way that nobody warns you about until it has already eaten an afternoon.
Here is the honest version of the problem, because the marketing version is wrong.
The marketing version vs. what actually happens
The pitch you'll read on a dozen tool landing pages is: "two agents in the same folder silently overwrite each other's files." We went looking for a real developer with that war story and couldn't find one. That specific claim is mostly vendor copy.
What we did find is more interesting, and worse.
One. Isolation is now table stakes — and it still loses work. An issue on Anthropic's own claude-code repo (#55724) documents it cleanly: "Tested with 13 parallel agents: 5 committed successfully, 8 failed due to lock contention." Even with every agent in its own git worktree, the worktrees share one .git/ directory, so they fight over .git/index.lock. The agent whose commit loses the race exits — and the worktree auto-cleanup then deletes its work permanently. Isolation didn't prevent the collision; it just moved it into git's plumbing.
Two. Developers forget to isolate, and the agents don't always do it for them. From Hacker News, a real practitioner (aubanel): "I want to work on several things in parallel through several agents, always forget to do worktrees, then the different branches of work tend to step on each other." Another: the orchestrator agent "sometimes uses git worktrees, sometimes not." The safety rail is opt-in and unreliable.
Three — and this is the one that matters most — even when isolation works perfectly, the conflict doesn't disappear. It just gets deferred to merge time. As one commenter put it, the real bottleneck "isn't human review per se, it's unstructured review." Two agents on two clean worktrees both edit the central router file. Neither knows. You find out twenty minutes and a few thousand tokens later, at the merge, when it's most expensive to untangle.
Simon Willison, who runs this workflow deliberately, frames the ceiling honestly: the limiter isn't the agents, it's "I can only review so fast." Worktrees and containers protect your blast radius. They do not tell you that agent C is about to redo the same twelve lines agent A just touched.
The cheap question nobody asks early enough
So here's the thing we kept coming back to: at merge time, git computes whether two branches conflict. That computation doesn't need the merge to have happened. It doesn't even need a branch. You can ask git the question — would these two sets of changes conflict? — at any moment, for free, before either agent has committed.
The tool is git merge-tree, in its modern form (Git 2.38+):
git merge-tree --write-tree --name-only <ref1> <ref2>
It runs a real three-way merge in memory — auto-detecting the merge base, using git's actual merge engine — and writes the result to the object store. It touches no working tree, no index, no HEAD. It creates no commit. It just answers:
- exit 0 → the merge is clean.
- exit 1 → conflict, and stdout lists the conflicting files.
- exit > 1 → a real error (bad ref), not a conflict. (Branch on the exit code; don't treat "non-zero" as "conflict.")
We verified every branch of that on Git 2.50.1. The result worth internalising is this one:
# agentE edits line 1; agentF edits line 5 of the SAME file
$ git merge-tree --write-tree --name-only agentE agentF ; echo "exit: $?"
edee7ce86fe24019e8ea6e1af8831e79cc7b38c9
exit: 0 # CLEAR
Same file, both edited — clean. A naive guard ("did both agents touch router.ts?") screams conflict here and is wrong most of the time. merge-tree does the real line-level diff3, so it only flags genuine overlap. It is exactly as smart as git's own merge, because it is git's own merge.
The one subtlety that makes it actually work
There's a catch, and it's the whole game: merge-tree only reads committed refs. It is blind to the index and the working tree. Point it at an agent mid-edit and it cheerfully reports the last commit's state and ignores everything uncommitted.
So to preflight an agent's in-flight changes, you first snapshot them into a throwaway, unreferenced commit — without disturbing the real index, HEAD, or checkout:
tmpidx="$(mktemp)"
GIT_INDEX_FILE="$tmpidx" git read-tree HEAD
GIT_INDEX_FILE="$tmpidx" git add -A
cand_tree="$(GIT_INDEX_FILE="$tmpidx" git write-tree)"
rm -f "$tmpidx"
candidate="$(git commit-tree "$cand_tree" -p HEAD -m preflight-candidate)"
# now: git merge-tree --write-tree --name-only "$candidate" <other-agent-ref>
That candidate commit is reachable from nothing and gets garbage-collected. Get this step wrong and your hook silently checks stale state — which is worse than no hook, because it lies to you.
The whole thing is 55 lines
We wrapped it as preflight, test-first, five cases (clean / different files, same-file-different-lines = CLEAR, same-file-same-lines = CONFLICT, dirty-working-tree snapshot, bad-ref-is-an-error). All green. The 40-second demo above shows all three checks running against four "agent" branches of one file.
As a PreToolUse hook on Write/Edit, it becomes a 200-millisecond gate: before an agent's patch lands, snapshot it, preflight it against the integration branch (or each sibling worktree's HEAD), and if it would conflict, hand the agent the conflicting file list now — while it still has the context to route around it — instead of at merge time.
What this is, and isn't
We're not selling you anything. This is one git merge-tree call with a careful snapshot in front of it, and we're showing the working code because the mechanism deserves to be better known.
Prior art is real and worth crediting: Clash surfaces cross-worktree conflicts during development (closest in spirit to this); Conductor, Crystal, uzi, and vibe-kanban orchestrate worktree-per-agent; container-use isolates each agent in its own container. They solve isolation. This solves the narrower, earlier question: would it merge cleanly right now?
And the honest limits: preflight catches textual conflicts — the same class git itself would flag — and nothing more. Two agents that rename the same variable in different files, both merging cleanly but logically fighting, sail through CLEAR. It tells you when git's auto-merge would break, which is the right gate for "should this patch land now." It does not read intent. Nothing this cheap does.
But for the failure mode that actually burns fleet time — two agents quietly converging on the same lines — the answer was sitting in git's plumbing the whole time. You just have to ask before, instead of after.
We build and run autonomous agent fleets in production. If you're wrestling with multi-agent coordination, talk to us.
Get the tool → preflight in agent-ops — open source (MIT), a single dependency-free script, part of our toolkit for running coding agents in production.
Found this useful?
- Your Agent Did the Work, Then It Vanished. Here's How to Get It Back.
- Your Claude Code Session Is Permanently Stuck on a 400. Don't /clear — Do This.
- The One Kind of Agent Work You Can't Recover — and How to Stop Losing It
- Your Agent Will Eventually Run git reset --hard. Stop It at the Door.
- Your Agent Reads Text You Can't See. Frisk It First.
- You're Running a Dozen Agents. Which One Is Stuck?
- What's Actually In Your Claude Code Session File (and a Tool to Read It)
- Your Agent Fleet's Worktrees Are a Minefield. Here's How to See It.
- The Agent Wrote the Code in Minutes. Reviewing It Takes Hours. Here's Why.
- Your Claude Agent Re-Reads Its Whole Prompt Every Turn. Here's the 10× You're Leaving On the Table.
- Your Agent Can Read Everything Your Shell Can. Have You Looked?
- The Loosest Line in Your Repo Is in .claude/settings.json
- The Most Expensive File in Your Repo Runs on Every Single Turn
- Your Skill's Description Is the Whole Ballgame
- Your Repo Already Knows How To Build Itself. Put That In the CLAUDE.md.
Related posts
The boring part: governance that enforces, not displays
Most "AI governance" is a dashboard. It shows you what an agent spent, what it touched, what it decided — after the fact, in a panel nobody refreshes until the bill arrives. A display is not a control. A control is the t…
Your Launch Deserves a Real Demo Video, Not a Screen Recording With Captions
Most product launches skip the demo video entirely, and the ones that don't ship one usually reach for the fastest option: a raw screen recording, maybe some auto-generated captions, posted as-is. It's better than nothin…
The MCP Ecosystem Is Growing Fast — and Quietly Becoming a Directory of Hosted Services
We [recently measured](/insights/in-the-registry-is-not-runs-2) whether the servers in the official MCP registry actually *run* (short version: 84% are remote-only, and under half of the installable ones boot clean). Whi…
Installing a Skill Usually Means Running a Stranger's Code
The pitch for Claude Code "skills" is that they're just *instructions* — a `SKILL.md` file with some markdown telling the agent how to do a task. That framing makes them feel safe to install. A prompt can't hurt you; wor…