Перейти к основному содержимому

Parallel Agents at Merge Time: Intent Conflicts and the CI Wall (2026)

Продвинутый
What you'll learn
  • 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 modeWhat it looks likeWhy isolation doesn't help
Destructive vs additiveAgent A replaces or removes the thing Agent B is extendingBoth diffs touch different lines, or even different files — the merge is clean, the design is broken
Duplicate workTwo agents solve the same problem from different anglesNeither branch conflicts; you pay twice and then pay again to reconcile
Contract driftOne agent changes an API, schema or config; another codes against the old shapeIt 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.

What you'll learn
  • 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​

RuleFires whenSeverity
FM-C001 Destructive vs additiveOne side non-preserving, the other preserving, on overlapping scopesHIGH when both operations were explicitly declared; MEDIUM when inferred
FM-C002 Divergent rewriteBoth sides non-preserving on the same scopeHIGH asserted / MEDIUM surfaced — asks the agents to pick one target design first
FM-C003 Shared contractBoth sides preserving on an overlapping scopeMEDIUM, never asserted — a coordination note; the changes may well be compatible
FM-C004 Duplicate workSummary similarity — tokenised, CamelCase split, stopwords dropped — with Jaccard ≥ 0.62, or matching operations plus overlapping scopes above 0.42MEDIUM, never asserted
FM-C005 Overlapping claimAn active claim already exists on the same canonical scopeMEDIUM 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​

Guided walkthrough1 of 3
  1. 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.

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.

Watch out
  • 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 workBeforeAfter
Change-detection, slowest run138 s37 s
Change-detection, median26 s8 s
Checkout on the slowest gate94 s20 s
Gate jobs with no checkout at all27 s7 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.

What you'll learn
  • 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 componentBeforeAfter
Per-shard setup110–140 s67–73 s (−44%)
pnpm install44–73 s16–18 s
Database setup (snapshots)12 s per container1–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.

ChangeMeasured effect
GitHub-hosted runners → third-party runnersJobs 34% faster on average; tsc workloads −52%
tsc → tsgoWeekly median of the TypeScript check −73%
Type-aware custom lint rules → AST-only static analysisAPI lint −68%, full-repository lint −55% (plus further savings from Oxlint)
Vitest opt-in project with isolate: falseShard 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​

Guided walkthrough1 of 6
  1. 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.

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​

Нажмите Enter или пробел, чтобы перевернуть карточку. Используйте стрелки влево и вправо для перехода между карточками.Показан термин.
1 / 8

Check yourself

0/7
  1. Two agents work in separate worktrees. Agent A replaces PaymentService with a Stripe-specific class; Agent B adds PayPal support to the original abstraction. What does Git do at merge?
  2. In Foremerge's model, which pair of operations on the same scope raises the highest-severity finding?
  3. Why are claims advisory leases rather than exclusive locks?
  4. Why is there deliberately no LLM in the conflict-detection path?
  5. Linear cut median PR wait from over 6 minutes to just over 5. What would the wait have been without those optimisations, on today's suite?
  6. Which change saved roughly 87,000 runner-minutes a month — 11.8% of total CI usage?
  7. Why couldn't Linear simply double their shard count from four to eight at the start?
Key takeaways
  • 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​

Next​