skip to content

how to prevent merge conflicts between AI agents.

published

to prevent merge conflicts between AI coding agents like Claude Code, Codex and Cursor, stack defenses that avoid, flag or catch them: split work by file, give each agent a worktree, claim files, warn before each edit, predict conflicts with git merge-tree, merge through a queue, and test the merged result. teammates’ agents need a shared record of edits.

how parallel agents overwrite each other’s changes

two agents working at once collide in three ways, and each defense below covers some of them.

a few studies have measured how often this happens, each counting something different; how often AI coding agents cause merge conflicts puts them side by side.

how to avoid merge conflicts with multiple coding agents

the list runs from planning to after the merge. the early defenses act while an agent can still pick different work. the late ones look at real code, so they’re more certain, and what they find is rework. every tool named here is described from its own documentation or source, checked on 2026-10-16.

defenseactscatchesmissessetup
1. split by file or modulebefore work startstwo agents in one file, while the split holdsshared files, drift, breaks across filesa CODEOWNERS file and tasks written around it
2. a worktree per agentwhen an agent startstwo agents writing one file on diskone file on two branches, teammates’ machinesa flag per session, setup per checkout
3. claim before editingbefore the first writetwo plans for the same pathsagents that don’t claiman MCP server and an instruction
4. warn before each editat each editagentmash: a teammate’s change to the file, or (JS/TS, from an agent that reports the names it changed) to a symbol it imports; Clash: your other local worktreesagentmash: your own agents; Clash: teammates’ machines; both: shell commandsa hook in each agent
5. git merge-treewhile branches are in flighttextual conflicts between committed branchesuncommitted work, semantic breaksgit 2.38 and a script, or Clash
6. merge through a queueat the mergepull requests that pass alone and fail togetherwhat the checks don’t testa protection rule and merge_group, where GitHub or GitLab offers you a queue
7. build and test the resultin the queue and after the mergesemantic breaks the tests reachseams no test coversCI time

1. split the work along file and module boundaries

before any agent starts, give each agent, and each developer, a part of the repository for the task: a module, a directory, a list of files. the Claude Code docs on agent teams say it directly: “Two teammates editing the same file leads to overwrites.” their fix is this one, a different set of files for each teammate.

a CODEOWNERS file is the usual map. GitHub reads it from .github/, the repository root or docs/, and requests a review from the owners of the code a pull request changes, though not while the pull request is a draft (about code owners). that routes review and doesn’t stop an agent from editing a path someone else owns, so write the split into each task’s prompt too, since the prompt is what the agent reads.

text
# .github/CODEOWNERS
/src/models/   @alice
/src/api/      @bob

keep each agent’s task small, and merge its pull request soon. a small change has fewer lines to collide with, and a branch that merges soon has less time to drift from main while other work lands.

2. give each agent a worktree

a git worktree is a second working directory of the same repository, on its own branch, and each agent gets its own when it starts. by default git refuses to check out one branch in two worktrees, so two agents can’t end up on the same branch by accident. the agent tools make one for you:

for any other agent, make one by hand and start the agent inside it:

git worktree add ../app-alice -b alice/soft-deletes

3. claim files before editing

a claim is the one fact a shared record can hold before any edit exists: “my agent is taking src/routes/ for the next hour.” the agent makes it at the start of a task, before its first write. a second agent that asks for overlapping paths learns who holds them, and can take other work.

tools differ on what happens next. a lock refuses the second agent. an advisory claim tells it and lets it decide.

a lock held by an agent that crashed stalls everyone waiting on it, so each tool below keeps claims advisory, gives them an expiry, or both. Befall and agentmash each keep a room per repository, a record on a shared server that every teammate’s agents report to.

toolwhat an agent claimswhen two claims overlapwho shares the claims
Foremergean intent with semantic scopes, such as symbol:PaymentServiceboth succeed; colliding plans raise an advisory findingthe agents on one machine, through a store under .git
Befallpath globs, over MCP (README)refused at claim time; the agent is told who holds it and a file both claims coverteammates, in a hosted room per repository
Shepherdthe work it’s starting, with its work tool, until done or a TTL (60 minutes by default)both claims succeed; work reports the overlap as an advisory conflict (source)teammates, through a hub the team runs or Korso hosts (README)
agentmashpaths and a one-line task, with the claim_work MCP toolboth stand; the second agent is told who holds what, and to split the workteammates, in one room per repository

Claude Code’s agent teams, an experimental feature that is off by default (CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 turns it on), have claiming too, for the tasks on their shared list, with file locking so two teammates can’t take the same task. that lock covers the task list; two teammates can still edit the same source file. how Claude Code agent teams compare with agentmash goes through the rest.

in agentmash, an agent calls claim_work with the paths it expects to change. this is what dana’s agent is told when alisher’s agent already has part of them:

text
Claimed src/routes/login.ts, src/routes for "add a login endpoint" as dana@example.com
(id claim_x9…, 120 min).

OVERLAP — someone else has already claimed part of this:
- alisher@example.com has src/routes for "rename every route handler" (claimed 4 min ago)

Your claim stands, but split the work before you write anything: take the files and symbols
they have not claimed, or build on top of what they land rather than changing it. …

an agentmash claim is advisory, never a lock. on the agent’s own branch it stands until the branch merges, a week at most. on the default branch it expires on its own, after two hours by default and eight at most, and ends with the session that made it.

an agent about to edit a file a teammate claimed gets an [AgentMash: CLAIMED] note, delivered the way that agent hears the warning in defense 4. how claims work has the rest.

4. warn the agent before each edit

a hook runs before the agent’s edit tool, at the last moment the agent can still change course. it looks up what else is changing and puts what it finds into the agent’s context. it doesn’t depend on the agent remembering to ask, which is the gap claims leave.

Clash ships a Claude Code plugin that checks a file against your other local worktrees before Claude writes it. agentmash’s hook checks the repository’s room instead: if a teammate’s agent changed the same file, or changed an exported symbol the file depends on and reported the names it changed (Claude Code’s edits do; a Codex patch and Cursor’s edits don’t), the warning (agentmash calls it an advisory) goes into the agent’s context, graded by severity. this is what bob’s agent is told when alice’s agent changed the file two minutes earlier in the checkout bob is working in, while she is still at it, word for word:

text
[AgentMash: ACTIVE COLLISION] alice's agent is working in src/models/user.ts — last write 2 min ago on your branch (main), while working on 'add soft deletes to the user model' (+12/-3 lines, touching deletedAt). Their write is already in your working tree, so whatever you read from this file earlier is out of date. Re-read src/models/user.ts now and rebuild this edit against what is actually there: a stale old_string either fails to match or quietly reverts their change. Leave deletedAt named and shaped as alice left it — that is what they just changed. If your task genuinely needs those same lines, change them and say so in your reply, so the overlap is visible.

the agent is told to re-read the file and rebuild its edit. a change that isn’t in your working tree, on another branch or in a teammate’s own clone, is worded as a PARALLEL EDIT instead: there’s nothing to re-read, so the agent is asked to keep its edit additive, not to reformat or reorder, and to name any divergence in its reply.

how the warning arrives depends on the agent. in Claude Code, Codex and GitHub Copilot it’s a note the agent reads, and the edit goes ahead. Cursor, Amp, Crush, Factory Droid, Gemini CLI, goose, Kilo Code, Kiro, OpenCode, OpenHands and Qwen Code get it as a refusal of the first edit, with the advisory as the reason, and the same edit tried again goes through. the refusal comes at most once per session and file every ten minutes (in Cursor, once per conversation and file).

5. predict textual conflicts with git merge-tree

while branches are still in flight, before anyone opens a pull request, git merge-tree --write-tree can tell whether two of them conflict. it performs a merge without reading or writing the index or the working tree, and exits with status 1 when the merge has conflicts (git merge-tree). that mode arrived in git 2.38.

git merge-tree --write-tree --name-only alice/soft-deletes bob/user-email

on a small test repository where both branches changed createUser, git 2.39.3 printed the tree the merge would have written, the conflicted file and the reason, and exited 1:

text
03a19f56d98fd1753aae2c0a9bc151d775cd9a70
src/models/user.ts

Auto-merging src/models/user.ts
CONFLICT (content): Merge conflict in src/models/user.ts

to check against a teammate’s branch, run git fetch first and name it as origin/<branch>. Clash runs the same three-way merge between every pair of worktrees on your machine, read-only: clash status shows the matrix, clash watch keeps it current, and clash check <file> looks at one file.

researchers have replayed agents’ merges at scale, though against the base branch rather than a second branch in flight. in one study of AI coding agents’ pull requests that were never merged (still open, or closed unmerged), researchers at UNLV replayed 107,026 merges against each pull request’s base branch and found a textual merge conflict in 27.67% of them (AgenticFlict, Ogenrwot and Businge, AIware 2026). the other side of each conflict could be anyone’s change, a person’s or an agent’s.

6. merge through a merge queue

a pull request’s checks test it against the base branch as it was when they ran, so two pull requests can each pass against main and still conflict or fail once both are in. a merge queue tests them in the order they’ll land.

on GitHub, a pull request added to the queue is grouped on a temporary branch with the latest version of the base branch and the pull requests ahead of it. the required checks run on that group, and a pull request whose checks fail, or that conflicts with the base, is removed from the queue (managing a merge queue). GitLab’s merge trains test each merge request against the combined changes of the ones ahead of it.

7. build and test the merged result

this is the one defense that checks a semantic conflict in the code itself: two changes that merge without a textual conflict and break together. it runs in the queue, and again on main after each merge. defenses 3 and 4 can flag the risk earlier, by scope or by symbol; only a build or a test shows the break.

on GitHub Actions, a pull_request workflow runs on the pull request’s merge branch, refs/pull/<number>/merge, so it already tests your branch merged with the base, as long as the pull request has no merge conflict; with one, the workflow doesn’t run (events that trigger workflows). it doesn’t test your branch with a teammate’s pull request that hasn’t landed. the merge queue’s group does, once their pull request is ahead of yours in the queue, and the build on main after each merge is the last check.

the tests have to reach the seam. in the createUser example, if the new signature makes the old call invalid, TypeScript’s type check fails the build in src/api/handlers.ts. in a codebase without a type checker, it takes a test that calls that handler, or a static check that knows the signature.

on tasks built to trigger the problem, researchers at UIUC and Columbia had GPT-5.5 write code against real Django helpers while a scripted parallel change altered those helpers: in 97% of runs (105 of 108), the two changes each passed alone and merged without a textual conflict, then failed together (Passes Alone, Fails Together). the authors say these constructed rates don’t estimate how often it happens in practice. on 834 runs over 417 real, merged Django pull request pairs, run with a GPT-5-class model and graded after the authors corrected their procedure, one showed interference.

avoiding conflicts with teammates’ agents on other machines

most of the stack runs on one machine or at the very end. worktrees and Clash see the checkouts on your laptop. Foremerge keeps its store under the repository’s .git on one machine, and its README puts coordination between machines outside its scope.

Claude Code’s agent teams keep a team’s config under ~/.claude on the lead’s machine, one team per session. git merge-tree and a merge queue do see teammates’ work, once it’s committed and pushed, which is usually after their agent has finished.

alice’s Claude Code agent, on her laptop, is halfway through src/models/user.ts on alice/soft-deletes, and has just changed the signature of createUser. bob’s agent, on his, is about to edit the same file on bob/user-email. nothing on bob’s machine knows. the conflict shows up when the second pull request merges, or as a broken build if the two changes met in different files.

covering it takes a shared record that both agents report to while they work. Befall, Shepherd and agentmash are three tools that keep one for a team, each described here from its own docs, checked on 2026-10-16:

toolwhere the shared record liveshow an agent hears about a teammate
Befalla hosted room per repositorythrough MCP tools it calls, such as a refused claim or the room’s status; a local daemon also heartbeats each checkout’s uncommitted files, so overlaps with live claims surface for a tool that never claimed
Shepherda hub the team runs itself, or Korso hoststhrough MCP tools it calls (work, sync), with claims that last until done or a TTL
agentmasha hosted room per repositoryfrom a hook before each edit, with nothing for the agent to call; claims and MCP tools on top

agentmash’s hooks report each edit to the room as it happens, before it’s committed or pushed. so bob’s agent gets the warning from defense 4 before it edits src/models/user.ts, as a PARALLEL EDIT. while her edit is inside the 30-minute window, bob’s agent gets one again before it edits src/api/handlers.ts, since that file imports the createUser whose signature her agent changed.

past the window, the room remembers her unmerged work by person, branch and file for up to a week, until the branch merges, and matches it by file only: bob’s agent still hears of it before editing src/models/user.ts, but not before src/api/handlers.ts. while her changes are uncommitted, the advisory says they’re only on her machine, so nothing bob can fetch shows them yet. once she has committed, it says how to read her side after she pushes: git fetch origin, then git diff HEAD...origin/<branch> -- <file>. that holds for bob in Claude Code, Codex or GitHub Copilot. in Cursor he’d hear less of it: Cursor’s adapter is told only of work from the last 48 hours by default, on a branch he hasn’t worked on, in a file he hasn’t changed since, and without those two notes.

the agents don’t have to come from one vendor. npx agentmash login connects the coding agents it knows on a machine (Antigravity when asked for), so alice in Claude Code and bob in Codex report to the same room. if a teammate’s agent and yours change the same file anyway, in Claude Code, Codex and GitHub Copilot agentmash tells you once, as the agent finishes its turn, whose change each file meets, so a person can look at both before either lands and decide how the two come together.

what agentmash doesn’t do

where to start

which defenses fit depends on where the agents run: