Matrix logo

Snapshot & Proofs

cortex/snapshot manages the cryptographic commitment layer: a journal MMR (Merkle Mountain Range) over every write, per-namespace SMTs (Sparse Merkle Trees) over canonical memor...

cortex/snapshot manages the cryptographic commitment layer: a journal MMR (Merkle Mountain Range) over every write, per-namespace SMTs (Sparse Merkle Trees) over canonical memory and edge records, and SnapshotManifest values that seal a point-in-time OverallRoot. cortex.Proof builds multi-proofs for sub-agent scope shipping.

Source files: cortex/snapshot/snapshot.go, cortex/snapshot/mmr.go, cortex/snapshot/smt.go, cortex/snapshot/multiproof.go.


Design decisions

Two anchored namespaces: memories and edges. The SMT covers the canonical bytes of m/<id> (MemoryHead) and e/from/<src>/<t>/<dst> (EdgeRecord). Tombstones fold into the parent canonical bytes — a tombstoned Head carries Tombstoned set; the SMT value-hash changes. Salience, forms, and embedding metadata are NOT anchored (derived state).

Cortex never signs. The SignedBy field in SnapshotManifest is populated by the agent runtime or tools/attest layer before chain anchoring. Cortex holds no key material (D4).

Pull-driven snapshots. cortex.Snapshot(reason) is called explicitly by the skill compiler, tools/attest, or a periodic snapshotter. There is no auto-snapshot. The reason is recorded in the manifest for ops visibility but does NOT feed OverallRoot.

MMR hook is always running. cortex.New installs a JournalHook on the store. Every AppendJournal call — Write, Update, Tombstone, AddEdge, Embed, Compact, Attest, everything — atomically appends an MMR leaf in the same Pebble batch.


OverallRoot

root, err := c.OverallRoot()  // [32]byte

OverallRoot is a single 32-byte hash that commits to the entire cortex state:

OverallRoot = sha256(
    journal_root   ||    // sha256 over all MMR peaks
    memories_root  ||    // SMT root over m/<id> canonical bytes
    edges_root           // SMT root over e/from/* canonical bytes
)

This is the cortex_snapshot_hash used in the D11 compiler seed:

D11 seed = sha256(intent.id || actor || OverallRoot || mtx_digest || model_digest)

Snapshot

manifest, err := c.Snapshot("pre-compile")

Persists a SnapshotManifest at snap/<seq> and returns it. The manifest captures:

type Manifest struct {
    SeqAtSnapshot uint64
    CreatedAt     time.Time
    Trigger       string      // "pre-compile", "post-attest", etc. — NOT in OverallRoot
    Actor         string
    SignedBy      string      // populated by agent runtime before chain anchor
    JournalRoot   [32]byte
    StateRoots    map[string][32]byte  // {"memories": root, "edges": root}
    OverallRoot   [32]byte
    // sanity counters (not in OverallRoot):
    MemoryCount   uint64
    EdgeCount     uint64
    TombstonedCount uint64
}

Journal MMR

The journal MMR is an append-only Merkle accumulator over every journal entry's leaf hash. Peaks are persisted under accum/mmr/.

leaf_hash = sha256("matrix.cortex.journal.v1" || canonical_CBOR_entry)

Each AppendJournal call (inside a WriteBatch) invokes the installed MMRHook, which stages the leaf into the accumulator in the same atomic Pebble batch. The journal_root component of OverallRoot is derived from the current MMR peak set.


Per-namespace SMTs

Two sparse Merkle trees track canonical state:

memories SMT: keyed by sha256(m/<id:16>) → value is sha256(canonical_Head_CBOR). Updated on every Write, Update, Tombstone, UpdateHead, and embedder KindEmbed (the embedder rewrites m/<id> with EmbeddingRef set).

edges SMT: keyed by sha256(src || edgeTypeByte || dst) → value is sha256(canonical_EdgeRecord_CBOR). Updated on every AddEdge and RemoveEdge.

SMT node cache lives under idx/smt/, which is in the derived (droppable) namespace. Rebuild re-derives the SMTs from the canonical m/ and e/from/ keys.


Multi-proofs for sub-agent scopes

// 1. Take a snapshot (fixes the root the proof verifies against)
manifest, _ := c.Snapshot("for-scope")

// 2. Build a multi-proof for the URIs the sub-agent needs
proof, err := c.Proof([]memory.URI{uri1, uri2}, manifest)

// 3. Include the proof in the sub-agent's CortexScope
scope := &scope.Scope{
    SnapshotHash: manifest.OverallRoot,
    Proofs:       proof,
    // ... other fields
}

Proof returns a snapshot.MultiProof — a compact proof bundle that lets the sub-agent verify its included keys against manifest.OverallRoot without trusting the API.

If the memories SMT root has drifted since manifest was taken (i.e. new writes happened), Proof returns ErrManifestRootMismatch. Re-Snapshot before re-Proof.

MultiProof structure

type MultiProof struct {
    Root   [32]byte
    Proofs []SingleProof   // one per requested key
}

type SingleProof struct {
    KeyHash  [32]byte      // sha256(memory ULID bytes)
    Leaf     []byte        // canonical Head CBOR (nil = non-membership proof)
    Siblings [][]byte      // sibling nodes along the SMT path
}

func (mp *MultiProof) VerifyAgainstManifest(m *Manifest) error

Finding a snapshot by root

manifest, err := c.snap.FindSnapshotByRoot(hash)
// err == snapshot.ErrSnapshotNotFound if no manifest has that OverallRoot

Used by the scope verifier to resolve Scope.SnapshotHash against existing manifests. Returns the manifiest whose OverallRoot matches hash.


CurrentRoots

journalRoot, stateRoots, overallRoot, err := c.snap.CurrentRoots()

Returns the live roots without persisting a manifest. Used internally by OverallRoot() and the rebuild verifier.


Modifying snapshots

What to changeWhere
Add an anchored namespacesnapshot/smt.go — new SMT; snapshot/snapshot.go — add to StateRoots; replay/rebuild.go — re-derive in rebuild
Change MMR hash domain prefixjournal/journal.goLeafDomain — invalidates all existing journals
Add fields to SnapshotManifestsnapshot/snapshot.go — bump schema version; add to CBOR key map
Change which keys are derived vs canonicalreplay/drop.goderivedPrefixes; document whether the new key participates in OverallRoot