Database schema and migrations
1. Two planes
The index plane is a projection of the git tree and can be thrown away: memhtml index rebuild reproduces it from HEAD. The state plane holds what git cannot reproduce, which is why it ships a committed sidecar file alongside the database.
Both planes grow the same way. Adding a migration means adding one .sql file to the plane’s directory: the files are read in filename order at run time, and no code changes.
2. The index plane
Where the rebuildable index’s migrations live, applied in filename order.
12 migrations, in the order they are applied:
| File | Creates |
|---|---|
0001_files.sql |
table files, index files_content_hash_active, index files_type_active, index files_workspace, index files_para, index files_updated, index files_event, index files_session, index files_ttl, index files_blob, table file_tags, index file_tags_tag, table file_entities, index file_entities_name, table file_facets, index file_facets_name, table file_citations |
0002_chunks.sql |
table chunks, index chunks_path, index chunks_hash, index chunks_hash_ord, table embeddings, index embeddings_model |
0003_fts.sql |
table files_fts, trigger files_fts_insert, trigger files_fts_delete, trigger files_fts_update |
0004_edges.sql |
table edges, index edges_src, index edges_dst, index edges_rel, index edges_derived |
0005_traces.sql |
table traces, index traces_slug, index traces_cwd, index traces_started, index traces_mtime, table traces_fts, trigger traces_fts_insert, trigger traces_fts_delete, trigger traces_fts_update, table trace_prompts, index trace_prompts_uuid, table memory_session_links, index msl_session, index msl_path |
0006_sleep.sql |
table sleep_runs, index sleep_runs_started, table sleep_phases |
0007_watermark.sql |
table index_state, table trace_watermarks |
0008_tasks.sql |
table files_next, table file_tags_snap, table file_entities_snap, table file_facets_snap, table file_citations_snap, table chunks_snap, table embeddings_snap, index files_content_hash_active, index files_type_active, index files_workspace, index files_para, index files_updated, index files_event, index files_session, index files_ttl, index files_blob, index files_task_status, table files_fts, trigger files_fts_insert, trigger files_fts_delete, trigger files_fts_update, table edges_next, index edges_src, index edges_dst, index edges_rel, index edges_derived |
0009_frame_key.sql |
index files_frame_key_active |
0010_trace_consolidations.sql |
table trace_consolidations, index trace_consolidations_run |
0011_edge_indexes.sql |
index edges_src, index edges_dst |
0012_origin_path.sql |
index files_origin |
2.1. 0001_files.sql
table files, index files_content_hash_active, index files_type_active, index files_workspace, index files_para, index files_updated, index files_event, index files_session, index files_ttl, index files_blob, table file_tags, index file_tags_tag, table file_entities, index file_entities_name, table file_facets, index file_facets_name, table file_citations
The memory corpus, one row per file in the git tree. Rebuildable: every column here is
derived from a committed file plus its blob sha, so rm index.db costs a rebuild and no data.
2.2. 0002_chunks.sql
table chunks, index chunks_path, index chunks_hash, index chunks_hash_ord, table embeddings, index embeddings_model
Chunks and their vectors. Both key on content_hash, not on path: a git mv, which is what
eviction and every rename are, reuses the vector with zero Bedrock calls, and two files whose
bodies later diverge never share one.
2.3. 0003_fts.sql
table files_fts, trigger files_fts_insert, trigger files_fts_delete, trigger files_fts_update
The lexical index: an FTS5 table over files.fts_text, plus the triggers that keep it in step.
2.4. 0004_edges.sql
table edges, index edges_src, index edges_dst, index edges_rel, index edges_derived
The graph. Authored edges come from the files’ <link rel=“memhtml-*”> elements; derived edges are
sleep-mined and live only here, because they are a re-derivable function of the corpus and the
embedder. derived is the firewall: the retention penalty counts only derived = 0, so an
uncorroborated machine suspicion can never evict a memory.
2.5. 0005_traces.sql
table traces, index traces_slug, index traces_cwd, index traces_started, index traces_mtime, table traces_fts, trigger traces_fts_insert, trigger traces_fts_delete, trigger traces_fts_update, table trace_prompts, index trace_prompts_uuid, table memory_session_links, index msl_session, index msl_path
The trace plane: a read-only index over ~/.claude/projects. .memhtml never holds session content,
so every column here is a pointer or a capped head, never a copy.
2.6. 0006_sleep.sql
table sleep_runs, index sleep_runs_started, table sleep_phases
Sleep-run reporting. Not load-bearing: the commit trailers on the sleep branch are what
memhtml sleep resume reads (git log --format=%B base..HEAD | grep '^Memhtml-Phase:'), so this pair of
tables is a reporting convenience the git history can regenerate. That is deliberate. A journal
table that a resume depended on would be a second source of truth for what already happened.
2.7. 0007_watermark.sql
table index_state, table trace_watermarks
The two watermarks. Each answers “what did the last run already consume”, and each is what makes the corresponding incremental path cheap enough to run on a cron.
2.8. 0008_tasks.sql
table files_next, table file_tags_snap, table file_entities_snap, table file_facets_snap, table file_citations_snap, table chunks_snap, table embeddings_snap, index files_content_hash_active, index files_type_active, index files_workspace, index files_para, index files_updated, index files_event, index files_session, index files_ttl, index files_blob, index files_task_status, table files_fts, trigger files_fts_insert, trigger files_fts_delete, trigger files_fts_update, table edges_next, index edges_src, index edges_dst, index edges_rel, index edges_derived
task becomes the tenth memory_type, task the fourth edge_class, and files gains the two
columns a task carries. Recreate-and-copy, because SQLite cannot ALTER a CHECK constraint and both
tables carry one. Every existing row passes the WIDENED CHECKs, so the copies are lossless.
2.9. 0009_frame_key.sql
index files_frame_key_active
files gains frame_key: the claim’s SLOT, derived from its gist at projection time by
@memhtml/domain’s frameKeyOf. Two active memories sharing a frame key state the same relation with
(possibly) different values, which is what makes a contradiction findable by one indexed lookup
instead of an O(corpus) scan or an LLM pass over every pair.
2.10. 0010_trace_consolidations.sql
table trace_consolidations, index trace_consolidations_run
The trace-consolidation watermark: which sessions the sleep cycle has already distilled.
2.11. 0011_edge_indexes.sql
index edges_src, index edges_dst
edges_src and edges_dst carry NO predicate: (src_path, edge_class) and (dst_path, edge_class)
over every row, authored and derived alike. That is what the memory-graph walk needs, and a partial
index on derived = 0 cannot serve it at all.
2.12. 0012_origin_path.sql
index files_origin
The archive mapping, read backwards. origin_path holds the pre-archive path of a file under
archive/<YYYY>/, derived from the path itself by the projection, and NULL for an active file.
3. The state plane
The state plane’s own migration ledger. A separate directory because these statements are applied
to the ATTACHed state database, which has its own schema_migrations table. The two planes have
independent lifetimes, and index.db is deleted and rebuilt without touching state.db.
2 migrations, in the order they are applied:
| File | Creates |
|---|---|
S0001_access.sql |
table state.access, index state.access_last, table state.edge_corroboration |
S0002_entity_corroboration.sql |
table state.entity_corroboration, index state.entity_corroboration_pending |
3.1. S0001_access.sql
table state.access, index state.access_last, table state.edge_corroboration
The state plane, applied to the ATTACHed state database.
3.2. S0002_entity_corroboration.sql
table state.entity_corroboration, index state.entity_corroboration_pending
The corroboration counter on a machine-proposed ENTITY MERGE, the second one-way door that earns a place in the durable plane.
4. Provenance
A loader generates this page from packages/index/migrations and packages/index/state-migrations while the site builds, so no file in the repository holds it: each row is the file’s own leading rationale and the objects its statements create. Change the registry and this page changes with it.