Parallel Agents at Merge Time: Intent Conflicts and the CI Wall (2026)
- Name the three failure modes that survive worktree isolation — and why a clean git merge is not evidence that two agent plans are compatible
- Read a coordination protocol's actual rules: semantic scopes, preserving vs non-preserving operations, and the five conflict rules Foremerge ships
- Understand why the detection path is deliberately deterministic with no model in it, and why claims are advisory leases instead of locks
- Find the real critical path in your CI — the short gating jobs, not the long test shards — using Linear's measured before/after numbers
- Know the sharding tax: why doubling shards does not halve wall time, and what has to get cheap first
On September 21–22, 2026, two stories hit the Hacker News front page within a day of each other. One was an engineering post from Linear titled "AI coding has made CI a bottleneck, so we reworked ours to keep up." The other was a Show HN for Foremerge, a tool whose pitch is "catch intent conflicts before code conflicts."
They are describing the same thing from opposite ends. Agents made producing a diff nearly free. Everything downstream of the diff — proving it is correct, proving it is compatible with the four other diffs your other agents are writing right now — still costs what it always did. So that is where the queue forms.
AILmanac already covers the human half of this in The Verification Bottleneck, and file-level isolation in Git Worktrees. This page is the machinery in between: what breaks when several agents work one repo at once, and what to actually do about it.
Part 1 — Git compares diffs. It cannot compare plans.
A worktree gives each session its own directory and its own branch. That solves exactly one problem: two processes writing the same file at the same time. It does nothing about the more expensive failure, which is two plans that cannot both be true.
The canonical example from the Foremerge author: one session replaced PaymentService with a Stripe-specific implementation, while another session added PayPal support on top of the original abstraction. Git merged both branches cleanly. The second change now depended on an extension point the first one had deleted.
Nothing in the merge machinery could have caught that, because nothing in the merge machinery knows what either agent was trying to do.
| Failure mode | What it looks like | Why isolation doesn't help |
|---|---|---|
| Destructive vs additive | Agent A replaces or removes the thing Agent B is extending | Both diffs touch different lines, or even different files — the merge is clean, the design is broken |
| Duplicate work | Two agents solve the same problem from different angles | Neither branch conflicts; you pay twice and then pay again to reconcile |
| Contract drift | One agent changes an API, schema or config; another codes against the old shape | It compiles. It ships. It fails at runtime |
The author reports a production case where two jobs "started rearranging the same matching schema from opposite ends" and the data loss surfaced three days later in production. That is the shape of the bug class: silent at merge, expensive later.
- Worktrees isolate files. Merge queues serialize integration. Neither layer has any representation of intent, so neither can detect a conflict that exists only between two plans.
Part 2 — What a coordination layer actually does
Foremerge is the concrete instance worth studying, not because you must adopt it, but because its design decisions are the ones any team hits when it tries to solve this in-house. Apache-2.0, written in Rust, repo opened on August 21, 2026, at v0.4.3 as of September 18 and 491 stars on September 22.
The idea: agents declare what they are about to do before they do it, in a machine-comparable form. Two plans that cannot both be true then collide in a queryable store instead of in your merge.
Semantic scopes, not file paths
A scope is a small structured object — a kind, a key, and an operation — rather than a path:
{ "kind": "symbol", "key": "PaymentService", "operation": "replace" }
Recognised kinds: symbol, api, schema, config, infra, test, migration, env, file, component, contract, domain. Both kind and key are lowercased for canonical comparison.
The load-bearing distinction is in the operation, and it is the part most people get wrong when they sketch this themselves:
- Preserving —
add,extend,modify. Whatever else depends on this thing keeps working. - Non-preserving —
replace,remove,rename,migrate. It does not.
That single binary is what turns "two agents touched PaymentService" (useless, happens constantly) into "one agent is deleting the extension point the other is building on" (actionable).
The five rules, verbatim in behaviour
| Rule | Fires when | Severity |
|---|---|---|
| FM-C001 Destructive vs additive | One side non-preserving, the other preserving, on overlapping scopes | HIGH when both operations were explicitly declared; MEDIUM when inferred |
| FM-C002 Divergent rewrite | Both sides non-preserving on the same scope | HIGH asserted / MEDIUM surfaced — asks the agents to pick one target design first |
| FM-C003 Shared contract | Both sides preserving on an overlapping scope | MEDIUM, never asserted — a coordination note; the changes may well be compatible |
| FM-C004 Duplicate work | Summary similarity — tokenised, CamelCase split, stopwords dropped — with Jaccard ≥ 0.62, or matching operations plus overlapping scopes above 0.42 | MEDIUM, never asserted |
| FM-C005 Overlapping claim | An active claim already exists on the same canonical scope | MEDIUM soft warning — the new claim is still created |
Two details there are worth stealing even if you never install the tool. First, only exact canonical scope matches can assert a finding; anything inferred or loosely matched is downgraded to MEDIUM and merely surfaced. Second, overriding a HIGH finding requires a non-empty written justification — the escape hatch exists, but it leaves a record.
Three deliberate refusals
- A claim carries a lease duration in seconds and never becomes exclusive ownership. The reasoning is operational: one crashed agent holding a hard lock stalls the entire fleet. Abandoned work expires on its own. The threat model is stated plainly as fallible agents, not adversarial ones.
- Conflict detection is deterministic and heuristic — same inputs, same answer, every run. The author's argument: a judge that changes its mind between runs destroys exactly the trust the layer exists to provide. It also means you can unit-test your conflict rules, which you cannot do with an LLM referee.
- Merge queues are explicitly out of scope — the Git host owns that. This is a pre-code layer, and it does not replace code review, CI, or architecture governance.
Where the state lives — the elegant bit
State is a single SQLite file in WAL mode at .git/foremerge/state.sqlite3. No server, no daemon, no infrastructure. And because every worktree of a repo already shares the common Git directory, shared coordination state across worktrees comes free — the thing that made isolation possible is the same thing that makes coordination possible.
Wire it into a fleet of Claude Code sessions
# install + initialise coordination in the repo curl -fsSL https://foremerge.com/install.sh | sh foremerge init foremerge setup all # wires the agent clients (Claude Code, Codex, Cursor) over MCP # what an agent does before it writes a line of code foremerge intent publish foremerge work claim foremerge changeset accept
The compliance problem nobody can engineer away
The protocol only works if agents actually publish intent. With MCP in the loop, the author argues compliance is strong because declaring intent is just another tool call in the agent's loop — same mechanism as any other MCP server. Foremerge exposes 18 lifecycle tools that way, including publish_intent, publish_changeset and run_verification, and installs native skills during setup.
Without MCP, compliance is whatever your system prompt can persuade the model to do — which is to say, unreliable at exactly the moment the fleet gets busy.
- No published benchmarks yet, validation commands are not sandboxed, and the project is pre-1.0 and three weeks old at the time of writing. Treat the protocol as the lesson and the binary as an experiment.
- A coordination layer adds a step to every agent's loop. If your fleet is two sessions, the overhead is not worth it — worktrees plus a short-lived branch policy still win.
Part 3 — The CI wall, with the numbers
Now the other end. Linear's engineering team published the arithmetic of what happens when agents are productive: the test suite nearly quadrupled since the start of the year, growing at roughly 2,000 tests a week.
Their honest headline: after all the work below, median pull-request wait went from more than 6 minutes to just over 5. Without the optimisations, the same suite would now make developers wait roughly 11 minutes. That framing is the real lesson — most of the effort bought standing still against a suite that doubles on you.
The critical path is the short jobs
The intuition says optimise the long test shards. The measurements say otherwise. Every run begins with gating jobs that check which paths a PR touched and whether those tests already passed for the same inputs. None of the eight API test shards can start until those finish — so a handful of seconds on a tiny job costs every downstream job the same seconds.
| Gate work | Before | After |
|---|---|---|
| Change-detection, slowest run | 138 s | 37 s |
| Change-detection, median | 26 s | 8 s |
| Checkout on the slowest gate | 94 s | 20 s |
| Gate jobs with no checkout at all | 27 s | 7 s |
| Merge-path saving per API pull request | — | 42 s |
Two specific tricks: a sparse, blobless checkout with limited history was enough for change detection (another ~11 s), and actions/checkout was replaced with a composite action that retries with backoff and sets GIT_HTTP_LOW_SPEED_LIMIT / GIT_HTTP_LOW_SPEED_TIME so a stalled connection aborts after about 30 seconds instead of hanging the run.
Then the cheapest win on the board: seven independent checks were each booting a runner, checking out the repo and installing dependencies to do a few seconds of real work. Batching them saved roughly 87,000 runner-minutes per month — 11.8% of total CI usage.
- Optimising the slowest job shortens the tail. Optimising the gating jobs shortens everyone's wait. Measure the critical path before you touch the test suite.
Setup overhead is what decides how far you can shard
Doubling shards does not halve wall time, because each shard pays setup again. Linear could only move from four shards to eight after per-shard setup got cheap:
| Setup component | Before | After |
|---|---|---|
| Per-shard setup | 110–140 s | 67–73 s (−44%) |
pnpm install | 44–73 s | 16–18 s |
| Database setup (snapshots) | 12 s per container | 1–2 s per container |
The payoff: at four shards, setup consumed 8.3 minutes in total. After the cuts they could run eight shards for 7.5 minutes of total setup — more parallelism for less aggregate overhead. The critical job came out about 19% faster and 19% cheaper, with the slowest shard going from 5.25 to 4.33 minutes and total API-shard runner time from 32.8 to 22 minutes per run.
Swap the tool before you rewrite the rules
The largest single wins were not clever — they were replacing a slow implementation with a fast one that does the same job.
| Change | Measured effect |
|---|---|
| GitHub-hosted runners → third-party runners | Jobs 34% faster on average; tsc workloads −52% |
tsc → tsgo | Weekly median of the TypeScript check −73% |
| Type-aware custom lint rules → AST-only static analysis | API lint −68%, full-repository lint −55% (plus further savings from Oxlint) |
Vitest opt-in project with isolate: false | Shard time 300–379 s → ~195 s, worth about 17% of monthly CI spend |
That last one is a real trade, not a free lunch: turning off isolation lets safe test files share a module registry inside each worker. It is opt-in per project precisely because a test that mutates module state will now poison its neighbours. Faster tests, weaker guarantees — decide deliberately.
The counterpoint from the thread
The Hacker News discussion did not let the premise pass unchallenged, and the objection is worth carrying: an agent adding 2,000 tests a week is not obviously adding 2,000 tests' worth of signal. Multiple commenters described agents writing large volumes of low-value tests in inefficient ways, which inflates CI cost forever and makes future changes harder — every one of those tests is a thing a later refactor must satisfy or delete.
Before you spend a quarter making CI 19% faster, it is worth asking whether a slice of the suite should exist at all. A test that never fails for a real reason is pure carrying cost.
What to do this week
- Pull the median time from PR opened to all-checks-green over the last 30 days. Then split it: how much is gating/setup before any real work starts, versus actual test execution? Most teams have never looked and are surprised by the ratio.
- Each one pays a full runner start, checkout and dependency install. Batch them into a single job. This is usually the largest cost saving available and it takes an afternoon.
- Cache or snapshot the expensive parts — dependency install, database creation. Only then increase shard count, and re-measure: if aggregate setup grows faster than execution shrinks, you have gone one step too far.
- Faster type-checkers, AST-only linters, faster runners. These change no semantics and no rules, so they cost almost nothing in review and are trivially revertible.
- At two parallel agents: worktrees plus short-lived branches. At five or more on one codebase: require a declared plan (scope + operation) before code, whether that is a protocol like Foremerge, a shared task file, or a lead agent that owns the design. Ad-hoc does not survive the transition.
- Give your agents an explicit instruction in CLAUDE.md or AGENTS.md about when NOT to write a test. Otherwise CI cost grows linearly with agent output forever.
Audit your own critical path with Claude Code
Read our CI configuration under .github/workflows (or the CI config in this repo). Produce a table of every job with: does it block other jobs, its typical duration, and whether it starts a runner + checkout + dependency install to do less than 30 seconds of real work. Then answer three things: 1. Which jobs are on the critical path before any test can start? 2. Which short jobs could be batched into one, and what would that save? 3. Where does the same expensive setup step (dependency install, DB creation, checkout) get repeated across jobs that could share a cache or a snapshot? Do not change any files. Output the table and the three answers only.
Terms worth keeping
Check yourself
0/7- Worktrees isolate files; they cannot detect two plans that contradict each other. The three survivors of isolation are destructive-vs-additive collisions, duplicate work, and contract drift.
- A coordination layer works by making agents declare a scope — kind, key, operation — before writing code, and the preserving vs non-preserving split on that operation is what makes detection actionable instead of noisy.
- Keep the detection path deterministic and the claims advisory: a non-reproducible judge destroys trust, and a hard lock turns one crashed agent into a stalled fleet.
- Your CI critical path is probably short gating jobs, not long test shards — Linear's median change-detection gate went 26 s to 8 s, and batching seven tiny checks saved 11.8% of total CI usage.
- Sharding is taxed by setup: cut per-shard setup first, then add shards, then re-measure.
- Tool swaps (tsgo −73% on the tsc check, AST-only lint −68%, third-party runners −34%) change no semantics and are the cheapest wins available.
- None of this outruns an agent fleet that generates tests without a ceiling — cap test generation in CLAUDE.md or AGENTS.md before you optimise the suite that runs them.
Sources & further reading
- AI coding has made CI a bottleneck, so we reworked ours to keep up — Mufeez Amjad, Linear, September 21, 2026. Every CI figure on this page comes from here.
- Hacker News discussion of the Linear post — including the test-volume counterpoint.
- naw103/foremerge — Apache-2.0, Rust. Protocol objects, CLI and MCP integration.
- foremerge/docs/protocol.md — scope kinds, preserving vs non-preserving operations, lease semantics, object lifecycle.
- foremerge/docs/conflict-detection.md — the FM-C001 to FM-C005 rules and their severities.
- Parallel coding agents without the carnage and 31 hard questions about coordinating parallel coding agents — the author's failure-mode write-ups.
- Show HN: Foremerge — September 22, 2026.
- Git worktree documentation — the isolation layer underneath all of this.
Next
- Git Worktrees & Parallel Workstreams — the file-isolation layer this page sits on top of
- Subagent Fleet Limits — how many parallel agents you can actually run before coordination cost dominates
- The Verification Bottleneck — the human half of the same problem: reviewing what the fleet produced
- CI/CD for Agent-Written Code — the merge-queue arithmetic and the gate that stops an agent grading its own homework