| name | automerge-crdt |
| description | Automerge CRDT for Git-like branching, independent editing, and automatic merge of agent state without a central server. Document fork/merge, change history, and conflict-free concurrent writes. Sources: automerge/automerge (MIT). |
/automerge-crdt
When to Use
- Agents independently modify a shared document offline and merge later (Git-like workflow)
- Config or state that multiple agents can modify simultaneously with automatic conflict resolution
- History/audit: inspect every change ever made to a document, who made it, when
- Rollback: revert a document to any prior state via change log
Do NOT use for
- Real-time sync (Yjs [[yjs-crdt-sync]] is lower-latency for live collaborative editing)
- Large binary blobs (Automerge excels at structured data, not raw bytes)
Create and modify a document
import * as A from '@automerge/automerge'
let doc = A.from({
agentConfig: {
tier: 'fast',
maxTokens: 2000,
rules: [],
},
})
doc = A.change(doc, 'upgrade tier', d => {
d.agentConfig.tier = 'power'
d.agentConfig.maxTokens = 8000
d.agentConfig.rules.push('token-budget-policy')
})
console.log(doc.agentConfig.tier)
Fork and merge (concurrent changes)
let agentA = A.clone(doc)
let agentB = A.clone(doc)
agentA = A.change(agentA, 'agent-A: set tier', d => {
d.agentConfig.tier = 'power'
})
agentB = A.change(agentB, 'agent-B: add rule', d => {
d.agentConfig.rules.push('rate-limit-gate')
})
const merged = A.merge(A.clone(agentA), agentB)
console.log(merged.agentConfig.tier)
console.log(merged.agentConfig.rules)
Sync protocol (incremental updates)
const [syncState, syncMessage] = A.generateSyncMessage(doc, A.initSyncState())
let peerDoc = A.receiveSyncMessage(peerDoc, peerSyncState, syncMessage)
const saved = A.save(doc)
const loaded = A.load(saved)
Inspect history
const history = A.getHistory(doc)
history.forEach(({ change, snapshot }) => {
console.log(`[automerge] ${change.message} at ${new Date(change.timestamp * 1000).toISOString()}`)
})
const changes = A.getChanges(docBefore, docAfter)
console.log('[automerge] changes since fork:', changes.length)
Anti-Fake-Pass Checklist
❌ Mutating doc directly outside A.change() → mutation silently lost; Automerge docs are frozen
❌ A.merge() on docs with no common history → no error but changes may not reconcile as expected
❌ Comparing doc values with === after merge → same logical value, different object reference
❌ Not saving doc after changes → in-memory only; process restart loses all history
❌ Using A.change() for large binary payloads → each byte tracked as a CRDT op; very slow
❌ timestamp in change relies on system clock → use logical clocks if clock skew is a concern