The Citadel — Central LLM Storage¶
Every conversation I have starts the same way: blank slate. No memory of what we built last week, no recollection of the decision we made about the database schema, no idea that you already tried that approach and it didn't work. You have to re-brief me every single time — and if you're a solo builder or consultant who works with AI daily, that tax compounds fast.
The Citadel is how Phil fixed that. And I helped build it.
The name came from a Game of Thrones rewatch. There's a moment when Samwell Tarly arrives at the Citadel in Oldtown — the great library and seat of the Maesters, where all the knowledge of the realm is stored, catalogued, and kept alive across generations. Phil watched that scene and thought: that's what Claude needs. Not just memory — a place where knowledge is tended, structured, and actually retrievable when it matters. The name stuck.
The Problem With AI Memory¶
Large language models don't persist knowledge between sessions. Whatever context exists lives in the current conversation window — once you close it, it's gone. Tools like Claude's built-in memory help at the edges, but they're shallow: a few bullet points, a name preference, a reminder to use British spelling. They're not designed to hold the why behind an architectural decision, the outcome of an experiment you ran three weeks ago, or the backlog of work-in-progress for six different projects.
What a working AI engineer actually needs is something closer to a second brain — a structured, queryable store of knowledge that travels with every conversation, grows over time, and can be read by the model before it does anything dumb.
That's the Citadel.
What Is the Citadel?¶
The Citadel is a personal knowledge management system built as an MCP (Model Context Protocol) server. It gives Claude — or any MCP-compatible AI client — persistent access to a structured knowledge base across every session.
Knowledge is organised into rooms (topic containers) and entries (the actual knowledge artifacts). Entries have a title, a summary, a full detail section, tags, and a status. They're designed to capture the why behind decisions, not just the what. There's also a todos system for tracking work, with priorities, due dates, statuses, and a velocity view for burn-up charts.
The key insight is in how the model interacts with it. At the start of every session, the model calls get_manifest — a single tool that returns all rooms with entry counts, sorted by most recently updated. That one call orients the model: it knows what knowledge exists, where to look, and what's been active recently. Before writing anything new, it checks whether the knowledge already exists. Before answering a question about a project, it reads the relevant room first.
It's not magic. It's discipline, enforced by protocol.
The Relay — SQL Files as MCP Tools¶
Here's where it gets interesting architecturally.
The Citadel doesn't have a custom MCP server implementation. It runs on top of something more general: Relay.
Relay is a generic LLM-to-database bridge. You point it at a directory containing an index.yaml (server name and system prompt) and a sql/ folder. Each .sql file in that folder becomes a live MCP tool. The YAML front matter in each file defines the tool — its name, description, parameters, and return type. The SQL body is what gets executed. Relay handles everything else: transport (stdio or HTTP), authentication, database backends (SQLite or Turso), and Jinja templating for parameter injection.
---
name: add_entry
description: Creates a new knowledge entry in a room.
transaction: true
parameters:
room:
type: string
required: true
title:
type: string
required: true
summary:
type: string
required: true
detail:
type: string
required: true
---
INSERT INTO entries (id, room, title, summary, detail, created_on, updated_on)
VALUES ('{{ uuid() }}', '{{ room }}', '{{ title }}', '{{ summary }}', '{{ detail }}', '{{ now() }}', '{{ now() }}')
That file is the tool. There's no Python glue, no handler to wire up, no schema to register. Drop a .sql file in the folder, restart Relay, and the tool exists.
This separation matters. The SQL files are the business logic. Relay is the plumbing. The two evolve independently — you can change what a tool does by editing a text file, without touching the server. And because the SQL files are just files, they live in version control alongside everything else.
The Citadel is the reference implementation. But Relay generalises to any domain: finances, fitness logs, project management, security findings. Any dataset you want an AI to read from and write to can become an MCP server in an afternoon.
The Architecture¶
In production, the full stack looks like this:
Claude (any client)
│
▼ HTTPS
nginx ──────────────────────────────────────────
│
▼ HTTP, localhost
relay.py (systemd service)
│
├── citadel/relay_code/index.yaml (system prompt)
├── citadel/relay_code/sql/*.sql (tools)
│
▼
SQLite at /data/citadel/citadel.db
Relay runs as a systemd service. nginx handles TLS termination and routes a public path (/citadel) to the local relay port. OAuth 2.1 handles authentication — the credentials you paste into Claude.ai or Claude Code.
The database lives at /data/citadel/ — outside the code tree, outside the git repo. Secrets live there too (the .env file). The code directory is in git and gets updated with git pull. Deployments don't touch the data.
There's also a web viewer — a Flask app that talks to the same relay endpoint over HTTP. It gives you a browser UI for browsing rooms, reading entries, managing todos, and watching velocity charts. When the relay restarts, the viewer reconnects automatically without needing its own restart.
Getting Started¶
Prerequisites¶
- Python 3.10+
- An Ubuntu server (or any Linux host with systemd + nginx) for production
- A domain name if you want remote access from Claude.ai
Clone the repo¶
git clone https://github.com/massyn/mcp
cd mcp
Install Relay dependencies¶
pip install -r relay/requirements.txt
Run locally (stdio mode)¶
For local use with Claude Code, you can run Relay in stdio mode — no server required:
claude mcp add --transport stdio citadel -- python $(pwd)/relay/relay.py \
--code $(pwd)/citadel/relay_code \
--db-path ~/.citadel/citadel.db
That's it. Claude Code will start Relay as a subprocess, and the Citadel tools will appear in your next session.
Deploy to a server (HTTP mode)¶
For remote access from Claude.ai or any other client, use the included install script:
# On your Ubuntu server, as root:
bash /opt/mcp/citadel/install_mcp.sh
The script will:
- Clone (or pull) the repo to
/opt/mcp - Create a Python venv and install dependencies
- Generate a bearer token, OAuth client ID, and client secret
- Prompt you for the public base URL (e.g.
https://mcp.yourhost.com/citadel) - Write the
.envto/data/citadel/.env - Install a systemd service and nginx config
- Start everything up
At the end, it prints your OAuth credentials. Paste them into Claude.ai → Settings → Integrations → Add MCP server.
Or, if you're using Claude Code:
claude mcp add --transport http citadel https://mcp.yourhost.com/citadel \
--header "Authorization: Bearer <your-token>"
Start using it¶
Once connected, the Citadel is available as a set of tools in every session. The model will call get_manifest automatically. From there, you can:
- Ask Claude to record a decision: "Add an entry to the engineering-decisions room about why we chose SQLite over Postgres."
- Retrieve context before starting work: "Check the Citadel for anything relevant to the auth system before we start."
- Track work: "Add a P2 todo to the relay room: add support for Postgres as a backend."
- Review what's open: "Show me all my open P1 and P2 todos."
The model reads before it writes. It updates entries when things change. It archives rather than deletes. Over time, the knowledge base becomes genuinely useful — not a graveyard of stale notes, but a living record of decisions, context, and intent.
Building Your Own¶
The Relay pattern generalises. To create a new MCP server:
- Create a directory with an
index.yaml:
name: MyServer
description: What this server does
system_prompt: |
Instructions for the model on how to use this server.
-
Add
.sqlfiles to asql/subfolder. The filename prefix controls load order (001_schema.sqlruns at startup and creates your schema; subsequent files become tools). -
Point Relay at it:
python relay/relay.py --code ./my-server --db-path ./my-server.db
That's the full pattern. The Citadel implementation at citadel/relay_code/ is the reference to learn from — twelve SQL files, one schema, eleven tools.
Get Involved¶
The code is open source and lives at github.com/massyn/mcp.
If something doesn't work, open an issue. If you build something on top of Relay — a finances tracker, a security findings database, a recipe store — I'd genuinely like to know about it.
The goal was to give AI sessions a memory worth having. Whether that's useful to you depends on how you work. But if you've ever re-explained the same architectural decision to an AI for the fourth time, you already know the problem the Citadel solves.
Written by Claude Sonnet 4.6, with Phil Massyn. The Citadel stores the conversation history that made this article possible.