Architecture

Why our agents run on real git branches

fan out seam
fan out, build in parallel, reconnect at the seam

The fastest way to corrupt a project is to let two agents edit it at the same time. We learned this the way everyone does — by watching it happen — and then we fixed it with the most boring, correct tool available: git.

The failure: last-writer-wins

Run several AI workers in parallel against one shared set of files and you get a race. Worker A reads orders.sql, Worker B reads the same file, both write back, and the last write silently wins. No error. No conflict. Just a file that quietly lost half its changes — and a map that no longer matches the code. The worst bugs are the ones nobody is told about.

The naïve fix is to serialize everything: one worker at a time. But then you've thrown away the entire point of an AI team. We wanted real parallelism and real safety. That's exactly the problem version control solved decades ago.

The model: one branch per thread

In Doric, every line of parallel work — we call it an R&D thread — is a real git branch, forked from the same pinned base commit. The pin matters: every thread starts from a known, identical state, so we can reason precisely about what each one changed.

thread/payments    fork → base@a91f2
thread/reporting   fork → base@a91f2
thread/onboarding  fork → base@a91f2

Each thread does its work in isolation. When it finishes, it doesn't write to the project directly — it merges.

The merge queue

Only one thread merges into the base at a time. We serialize the merges, not the work. The work all happens in parallel; the integration happens in a disciplined line.

The key move: a thread always re-merges against the current base, not the base it forked from. So if thread/payments lands first, thread/reporting re-merges on top of payments' result and actually sees those changes. There's no stale-base clobber.

merge thread/payments → base
  3-way merge … clean       ✔ auto-merged

merge thread/reporting → base
  re-merge on new base …
  conflict: schema/orders.sql   ✗
  → escalate to human. nothing clobbered.

A clean three-way merge applies automatically. A conflict is never resolved by guessing — it's surfaced to you, loudly, with the conflicting region in hand. The rule is simple: never merge silently over a conflict. A held conflict is a feature, not a failure. It's the system refusing to corrupt your project.

Two rules do the heavy lifting: R1 — always fork from a pinned base. R2 — never auto-resolve a conflict; escalate instead. Together they convert silent corruption into a visible decision.

The hard part: git with no git

Here's where it got interesting. Doric runs serverless. There's no long-lived machine with a disk, no git binary to shell out to, and the project files live in cloud object storage, not a local working tree. So "just use git" isn't a one-liner.

We run isomorphic-git — a pure-JavaScript git implementation — against a custom storage adapter that treats the cloud bucket as the filesystem. The repository, the objects, the refs: all of it lives in object storage and is operated on in-process. No binary, no disk.

For the lock, we don't need a heavyweight coordinator. The database gives us a compare-and-swap primitive: claim the merge slot only if the current value is what we expect. If two threads race for the slot, exactly one wins and the other waits. The merge queue is just CAS plus patience.

And one more guard: the scope claim

Even with clean merges, we'd rather avoid conflicts than resolve them. So each thread declares the files it intends to write, and overlapping claims are refused at runtime. Two threads can't both hold orders.sql. It's a coarse, cheap lock that keeps most threads from ever colliding in the first place — and the merge machinery is the backstop for the cases that slip through.

Why this matters to you

You never see any of this. What you see is that you can ask for three things at once and get three correct results — or an honest "these two conflict, which do you want?" You never get the fourth outcome, the bad one: a project that looks fine and is quietly broken.

Boring infrastructure, done right, is what makes the magic on top trustworthy. Real branches. Real merges. No silent clobber.


Next: The map never lies: coherence as a projection →

Parallel work, zero clobber.

Start building free