Where Claude’s memories go: Cortex, traced through its source
Every Claude Code session leaves two kinds of traces in Cortex. Memories go into one database table, memories, each row with a 384-dimension vector and a heat value that the database recomputes at every read. Decisions get an identity of their own: a numbered ADR file on disk that the database only points to. This note follows both, from the hook that captures them to the recall that brings them back into context. Every statement links to the lines of the v4.22.0 release that implement it, so you can check each one instead of taking it on trust.
The retrieval figures come from one run of benchmarks/reproduce.sh --no-regression on 15 September 2026, in an ephemeral PostgreSQL container, on the code released as v4.22.0; they are retrieval scores, not answer accuracy.
Two doors, one store
Nothing enters Cortex except through one of two doors. The plugin hooks fire on their own at fixed points of a session and talk to the infrastructure layer directly3. The MCP tools (remember, recall, wiki_adr and the rest) go through the server, where only the handlers may combine the pure core with infrastructure1. The core performs no I/O: environment flags, the reranker’s model cache and the wiki filesystem reach it through seams that raise when unwired, and one function wires them all at every process entry point2.
What the hooks read and write
You only see part of the work: the “Cortex Memory Context” block at the top of a session5. Six other hooks read or write without asking. One, decision_gate, never touches the database: it refuses an edit that adds a long run of comment prose, because decision prose belongs in the wiki6.
A memory has to get past a novelty gate
Storage has a gatekeeper: it keeps what contradicts its expectations. Four novelty signals are weighted and compared with a threshold of 0.48. The gate mostly filters automatic capture: a deliberate remember, the default class, bypasses it, as do decisions, errors and an important tag9. A decision written deliberately under an agent topic, from a trusted origin, is also marked global so the whole team of agents sees it; a fetched page or an automatic capture that merely contains a decision cue is not10.
One row of the memories table
A row carries much more than its text. The most misleading column is heat: no heat column is stored. The database keeps heat_base and the time it was set, and the SQL function effective_heat() applies the decay when the row is read; protected and anchored rows skip it11.
Content and vectors
- content
- the text, hardened on input
- embedding
- vector(384), cosine index
- content_tsv
- generated full text
- tags
- JSONB: auto-captured, adr…
Scope
- domain
- project, from the git root
- directory_context
- working directory
- agent_context
- the agent_topic argument
- is_global
- visible from every project
Thermodynamics
- heat_base
- 0–1, where decay starts
- heat_base_set_at
- the decay clock
- no_decay
- turns decay off (anchors)
- surprise_score
- the gate’s novelty score
Life cycle
- store_type
- episodic by default, or semantic
- consolidation_stage
- labile when written
- access_count
- +1 on every recall
- is_protected
- decision or anchor
Provenance
- write_class
- auto · deliberate · derived · mechanical
- capture_origin
- deliberate · local_action · network · unknown
- source_attribution
- who said it
- tag prov:<grade>
- provenance grade
Supersession
- supersedes_id
- the row it replaces
- superseded_by_id
- the row replacing it
- current_memories
- view hiding replaced rows
- compressed
- original_content kept
Recall is also a write
A recall first looks for an exact identity (ADR-0042, a memory id), then fuses five signals in a single database function17. On PostgreSQL the signals are max-normalised and summed with per-intent weights; on SQLite the fusion is rank-based, w/(k + rank), without the trigram signal13. Hopfield completion, hyperdimensional similarity and spreading activation rerank the result, then a cross-encoder has the last word14. The memories that come back do not leave untouched: their heat, their counters and the graph edges between their entities change on the way15.
A decision has an identity: ADR-NNNN
The wiki page id is the only decision index. Code keeps a pointer, and recall resolves that pointer before any fuzzy search17. A decision can take three paths; each leaves its trace in a different place and comes back a different way16.
Four memories, side by side
What Claude learns in a session does not land in one place. Claude Code has its own file memory, separate from Cortex; Cortex reads it for the cognitive profile and never copies it into the store18.
| Store | Location | Written by | Read back | Decay |
|---|---|---|---|---|
| Cortex memories | PostgreSQL or SQLite | the hooks and remember | at session start, on every prompt, on recall | yes, computed at read time; protected rows exempt |
| Wiki ADR | ~/.claude/methodology/wiki/adr/ | wiki_adr | recall on an exact ADR-NNNN | no, it is a file |
| Claude Code auto-memory | ~/.claude/projects/<project>/memory/ | Claude, through file writes | every session: Claude Code loads MEMORY.md | no |
| CLAUDE.md | a “Memory Insights” section between markers | sync_instructions | every session, with CLAUDE.md | no |
Cortex · source on GitHub · Start a pilot