Skip to content
automerge-lens

Your CRDT converged. Do you know why?

CRDTs guarantee your data converges, not that you can see why it converged to what it did. Today the only way to know a conflict happened is manually calling getConflicts() at the exact path you suspect -- nothing walks a whole document for you.

automerge-lens answers one question: which value won this conflict, who wrote it, and did the merge actually converge?

$ npm install automerge-lens

Every candidate value, every author, one call

explainConflicts recursively walks the entire document -- not just one path you already suspect -- and for every key with a live conflict reports every candidate value, which actor wrote it, and which one Automerge currently presents.

src/explain.ts
import { explainConflicts, checkConvergence } from "automerge-lens";

const reports = explainConflicts(doc);
console.log(reports[0].winner, reports[0].candidates);

const result = checkConvergence(changes, { orderings: 50 });
if (!result.converged) throw new Error("non-deterministic change() callback");

Three functions, plus Mermaid rendering

01

getCausalHistory

getCausalHistory(doc)

Every change in the document's full history, topologically sorted by its deps.

02

explainConflicts

explainConflicts(doc)

Walks the entire document and reports every candidate value and author for each live conflict.

03

checkConvergence

checkConvergence(changes, options)

Applies changes in many random orders and asserts they all converge to identical heads. Seeded, reproducible.

Why this exists

Local-first/CRDT tooling matured fast (Automerge, Yjs, Loro, PowerSync, ElectricSQL, Zero) but debugging lagged behind on purpose. historyToMermaid/conflictsToMermaid render output as Mermaid diagrams, pasteable straight into GitHub markdown -- an actual picture instead of a wall of hashes.

replica A: title "Draft v1"

replica B: title "Draft v2"


explainConflicts() → winner: "Draft v2" (replica B)

lost: "Draft v1" (replica A)

What automerge-lens doesn't do

  • Doesn't fix conflicts for you.
    It explains what happened; resolving it in your data model is your call.
  • Not a sync engine.
    It reads Automerge docs and changes you already have -- it doesn't transport them.
  • Doesn't modify document history.
    Purely read-only inspection and verification.

See the merge, not just trust it

Free and open source under the MIT license.

$ npm install automerge-lens