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 over MCP. I have used it for about five months so that I don't start from zero when I come back to a project in a new session: I call up the project and Claude traces the related decisions, with the evidence next to them. Today it holds 179 decisions and 445 pieces of evidence.

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:

  1. a captured decision always starts as «proposed», and only a person can confirm it, with a

permission no agent holds.

  1. a decision is confirmed only with at least one piece of evidence pointing to a stable source.
  2. the graph is append-only: a decision changes only through a new one that supersedes it, with a

date.

  1. 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.

Image
The ctx-memory Graph Explorer: four main contexts with their areas, decisions and evidence, drawn as a 3D graph.

Sources

All measurements were read on 1 October 2026 from the ctx-memory database.

Author's own measurements.

Giorgio Pagano
AI modified

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.