Memory Vault

The Memory Vault is Sanctum’s shared knowledge base, inspired by how human memory works — which is to say, it forgets things on purpose and considers this a feature. It uses a three-tier temporal architecture (working / short-term / long-term) sitting on top of a four-system backend stack (described below), with a daily consolidation process that acts like sleep: distilling raw observations into lasting knowledge.
At some point during development, we realized we’d built a system that remembers where you left your SSH keys, forgets trivial session data, and dreams at 4 AM. The horror movie writes itself.
Memory Stack
Section titled “Memory Stack”Today’s stack is the local git vault, fronted by two access surfaces (a Rust REST service and a Python MCP server), plus the entity graph running on the VM. The doc once described a four-layer design that included a mem0.ai cloud tier; that integration was never wired up, and the privacy posture decided on 2026-05-16 (vault GitHub mirror archived, “the haus does not sync its thoughts to the cloud”) makes wiring it now an explicit policy violation. Honesty over aspiration.
| Layer | Role | Backend | Cost |
|---|---|---|---|
| Memory Vault | Git-native versioned source of truth, primary cross-agent semantic memory | Local-only git repo at ~/.sanctum/memory/ (GitHub mirror archived 2026-05-16 as part of the privacy scrub; the haus does not sync its thoughts to the cloud) | Free |
sanctum-memory REST | The read/write data plane over the vault git repo | Rust service on 127.0.0.1:42069, serving /health and /v1/* HTTP routes (search, read, write, recall, ingest, consolidate) | Free |
memory_vault MCP | Tool surface — how an agent’s tool-call becomes a vault operation | Python server (python -m memory_vault) over stdio, exposing the 8 memory_* tools below | Free |
| Neo4j / Graphiti | Entity relationships & graph queries | Reached via SSH tunnel on local port 31416 (graph runs on the VM, not the host) | Free (self-hosted) |
Architecture
Section titled “Architecture”┌─────────────────────────────────────────────────────┐│ LAYER 1: WORKING MEMORY (per-session, ephemeral) ││ Agent's context window. Dies when session ends. │├─────────────────────────────────────────────────────┤│ LAYER 2: SHORT-TERM MEMORY (inbox/, days-weeks) ││ inbox/{agent}/ — raw observations, session notes ││ TTL: 7-30 days. Consolidated or discarded daily. │├─────────────────────────────────────────────────────┤│ LAYER 3: LONG-TERM MEMORY (consolidated, permanent)││ knowledge/{topic}/ — semantic facts (timeless) ││ events/YYYY/MM/ — significant episodes ││ procedures/ — how-to, runbooks ││ Neo4j/Graphiti — entity relationship graph │└─────────────────────────────────────────────────────┘Directory Structure
Section titled “Directory Structure”~/.sanctum/memory/├── inbox/ # Short-term, per-agent│ ├── claude-code/│ ├── gemini-cli/│ ├── openclaw/│ └── home-assistant/├── knowledge/ # Long-term semantic│ ├── devices/│ ├── network/│ ├── systems/│ ├── people/│ └── preferences/├── events/ # Long-term episodic│ └── 2026/03/├── procedures/ # Long-term procedural│ ├── troubleshooting/│ ├── maintenance/│ └── automation/├── archive/ # Expired, retained 90 days└── meta/ # Schema, consolidation logsNote Format
Section titled “Note Format”Every note has standardized YAML frontmatter. Opinions may vary on whether your haus needs a metadata schema for its thoughts. Opinions are wrong.
---type: semantic | episodic | procedural | observation | session_summarysource_agent: claude-code | gemini-cli | openclaw | user | systemcreated: 2026-03-20T17:00:00Zupdated: 2026-03-20T17:00:00Zlast_accessed: 2026-03-20T17:00:00Zaccess_count: 3importance: 0.85consolidation_status: raw | reviewed | consolidated | archivedttl_days: null # null = permanent, or integer dayssuperseded_by: null # path to newer versiontags: [network, infrastructure]related_entities: [mac-mini, ubuntu-vm]---
# Note Title
Content with [[wikilinks]] to related notes...Importance Scoring
Section titled “Importance Scoring”Every note has a computed importance score (0.0 to 1.0) that determines its TTL. The vault is, in essence, deciding what’s worth remembering. A power you’d think we’d reserve for sentient beings, but here we are.
| Importance | TTL | Notes |
|---|---|---|
| > 0.8 | Permanent | Core knowledge, user-stated facts |
| 0.5 - 0.8 | 90 days | Agent-observed patterns |
| 0.3 - 0.5 | 30 days | Single observations |
| < 0.3 | 7 days | Ephemeral session data |
Score formula: source_weight x recency x access_frequency x link_density
Notes accessed 5+ times are protected from expiry regardless of score. If the system keeps coming back to a memory, there’s probably a reason. Even if that reason is paranoia.
Consolidation
Section titled “Consolidation”The consolidation engine runs daily at 4:17 AM (LaunchAgent: com.sanctum.memory-consolidate). Like sleep for the brain, except it runs on schedule, never hits snooze, and files a report when it’s done.
- Scan inbox for notes older than 24 hours
- Deduplicate against existing long-term knowledge
- Classify and move to the appropriate long-term directory
- Recompute importance scores for all active notes
- Expire notes that have exceeded their TTL
- Enforce caps via bounded archive-eviction (see Hard Caps below)
- Clean archive — delete archived notes older than 90 days
- Generate report in
meta/consolidation-log.md
Any agent can trigger consolidation manually via the memory_consolidate MCP tool.
Hard Caps
Section titled “Hard Caps”To prevent bloat, each layer has a maximum note count. Without limits, a system that remembers everything eventually remembers nothing useful — a problem familiar to anyone who’s ever hoarded browser tabs.
| Layer | Max Notes | Action at Cap |
|---|---|---|
| Inbox | 300 | Bounded archive-eviction, ≤50/run |
| Knowledge | 1000 | Bounded archive-eviction, ≤20/run |
| Events | 500 | Bounded archive-eviction, ≤100/run |
| Procedures | 200 | Bounded archive-eviction, ≤10/run |
Eviction sorts candidates by (importance ascending, created ascending) and skips anything with importance > 0.8 — permanent knowledge survives cap pressure. Each run is rate-limited so a layer at 6× cap converges over many nightly cycles rather than collapsing in one massacre. Archived notes are retained for 90 days via ARCHIVE_RETAIN_DAYS before deletion — eviction is reversible during that window.
MCP Tools (8 total)
Section titled “MCP Tools (8 total)”| Tool | Description |
|---|---|
memory_search | Full-text search with tag and folder filters |
memory_read | Read a note (auto-tracks access) |
memory_write | Create/update with schema enforcement |
memory_delete | Remove a note |
memory_list | List notes by folder, tag, or type |
memory_links | Traverse the wikilink graph |
memory_consolidate | Trigger consolidation (dry-run by default) |
memory_health | Vault health metrics dashboard |
On Mem0 (historical aside)
Section titled “On Mem0 (historical aside)”Earlier versions of this doc described a mem0.ai cloud tier as the primary cross-agent memory layer, with a planned set of MEM0_* cloud tools and a “push to Mem0” step in nightly consolidation. None of that integration was ever wired up — there’s no mem0 client in the repo, no API key, and no mem0.ai traffic from the host.
When the privacy posture was decided on 2026-05-16 (vault GitHub mirror archived, “the haus does not sync its thoughts to the cloud”), Mem0-as-cloud-tier became incompatible with explicit policy. The architecture quietly converged on the local-only model documented above; the doc just hadn’t caught up. This section exists so anyone reading old commit messages or older drafts knows what happened: the cloud tier is not coming back absent a deliberate privacy-posture reversal.
Tool Integration
Section titled “Tool Integration”| Tool | Vault Access |
|---|---|
| Gemini CLI | memory_vault MCP over stdio (~/.gemini/settings.json) |
| Claude Code | Not currently wired — mcpServers is empty; reach the vault via the :42069 REST API or vault.sh until the MCP is added |
| OpenClaw agents | SSH skill (vault.sh) |
| Sanctum automations | :42069 REST API (/v1/write, /v1/search) — the old GitHub path died with the 2026-05-16 archive |
| Obsidian | File system (~/.sanctum/memory/) |
| Holocron | HausBrainPanel polls /vault/brain from Force Flow (:4077) every 5s; new-note particles fire in real time off an Electron IPC vault-event bridge, not a separate socket |
Known Gaps
Section titled “Known Gaps”After tonight’s reconciliation pass (2026-05-29), there are no open implementation gaps — the machinery does what this page says it does: short-term inbox + long-term knowledge/events/procedures, nightly consolidation with bounded archive-eviction, 90-day reversibility, the memory_* tool surface, the :42069 data plane.
One thing the caps table doesn’t show: the vault is currently over cap and grinding down. Events sits at roughly 8× its 500-note cap, and the nightly run evicts 100 events per cycle by design (MAX_EVICT_PER_RUN) rather than archiving thousands in one massacre. That’s the bounded-eviction design working, not a steady state — a system converging, not a system at rest.
The procedures layer was empty for months and is now seeded — 5 high-signal runbooks grounded in recent incidents live under procedures/{troubleshooting,maintenance,automation}/. The layer grows organically from there as incidents teach the haus new procedures worth remembering.
The only architectural decision left open is whether to ever re-introduce a cloud-sync tier (see On Mem0 above). That is a privacy-posture decision, not an engineering gap.
Anti-Bloat Rules
Section titled “Anti-Bloat Rules”- If derivable from code, logs, or sensors — don’t store it
- If the same fact is stated multiple ways — dedup into one
- If never accessed in 30 days and importance < 0.5 — archive
- Raw data goes to time-series DBs, not memory
- Every episodic memory needs context (who, what, when, why)
- Every semantic memory should be self-contained