DEV Community

Cover image for Parallel coding agents without the carnage
Nick Woodhead
Nick Woodhead

Posted on

Parallel coding agents without the carnage

We build GPTree with several coding agents working the same repository at once: Claude Code, Codex, and Cursor, each in its own git worktree. The failure that finally made us build tooling for it was small and completely silent.

One session was told to replace PaymentService with a Stripe-specific implementation. Another was told to add PayPal support to PaymentService. Different worktrees. Different files. Zero textual conflict. Git merged both branches cleanly, and the second change now depended on an extension point the first had deleted. Nothing in the toolchain had an opinion about it at any moment.

Git compares diffs. It cannot compare plans.

Worktrees isolate files, not plans

Worktrees became the standard answer to parallel agents for a good reason: two sessions editing one checkout will overwrite each other's files and poison each other's context. Isolated checkouts fix that completely.

But three failure modes survive file isolation, because they were never about files:

  1. Destructive versus additive. One agent removes or replaces a thing another agent is building on. The example above. Merges clean, breaks the design.
  2. Duplicate work. Two agents solve the same problem from different angles because nothing assigned ownership. You pay twice and then pay again to reconcile.
  3. Contract drift. One agent changes an API, a schema, or a config contract while another codes against the old shape. Compiles, runs, disagrees at runtime.

A shared task list helps with the second one, if every agent reads it, every time. Nothing in that setup catches the first or third, because the collision is between intentions, and intentions live in prompts, not in any file a tool can watch.

Declare the work before doing it

Foremerge is the internal tool we built for this, open-sourced this week. It is a coordination protocol that sits above Git: agents declare what they are about to do, before they do it, in a form precise enough to check.

A declaration is an intent with one or more semantic scopes, each carrying an operation:

foremerge intent publish \
  --agent "$AGENT" \
  --task "modernize-payments" \
  --summary "Replace PaymentService with StripePaymentService" \
  --scope symbol:PaymentService=replace
Enter fullscreen mode Exit fullscreen mode

Scopes are not file paths. The vocabulary covers symbol, api, schema, config, migration, contract, and more, because file paths miss API, schema, configuration, and cross-language collisions entirely. The operation (replace, extend, and so on) is declared rather than parsed out of the summary, so it does not matter how the agent phrased its plan.

When a second agent declares work on the same scope, deterministic rules compare the declarations and raise a finding while both pieces of work are still plans. This is real output from 0.4.0, captured while writing this post:

{
  "kind": "destructive_vs_additive",
  "severity": "HIGH",
  "scope": { "kind": "symbol", "key": "PaymentService" },
  "explanation": "One intent will replace `PaymentService` while the other will extend it; both declare the same semantic scope.",
  "suggestion": "Coordinate on a stable `PaymentProvider` contract first, then implement StripePaymentProvider and PayPalPaymentProvider behind it and migrate callers deliberately. This is a heuristic suggestion, not an automatic design decision."
}
Enter fullscreen mode Exit fullscreen mode

The finding names the rule that fired, explains itself, and suggests a resolution. It does not block anyone. Claims in Foremerge are leased and advisory: overlap produces a warning and shared context, never a lock, because two agents can often work the same region compatibly and a lock would serialize work that did not need serializing.

The other half of the protocol is evidence. When an agent finishes, it publishes a ChangeSet, and acceptance is gated on verification that Foremerge runs itself: your named check (a build, a typecheck, a test target you registered) executed against the exact candidate fingerprint. An agent saying "tests pass" is recorded as provenance; it does not satisfy the gate. If the tree changed after validation, the attempt is non-authoritative and the gate says so.

Mechanically it is one Rust binary. The CLI, a local JSON API, and an MCP server are adapters over the same SQLite store, which lives inside your repository's git common directory, which is exactly why worktrees work well with it: linked worktrees share that directory, so every agent in the repo sees the same declarations while keeping isolated files. Local-first, no cloud, Apache-2.0.

The five-minute version
The fastest path is to let your agent set it up.

Paste this into Claude Code, Codex, or Cursor from inside the repository you want to coordinate:

Set up Foremerge in this repository so we can coordinate parallel agents.
1. Install it:      curl -fsSL https://foremerge.com/install.sh | sh
2. Initialize:      foremerge init
3. Wire this client and any others in use: foremerge setup all
4. Register the check I should be validated against, for example:
                    foremerge checks set test -- cargo test --all-targets
5. Confirm:         foremerge doctor --client all
Then read the Foremerge skill that step 3 installed for this client and follow
it from now on: publish your intent with semantic scopes before editing, claim
the scope, and check for conflicts before you start.
Enter fullscreen mode Exit fullscreen mode

The MCP server gives the agent the full lifecycle as tools: publish intent, claim scope, check conflicts, publish ChangeSets, run verification, record the commit that landed. Set it up once per repository and every agent connected to that repository shares the same awareness.

Doing it by hand instead is the install line,

foremerge init

, and the commands in the README, which walks two throwaway agents into the exact conflict above in under five minutes.

What it deliberately does not claim
This is a pre-1.0, local-first MVP, and the parts it does not do are documented as carefully as the parts it does:

Detection is deterministic and explainable, but heuristic. It can miss synonymous concepts and warn on work that was always compatible.
Claims warn. They never lock files, symbols, or agents.
Passing validation proves that the recorded command passed for the recorded fingerprint. Nothing more.
The store is per-machine SQLite. Shared multi-machine mode does not exist yet.
There is a reproducible benchmark harness in the repo, but no published coordinated-versus-uncoordinated results yet. Performance claims wait for numbers.
The full list is in docs/limitations.md. We think a coordination tool that overclaims is worse than no coordination tool, because severity is the signal an agent uses to decide what to stop for, and a false HIGH is worse than silence.

Where this goes
The protocol is the part we most want feedback on: is the scope vocabulary the right shape, where would the conflict rules warn on compatible work in your codebase, and which collisions would they miss? Issues and Discussions are open.

Repo: github.com/naw103/foremerge
Site and install: foremerge.com
Crate: cargo install foremerge

If you run parallel agents and have hit collisions worktrees could not see, we would genuinely like to hear what they looked like.

Top comments (2)

Collapse
 
reidmarlow profile image
Reid Marlow

This is the failure mode worktrees made easy to miss. File isolation fixes the stomp, then two agents can still delete and extend the same contract in clean branches.I like that Foremerge treats the scope claim as a warning with evidence instead of a lock. Locks turn into a queue the minute the repo gets busy.

Collapse
 
naw103 profile image
Nick Woodhead

Thanks Reid. The queue point is exactly why claims stayed advisory so the moment a lock exists, every compatible overlap pays the serialization cost, and busy repos are mostly compatible overlaps. Two details that made warnings workable in practice: claims are leases, so a session that dies or wanders off cannot squat on a scope forever, and an overlap warning carries the other side's intent with it, so the common outcome is both agents proceeding with awareness rather than stopping to coordinate. The gate at the end stays hard (verification against the exact candidate fingerprint), which is what lets everything before it stay soft.