Your coding agents do not need better merges, they need to declare
Isolation then merge checks for collisions after the work is paid for. Claim-before-spawn checks before the process starts, so refusing costs nothing.
I argue that coding agents do not need better merges, they need to declare their write scope before they spawn. Isolation and merge checks catch collisions after tokens are already spent. Claim before spawn checks first, so a refusal costs nothing, and a checked exit catches writes nobody declared.
Opening three terminals, starting three coding sessions, and giving each one a task is now an ordinary afternoon. The tooling made it trivial. The agents are cheap, the wall time roughly halves, and the failure mode arrives so quietly that you will usually meet it a day later, in a diff, wondering who wrote that line.
The standard defence is isolation followed by reconciliation. Each agent gets its own worktree or its own branch. When they finish, a human merges, and whatever collided surfaces at merge time. That defence is not wrong, exactly. It is late. Every agent has already spent its tokens and its wall time before anybody finds out that two of them were working the same ground.
I want to argue that the control point sits in the wrong place, and that moving it earlier is both cheaper and duller than it sounds.
Two ways this actually breaks
The first failure is the silent overwrite. Two agents touch the same file. If they happened to touch different lines, git merges clean and nobody looks twice. If they touched the same lines, you get a conflict, and now somebody has to reconstruct two intents from two diffs with no record at all of what either agent was trying to do. The conflict markers tell you what changed. They tell you nothing about why, and the agent that could have told you has already exited.
The second failure is worse, because no tool anywhere is watching for it. Call it the scope escape. An agent writes somewhere nobody expected: a config file two directories up, a generated index, a sibling repository it happened to have a path to. No merge tool sees this, because nothing conflicts. The change is simply there, committed, plausible, and unreviewed by anyone who knew it should not have happened.
Both failures share one shape. The write set of each agent is unknown until the agent has finished. So every check you can build has to run late, and it has to infer intent from effect. That is a hard problem, and it is a hard problem you volunteered for.
Agents have been treated like colleagues
This is a concurrency control problem, and databases settled the shape of it decades ago. The reason it went unnoticed for so long is a framing habit.
Agents have been treated as if they were colleagues. Colleagues coordinate by talking: you mention in standup that you are in the billing module this week, I stay out of it, and if both of us forget, one of us apologises at merge. That model needs shared context, shared history, and continuous mutual awareness. It scales badly with three people and it does not scale at all with three processes that cannot remember yesterday.
Agents coordinate better when treated as transactions. Transactions do not talk. They declare what they intend to touch, a coordinator decides whether that is allowed, and the ones that would have collided never run. Nobody in a database is asked to keep the other transactions in mind.
That is the whole move: stop asking each agent to be aware of the others, and make awareness the coordinator’s job instead.
Claim before spawn
The mechanism I have been running is called claim-before-spawn, and it has three parts. Each is necessary and none of them is clever.
Declared scope. An agent’s write set is stated up front, as path globs, before the agent runs. Not inferred from its behaviour. Not discovered at merge. A claim is a small record: which session holds it, which paths, an optional narrower list of symbols, whether the claim is exclusive or shared, and a lease with an expiry that the session renews by heartbeat. Never an indefinite hold.
Refusal at claim time. A coordinator holds every live claim. An overlapping exclusive request is not granted. Because the check happens before the process starts, the losing agent never spawns. The collision costs zero worker tokens. The only thing you paid for was the planning that drafted the claim, which you needed anyway.
Checkable exit. Because scope was declared, the coordinator can compare what the agent actually wrote against what it said it would write, and record pass or fail. This is the part people underrate. A shared context cannot be checked; it is material you hoped would help. A declared scope can be checked, which is what makes it a contract rather than a wish.
The overlap rules are the reader-writer lock every systems programmer already knows, applied to path globs instead of memory addresses. Shared against shared, both granted. Shared held, exclusive wanted, wait. Exclusive held, shared wanted, reading is fine and writing is refused. Exclusive against exclusive is a collision, and something has to give.
The consequence that matters most is the one that sounds like nothing: two agents holding non-overlapping claims do not need to know about each other at all. They do not share history. They do not read each other’s progress. They do not negotiate. The coordinator already made sure their scopes do not touch, once, before either of them started.
A refusal has to carry a reason
One detail decides whether this works in practice or degenerates into a retry loop.
“Refused” here means “not granted”, never “rejected”. When two claims collide, the coordinator tells both sides who the other is, what it intends, and what phase it is in, in plain words. Not a code. The counterparty’s actual stated task.
An agent refused with no reason will retry, rephrase, retry again, and burn tokens doing it. An agent told that another session holds the billing paths because it is adding invoice retries, and is currently mid-work, can plan: narrow its own claim to a different subtree, wait for the lease to end, or hand its intent over and stop. The reason is what de-escalates. Resolution, in order of preference, is split the claims until they no longer overlap, wait, merge one intent into the other, or escalate to a human when there is no automatic answer. Splitting works most of the time, because most claims are wider than the work actually needs.
None of the primitives are new
I want to be exact about what is being claimed here, because the ideas underneath are all borrowed and most of them are older than I am.
Optimistic concurrency control gives the version-checked write. Lease-based locking gives expiry plus renewal, so nothing is ever held indefinitely by a process that died. Design by contract, from Meyer in 1986, gives preconditions and postconditions applied to a session instead of a routine. Blackboard architecture, from the Hearsay-II speech system in the 1970s, gives shared state as the coordination medium. Append-only session logs give a journal that is the only source of truth, with every view rebuildable from it.
None of that is a contribution. The contribution is the placement.
Applying these primitives at the process boundary of an AI coding agent, before the process spawns, with a refusal that carries the other side’s intent in plain words, is the part that is new. The multi-agent tools I have used put their guard at merge time, or they do not put one anywhere. Nobody was checking earlier, not because the primitives were missing, but because the field was still thinking of agents as people who would sort it out between themselves.
Boring primitives, moved one step earlier in the sequence, stop being a merge problem and start being a scheduling decision.
What this buys you
Prevention becomes free. That is the property worth keeping. In the isolate-then-reconcile model, every collision costs you two agents’ full run plus a human’s reconstruction time, and you cannot know in advance how many collisions you are buying. In the claim model, a collision costs one refused request, and the second process never starts.
The exit check is the quieter win. Once scope is declared, an undeclared write surfaces instead of passing silently. A human then decides whether the declaration was too narrow or the agent overreached. Without the check, that decision never gets made, because nobody knows it was needed.
If you are running more than one agent against one codebase today, the question to ask is not how to get better at merging. It is where your control point sits, and what it costs you every time it fires.
The full paper, including the mechanism in detail, two live trials, and the three things the mechanism could not see, is published under CC BY 4.0 at 10.5281/zenodo.22670723.
Written by Sagar Thakkar, AI systems architect specialising in large-scale data processing, cost-optimised cloud-native systems, and reliable production infrastructure. More at sagarthakkar.com.