Skip to content
// guide

Stop AI coding agents overwriting each other's files

Run Claude Code and Codex in the same repo at the same time and one of them will eventually stomp the other's edits. An uncommitted change vanishes, or two versions of the same function land in one merge. This is the practical fix list, ranked from free-and-simple to full coordination, written from the seat of someone who runs three agents on one codebase every day.

Updated 2026-09-01

Short answer

The overwrite you notice is a merge conflict. The one that hurts is an uncommitted change quietly replaced, because git never saw it and so cannot give it back. Commit often enough that the work exists in history, keep agents on separate branches, and have them declare the paths they are about to touch so the second one is refused rather than left to discover the loss afterwards.

What actually goes wrong when two agents share a repo?

One agent's edit disappears, or two agents write conflicting versions of the same file and you find out at merge time. Those are the two failure modes, and they're different. The first is a genuine race: agent A reads route.ts, agent B reads the same file, both edit their in-memory copy, both write: B's save lands last and A's change is silently gone, no conflict marker, no warning. The second is quieter and worse: each agent commits its own coherent version on its own branch, everything looks fine, and the collision surfaces as a merge conflict full of AI-authored code you now have to referee.

The first time I ran three agents on this very codebase (Claude Code, Codex CLI, and Cursor, one repo) I lost about twenty minutes of work to exactly the first case before I'd built anything to stop it. Two of them decided the same API route was theirs. Nobody was wrong; nobody knew the other existed.

Why do AI agents overwrite each other in the first place?

Because each agent assumes it's the only writer. A coding agent's edit loop is read-file → reason → write-file. It has no notion of a peer holding the same file open, and the filesystem won't stop it: last write wins, always. Git doesn't save you either: it only sees a conflict once both changes are committed on divergent branches. In the window between two agents reading and two agents writing, there is no referee at all. The more capable the agents, the faster they collide, because they move through files quicker than you can watch.

“My agents keep stepping on each other”

That phrase is the symptom; overwriting is the mechanism. People reach for it because what they notice first is not a lost file, it is the feeling that the agents are in each other's way: one undoing a change the other just made, two of them rewriting the same import block in opposite directions, a test that passes and then fails without anyone touching it. Anthropic's agent teams documentation, read on 2026-08-14, uses the same framing when it recommends giving each teammate a separate piece to own. If that is what you are searching for, the three fixes below are the answer, and they are ordered by how much they cost you rather than by how much we would like you to use them.

Fix 1: split the work by directory and use git worktrees

If the tasks are genuinely separate, give each agent its own directory and its own branch. This is free and it works. A git worktree is a second checkout of the same repository backed by one object store, so agent A edits in ../repo-a and agent B in ../repo-b and neither ever sees a half-written file from the other. Combine that with a hard task split (one agent owns apps/web, another owns packages/db, and they do not cross) and the overwrite problem evaporates.

git worktree add ../repo-web   feature/web-agent
git worktree add ../repo-db    feature/db-agent
# point one agent at each directory; keep their paths disjoint

The honest caveat: worktrees isolate the filesystem, not the intent. They stop the mid-edit race, but if both agents end up touching lib/shared-util.ts anyway, you've just deferred the collision to merge time. Worktrees are the right answer when, and only when, you can carve the work into provably non-overlapping directories. When you can, stop here; you don't need anything else. The full worktrees comparison walks through exactly where that line is.

Fix 2: run one agent at a time

The zero-infrastructure answer: never have two agents editing at once. Safe, and slow. Let one agent finish a task, review and commit, then hand the next task to the next agent. There is no race because there is only ever one writer. For a lot of solo work this is genuinely the correct call: coordinating two agents that finish in five minutes each is more overhead than just running them back to back.

The cost is the whole reason you wanted parallel agents. You bought three agents to get three things done at once; serializing them throws that away. It also doesn't scale to more than one human. The moment a teammate points their own Claude Code at the same repo, you are back to two uncoordinated writers and "just take turns" stops being enforceable.

Fix 3: claim an advisory path lock before editing

Let the agents share a working tree, and make each one claim the paths it is about to touch. An overlapping claim is refused when the agent asks, rather than surfacing after the edit. This is what Befall does. An agent announces intent, "I'm taking apps/web/app/api/**", and the room checks that glob against everyone else's active claims. No overlap: the lock is granted with a TTL. Overlap: refused with a 409 and the name of the agent already holding it, so the second agent picks non-overlapping work instead of racing into a file that's already being edited.

Claims are advisory and first-writer-wins: they auto-release on a TTL (default 30 minutes) or the moment an agent goes offline, and a lead can force-release a stuck one. Advisory is the load-bearing word. An agent that never calls the tool is never refused, and a refused agent that edits anyway is not stopped — Befall declines a request, it does not sit between a process and the filesystem. The git side is the backstop, and it works at a different granularity: each checkout's daemon heartbeats that working tree's dirty paths, so an edit made without a claim is visible as a property of the tree. Git never names the process that wrote a file, so an unclaimed edit is counted against the checkout, not against an agent. On GitHub the pull-request check names the claims that overlap the PR's files and who holds them.

What does it look like when it works?

A refusal carries the holder, its tool, and one concrete file both claims cover. This is the shape of that payload, written out — Befall ships no CLI that prints these lines:

agent A → claim  apps/web/app/api/**        granted · ttl 30m
agent B → claim  apps/web/app/api/route.ts  409 refused
  held by A (claude) · both claims cover apps/web/app/api/route.ts

Agent B now has the one fact it was missing before it opened the file: the path is taken, and by whom. What it does with that is up to agent B — Befall recorded a refusal, not a prevented write. That is the whole trade: an agent that asks finds out at claim time instead of at merge time.

The reason this is a product and not a shell script is that "do these two paths overlap" is deceptively hard. A verbatim edge case from the test suite: src/**/api must match src/api. The **/ has to match zero directories as well as many. Our first implementation got that wrong; a regression test pins it now. The boundary cases bite too: src/api and src/apiary must not collide on a naive prefix check. Every overlap decision in Befall routes through one pure, heavily-tested glob-intersection module: exactly the thing you don't want each team re-deriving in a bash one-liner.

Does this mean uploading my code somewhere?

No. The fix is coordination metadata, not your source. What leaves the machine is paths, branch names, commit SHAs, dirty-path lists, claims, task titles and free-text descriptions, and the messages agents explicitly send. Source code and diffs never leave: Befall coordinates on the shape of the work, not its contents. The caveat that matters is the one people skip: task text and messages are content you author, they are stored, and nothing stops an agent pasting a function into a handoff note — so treat them as a room chat. Realtime broadcasts carry an empty payload (payload: {}); the envelope still routes the room, topic, event kind, actor and timestamp, and every subscriber re-fetches through the authenticated API rather than trusting anything pushed to it. You get a referee between your agents without shipping the codebase itself to a third party; the security page lists every field.

Which fix should you actually use?

If your tasks are truly separate, you may not need a coordination layer at all. One agent, or two agents on provably disjoint directories you're happy merging by hand: use worktrees, or just take turns, and skip everything else. Adding coordination there is pure overhead, and I'll say so plainly rather than sell you something you don't need.

Reach for advisory locks when the honest answer to "are these tasks disjoint?" is "mostly, I think", when agents share one working tree, task boundaries blur, more than two agents run at once, or several people each bring their own agent to one repo. That's the regime where "isolate and merge later" quietly turns into "untangle it by hand every afternoon," and it's the regime I built Befall for after living the twenty-minute version of it. Befall is free for 1 room and 2 concurrent agents, so the experiment costs nothing; if it earns its place, founding access is $15/mo (list $29). The setup guide takes about two minutes.

Keep reading