Structured user memory: typed graph + fetch-before-cite, on every surface

Open 💬 0 comments Opened Jul 7, 2026 by parrik

Ask Claude a personal question on the phone and it makes things up. Fluent, confident, wrong. A summary that sounds like me but drifts from what I said.

Ask the same question in the terminal, where Claude Code has my knowledge graph, and it gets it right. It quotes what I actually said, with dates. When I'm wrong about my own history, it shows me the record.

Same models. The difference is the substrate.

What I run

I keep a typed graph in a YAML file. I've used it daily for 100+ days and I make real decisions with it. Write-up: https://parrik.com/puzzles/know-thyself/

  • Nodes are typed: observation, reference, interpretation, practice, forecast.
  • Edges are typed too: grounded-by, related-to, supersedes, counter-evidence.
  • Every node carries provenance. Did I say it or did the model infer it? Is it tentative? When was it true?
  • Corrections don't overwrite. They supersede, with a date. A guess said five times stays one guess.
  • Search goes through an MCP server and returns names and edges only. No bodies. Reading a node is a separate, explicit step.
  • One rule on top: the model may not cite a node it hasn't read this turn. That one rule kills most memory hallucination.
  • Writes are gated by ring. Low-stakes notes auto-merge. High-stakes claims wait for my accept click. The model proposes. I curate.

The schema

One YAML file, a flat list of nodes. Both nodes and edges are typed.

| Node type | What it is | Who writes it |
|---|---|---|
| Reference | A fact from a single source. No interpretation. | model |
| Observation | A dated event or data point. The raw layer. | model |
| Overlap | A pattern backed by multiple independent observations. | model |
| Novel | A one-derivation interpretation. Flagged tentative. | model |
| Emergent | A claim that only appears where other nodes intersect. High value, high speculation. | model |
| Theme | A roof over nodes from different periods that share content. | model |
| Period | A named stretch of life with a start and an end. Other nodes live inside it. | model |
| Practice | A rule I live by. | me — accept click required |

| Edge type | Meaning |
|---|---|
| grounded_by | claim → the evidence under it |
| derives_from | interpretation → what it was derived from |
| counter_evidence | evidence against, kept on the node. Nothing gets deleted. |
| related_to | cross-link |
| supersedes (dated) | corrections replace. They don't overwrite. |

Fields that do the real work: tentative, source_kind (lived / told / inferred / imagined), valid_at, and an append-only revisions log. Every AI rewrite of a claim is itself recorded, so drift is auditable.

The split:

  • Auto-extracted, written directly by the model: observations, references, patterns, interpretations, themes, periods, and all their edges. Low stakes. Reversible. Sharpenable later.
  • Human in the loop: practices — the rules I actually live by. The model authors a candidate. Nothing merges until I click accept. The ring is capped around ten, so it stays readable.

The model does the volume. I curate only what can hurt me.

In long decision sessions the model pushes back with my own records instead of mirroring my mood. That is the most useful thing an AI has done for me. It comes entirely from the substrate.

What I'm asking for

Make this the default shape of memory, on every surface. Five pieces:

  1. User-owned memory with a schema. Typed records, typed relations, provenance, tentative flags, dated supersession. I can read and edit every byte of what the model knows about me.
  2. Find and read as separate steps, with cite-enforcement at the harness level. No citing what you didn't read this turn.
  3. Gated writes. A staging queue and an accept/reject surface. Model proposes, user curates.
  4. Same memory on every surface. The phone should mount what the terminal mounts. Right now the surface people use most is the one that confabulates.
  5. Provenance shown in answers. "You told me this, dated, tentative" is a different sentence from "I'm inferring this." Render them differently.

None of this needs my content. Anyone making repeated high-stakes decisions needs an assistant that can't misquote their own history back to them. The pieces already exist: files, MCP, hooks, tool use. What's missing is making them the default instead of a power-user build.

View original on GitHub ↗