Cortex: Developer Reference
Cortex is Matrix's per-actor persistent memory store, a Pebble-backed KV database with a typed taxonomy, salience-ranked queries, async embeddings, Merkle snapshots, and a full replay invariant.
Cortex is Matrix's per-actor persistent memory store: a Pebble-backed key-value database with a typed memory taxonomy, a salience-ranked query engine, an async embedding pipeline, a Merkle-authenticated snapshot system, and a full replay invariant. Every durable thing an agent knows, facts, preferences, goals, constraints, past events, procedural patterns, lives here.
This documentation is written for people working on cortex itself, extending the memory types, tuning the salience formula, adding index layers, or understanding how the replay and snapshot machinery works.
Contents
| Document | What it covers |
|---|---|
| Memory Taxonomy | The 9 typed memory kinds, Head, Version, Forms, Tombstone |
| Store & Journal | Per-actor Pebble DB, key encoding, atomic write batches, journal |
| Write API | Write, Update, Tombstone, UpdateHead mutations and their journal footprint |
| Find Query | The typed query engine, predicates, planner, ordering, graph traversal |
| Context Bundle | The three-tier cold-start composer, Pinned, Frame-relevant, Outcomes |
| Embedder & Vector | Async embedding worker, pure-Go HNSW, Find Near / Find NearURI |
| Edges & Graph | Typed edges, AddEdge, RemoveEdge, bounded BFS |
| Snapshot & Proofs | Journal MMR, per-namespace SMTs, OverallRoot, multi-proofs |
| Salience | The 5-factor formula, cold weights, EMA per-actor weight learning |
| Attest & Compact | Intent attestation, salience feedback, budget-aware compaction |
| Scope | Sub-agent CortexScope, Merkle-authenticated read/write gating |
| Replay | Drop-and-rebuild, the derivability invariant and Cortex.Rebuild |
Repository layout
cortex/
├── go.mod
├── cortex.go # top-level facade: Write / Update / Tombstone / Find / Context / Snapshot
├── attest.go # Attest, intent-outcome salience feedback + EMA weight update
├── compact.go # Compact, budget-aware context compaction + checkpoint records
├── context.go # Context, three-tier cold-start bundle composer
├── edges.go # AddEdge / RemoveEdge / GetEdge / IterEdgesOut / IterEdgesIn
├── embedder.go # StartEmbedder / StopEmbedder / DrainEmbedder + HNSW worker
├── goal_state.go # GoalRuntimeState sidecar (ambient scheduler bookkeeping)
├── ratelimit.go # Phase 14 token-bucket DoS guards (scope violations + attests)
├── rebuild.go # Cortex.Rebuild facade, delegates to replay.Rebuild
├── scope_enforce.go # VerifyScope / enforceRead / enforceWrite / logScopeViolation
├── update_head.go # UpdateHead, Head-only mutations without a Data version bump
├── keys/
│ └── keys.go # all Pebble key constructors + namespace prefixes
├── journal/
│ └── journal.go # Entry, Kind, payload types, canonical CBOR, leaf hash
├── memory/
│ ├── types.go # Type, Visibility, Head, Version, Forms, Tombstone, SourceKind
│ ├── data.go # IdentityData, FactData, …, PatternData (9 schemas)
│ ├── codec.go # canonical CBOR encode/decode + HashVersion
│ ├── validate.go # write-time schema validation
│ ├── verb.go # Verb (10 D7 verbs), ObjKind, FrameRef
│ └── edge.go # EdgeType, EdgeRecord
├── store/
│ ├── store.go # Open, Get, PrefixIter, JournalHook, NextSeq
│ └── writebatch.go # BeginWrite, AppendJournal (multi-entry), Commit / Abort
├── salience/
│ └── salience.go # Score, ColdScore, ColdScoreWith, Weights, EMA helpers
├── forms/
│ ├── forms.go # Render (short + medium), RenderFull (on-demand)
│ └── truncate.go # TruncateToTokens (UTF-8-safe, bytes/4 heuristic)
├── query/
│ ├── predicate.go # Predicate AST: Eq Ne Gt Gte Lt Lte In HasTag Matches And Or Not
│ ├── eval.go # field resolver + scalar comparator
│ ├── find.go # Run: planner, candidate scan, predicate eval, sort, render
│ └── graph.go # BFS traversal for Query.From / Query.Follow
├── embed/
│ ├── embed.go # Embedder interface + HashEmbedder (deterministic sha256 stub)
│ └── api_embedder.go # HTTP-backed API embedder (nomic-embed-text-v1.5)
├── vector/
│ └── vector.go # NewIndex, Add, Search, Save, Load, MapStore, VectorStore
├── snapshot/
│ ├── snapshot.go # State, Snapshot(), CurrentRoots(), FindSnapshotByRoot()
│ ├── mmr.go # journal MMR append + root computation
│ ├── smt.go # per-namespace sparse Merkle tree (memories + edges)
│ └── multiproof.go # MultiProof, BuildMultiProof, VerifyAgainstManifest
├── scope/
│ ├── scope.go # Scope struct, Selector, Sign, Encode, Allows
│ ├── verify.go # Verify, KeyResolver, StaticKeyResolver
│ ├── match.go # Allows per-Head matching logic
│ └── errors.go # ErrViolation, ErrNotWritable, ErrScopeExpired, …
├── replay/
│ ├── replay.go # Rebuild, Result, Options, VerifyPreservesRoot
│ ├── rebuild.go # rebuildMemoriesIndexes, rebuildEdgesSMT, rebuildJournalMMR, rebuildSalienceFromJournal
│ └── drop.go # DropDerived, CountDerived
└── cmd/cortex-shell/ # smoke-test CLI: write/resolve/update/tombstone/find/snapshot
The one-sentence contract
Cortex is the ground truth for all durable agent memory. The context window is a cache; cortex is the disk. Every write is atomically journaled; the journal feeds a Merkle accumulator; snapshots seal the state root. Drop the derived indexes, replay the journal, roots match. That is the invariant everything else depends on.
Key locked decisions
These decisions are frozen. Do not re-litigate them without a documented protocol-level change.
| ID | Decision |
|---|---|
| D4 | Cortex holds no key material. Signing lives in the agent runtime or tools layer. |
| D11 | Compiler seed = sha256(intent.id || actor || OverallRoot || mtx_digest || model_digest). Same inputs produce same output. |
| D13 | #latest is forbidden at ParseURI time. All versions must be pinned before sign-off. |
| D17 | One Pebble DB per actor. All namespaces are key prefixes inside that DB, the only way to satisfy §11.1 batch atomicity across journal + head + version + indexes. |
| D7 | Verb vocabulary is closed at exactly 10 values: find acquire build modify deliver analyze negotiate schedule monitor delegate. ObjKind is similarly closed. Extending either requires a journaled migration. |
| §8.2 | Pinned memories carry a salience floor of 0.7. Tombstoned memories rank to zero and are filtered upstream. |
| §11.1 | Every store mutation, Write, Update, Tombstone, AddEdge, UpdateHead, Compact, Attest, commits journal + primary keys + index keys in a single atomic Pebble batch. A write without a journal entry fails with ErrBatchNoJournal. |
| Phase 10 Q7 | Sub-agent UpdateHead requires Scope.Writable=true. Default deny. |
