ctx-memory: how I built a decision memory for Claude on Drupal
ctx-memory is an experiment of mine: a small graph of project decisions, built on Drupal 11 and Typesense, which Claude queries through an MCP server. It is an offshoot of the system I use to work with AI, and for about five months it has been one of the tools I use most. The code isn't public: it's a case study, and I'm happy to walk anyone interested through it.
Why a custom system, when ready-made ones exist?
I went custom to keep control and to be able to see it. There are plenty of MCP servers that give Claude a memory, and some of them are well made. I wanted to try a solution of my own instead: use Typesense for search, and keep the data in a small graph whose structure I control, field by field.
The problem was a practical one. When I work on the same project across several sessions, each new session starts without remembering the choices made in the earlier ones. With ctx-memory the decisions stay: I find them by querying the graph, instead of explaining them again or, worse, contradicting them.
How is ctx-memory built?
ctx-memory brings together a few components, each with a single job:
| Component | Role |
|---|---|
| Drupal 11 on PostgreSQL | stores contexts, decisions, evidence and relations as entities, with revisions and permissions |
| Typesense, through Search API | indexes everything for search, with an in-memory index that can be rebuilt from the database |
| MCP server | gives Claude three tools: search, read, capture |
| two Claude Code hooks | capture on their own the proposal.md of every OpenSpec change and every committed ADR, with the permalink |
| Graph Explorer | a 3D view of the graph, to look at how the data is organised |
| Sablier | starts the stack on the first request and stops it when it sits idle |
Relations are entities too: there are 645 of them today, linking each decision to its context and to the evidence behind it.
Why use Drupal as a graph database?
Because Drupal already provides almost everything a long-lived piece of data needs. Every entity has typed fields, revisions and permissions. The admin interface for fixing a record is there without writing it, and Search API connects Typesense with no indexing code. The custom work comes down to the data model and the rules, which is exactly the part I wanted to control.
Which rules keep the memory reliable?
The project specification sets four rules as non-negotiable principles:
- a captured decision always starts as «proposed», and only a person can confirm it, with a
permission no agent holds.
- a decision is confirmed only with at least one piece of evidence pointing to a stable source.
- the graph is append-only: a decision changes only through a new one that supersedes it, with a
date.
- every record states who wrote it, a person or a model, and in which run.
The numbers show the first rule at work. All 179 decisions in the graph were captured by a model; I confirmed 87, 82 are waiting for my review, I discarded 6, and 4 were superseded by a newer decision.
How do I use it day to day?
From the terminal, with Claude. I call up the project, and Claude traces the related decisions and their evidence, so a new session starts again from context that is already defined. New decisions are written into the graph by the ctx-memory skill, as proposals.
I don't use the Graph Explorer to search: it's there to look at the structure of the data and to check that the graph is growing the right way.
Sources
All measurements were read on 1 October 2026 from the ctx-memory database.
- Drupal (opens in a new tab) and Search API Typesense (opens in a new tab). Primary source.
- Typesense (opens in a new tab). Primary source.
- Model Context Protocol (opens in a new tab). Primary source.
- OpenSpec (opens in a new tab) and Architecture Decision Records (opens in a new tab). Primary source.
- Sablier (opens in a new tab). Primary source.
- ctx-memory specification and code, counts of decisions, evidence, contexts and relations.
Author's own measurements.
This text was translated by AI.
How was AI used?
Translated from the Italian original with AI assistance, then read and corrected by a person, who holds editorial responsibility.