The memory stack under the AI workflow: CLAUDE.md, MemPalace, and a knowledge graph
The first post in this series was about the practice — how I structure prompts, iterate in short cycles, and delegate mechanical work while keeping judgment on my side. This one is about the infrastructure underneath that practice: the three-layer memory system that makes it work across sessions, projects, and weeks.
None of these layers is technically complex. The value comes from how they fit together.
The problem with AI memory (briefly)
Language models have no persistent memory. Every session starts blank. That’s fine for a one-off question, but if you’re using AI as a serious development tool, it creates friction: re-explaining project structure, re-establishing conventions, correcting the same behavior you already corrected last week.
The fix isn’t pasting context into each session. That’s manual, inconsistent, and doesn’t scale. The fix is building a memory system that loads the right context automatically — and grows smarter the more you use it.
Three layers do this, each solving a different part of the problem.
Layer 1 — CLAUDE.md: static context as code
Every project I work on with AI has a CLAUDE.md file at the root. It’s loaded automatically at session start by Claude Code. The AI walks into each session already knowing the project.
The key distinction: this file is not documentation for humans. It’s context shaped around the questions an AI will ask.
A README answers “what is this?” for a human who will then read code. A CLAUDE.md answers “where are the config files?”, “how does deployment work?”, “what is this .k8s/ directory?”, “what should I avoid touching?” — the questions that would otherwise consume the first ten minutes of every session.
In practice, a well-written CLAUDE.md covers:
- Directory structure and what each folder actually does
- How to run the project locally, how to build, how to deploy
- Conventions: branch naming, commit style, what goes in a PR
- Constraints: what not to do, why certain decisions were made
The “why” matters as much as the “what”. “We use Recreate deployment strategy instead of RollingUpdate” is useful context. “We use Recreate because the app uses SQLite which doesn’t support concurrent writers” is the context that prevents the AI from helpfully suggesting a rolling update and breaking everything.
Layer 2 — MemPalace: dynamic memory between sessions
Static context covers what the project is. Dynamic context covers what happened — decisions made last Tuesday, feedback given last week, a workaround discovered in session seven.
This is what MemPalace handles.
The name isn’t accidental. The method of loci — a mnemonic technique attributed to the Greek poet Simonides of Ceos around 500 BC — works by mentally placing information in rooms of a familiar place. To recall it, you walk through the palace and find what you left behind. The software borrows the same structure deliberately: wings, rooms, drawers are the building. The AI walks through it.
MemPalace is a local-first memory system that runs as an MCP server (Model Context Protocol — an open standard for connecting AI tools to external data sources) integrated with Claude Code. During and after sessions, it mines conversations and saves structured memories to a local vector database (ChromaDB).
The first post mentioned the shape of this in passing — wings, rooms, drawers. Here’s the full picture: wings (one per project, plus a sessions wing for cross-project work), rooms (topics: technical, architecture, planning, problems, diary), and drawers (individual memory chunks).
How the hooks work
The integration runs silently through two hooks:
Stop hook — fires automatically every 15 message exchanges. Saves a diary checkpoint of the recent conversation to the project wing. No interruption, no output: silent_save mode means it happens in the background.
Precompact hook — fires before Claude Code compresses the context window. Mines the full session transcript into structured drawers, classifying content into rooms by type (technical details, architectural decisions, problems and workarounds, etc.).
The result: by the time a session ends, everything worth keeping is already filed. The next session starts with that knowledge available.
What gets stored
The extractor identifies five memory types without needing an LLM — keyword and pattern matching:
- Decisions — choices made, with their rationale
- Preferences — “always do X”, “never do Y”
- Milestones — something that shipped, a version that deployed, a problem solved
- Problems — bugs, errors, root causes, workarounds
- Emotional markers — breakthroughs, frustrations, context that shapes tone
In practice, the most valuable room is architecture: it accumulates the reasoning behind structural choices that aren’t visible in the code itself.
Layer 3 — The knowledge graph: structured relationships
Drawers store text. They’re retrieved via semantic search — useful, but fuzzy. When you ask “what does personal-blog deploy on?”, semantic search returns chunks of text that mention deployment. You still have to parse the answer.
A knowledge graph stores the answer as a fact: personal-blog → deployed_on → home-cluster. The query is instant, structured, and unambiguous.
MemPalace includes a temporal knowledge graph built on SQLite. Facts are stored as triples: subject → predicate → object, with optional time windows. Triples can be invalidated when they change — the old fact is marked expired, the new one added. The history is preserved.
The KG is populated via MCP tool calls. Each call is small:
subject: "personal-blog"
predicate: "deployed_on"
object: "home-cluster"The cost is negligible. The value compounds: once a fact is in the graph, it’s queryable in milliseconds — by me, or by the AI at the start of any session.
The graph answers questions that drawers can’t answer cleanly: “which projects deploy to home-cluster?”, “what databases does this stack use?”, “what tools do I work with?”. Structured queries, structured answers.
When facts change
The KG doesn’t overwrite — it expires. When something changes (a new database, a different deployment target, a replaced tool), the flow is:
- Invalidate the old fact:
mempalace_kg_invalidate(subject, predicate, object)→ marksvalid_to = today - Add the new fact:
mempalace_kg_add(subject, predicate, new_object)→valid_from = today
The old fact stays in the graph, timestamped. The result is a timeline:
personal-blog → uses_theme → twentytwentyfour (valid: ?→ 2025-11-30)
personal-blog → uses_theme → astra (valid: 2025-12-01 → present)You can query the graph with as_of="2025-06-01" to see what was true at any point. Two facts with the same predicate can coexist if both are current — for example, a project that genuinely uses two databases simultaneously. The graph represents reality, not just the latest snapshot of it.
The protocol that closes the loop
The three layers work together when they’re fed consistently. The mechanism is simple: at the end of each session that produced something worth keeping, before the conversation closes:
- The stop hook has already saved the diary checkpoint
- I extract 3–5 facts from the session and add them as KG triples
- The precompact hook will mine the full transcript on the next compression
Step 2 is the only manual part. It takes thirty seconds and maybe five MCP calls. The facts added at the end of one session are available as structured context in every future session.
Over time, the system accumulates: decisions with their rationale, stack details per project, preferences and corrections that become default behavior. Each session starts warmer than the last.
Why three layers and not one
A single CLAUDE.md covers the project but not history. A vector database covers history but not structure. A knowledge graph covers structure but not prose context. Each layer fills a gap the others leave.
The overhead is low precisely because each layer is narrow: CLAUDE.md is a file you write once and update occasionally. MemPalace runs its hooks automatically. The KG grows a few triples per session.
The value isn’t in any single layer — it’s in not having to re-establish context every time. The tenth session with a project should feel like a continuation, not a restart. That’s what this stack makes possible.
That’s the design. After a few months running it across four active projects, I stopped to count what had actually piled up — how many memories, classified into what, and what the graph could tell me that I didn’t already know.