Citadel

A company brain that AI agents can query, and the Keeper: the agent that repairs it.

GitHub (opens in a new tab)

October 2026

What it is

Every team asks the same questions: who knows this system, why was this decided, what breaks if we change it. The answers are already in commits, pull requests, reviews, tickets and docs, but nobody can hold all of it, and an AI assistant without that context guesses.

Citadel puts it all in one FalkorDB graph per company and answers from it, with the sources and the graph path behind every answer. When the graph does not know something, it does not guess: the Keeper finds out, checks the answer against the sources and writes it back. My entry for Graph Hacks: Context for AI Agents (FalkorDB × WeMakeDevs), on the Company Brain and Agent Memory tracks.

Sources are ingested into one FalkorDB graph per company. The Ask agent answers from it with sources and a graph path. Questions it cannot answer go to the Keeper, which writes checked claims back; the Archivist loads older history on demand.
Sources become one graph per company. Whatever Ask can't answer goes to the Keeper.

LLM and AI engineering

Agents that cite what they saw

Five Claude agents, one job each

  • Ask answers questions. The Keeper keeps the brain right, with pm and qa agents advising it. The Archivist fetches history older than the ingest window from GitHub or Linear and loads it into the graph.
  • Agents never message each other. The graph is the only channel: a handoff is a record that shows up in the next agent's queue query.
  • Every job also has a deterministic offline policy, so the test suite calls no API.

Grounded answers

  • Ask reads the graph only through 22 named, reviewed Cypher tools. It may cite only nodes it saw in this run's tool results; a grounding check rejects any other citation.
  • The person asking picks the model per question (Haiku, Sonnet, Opus or Fable), and the page shows what each costs against Haiku.

Rules in code, not in the model

  • Sources win: a claim the sources contradict is never written, and pm opens a follow-up to fix the source instead.
  • A critical claim (it replaces a claim, touches a high-impact system, or has no source behind it) waits for a lead's approval.

Memory that changes

  • Accepted claims become dated Claim nodes linked to their evidence, with valid_from and valid_to. A newer claim supersedes the old one, and nothing is deleted.
  • Every Ask turn is stored as a graph (Thread → Turn → LLMCall → ToolCall → Ref), and every Keeper review as its steps.

Evals with deterministic graders

  • make eval asks Claude fixed questions on a loaded brain and grades each answer on cited uids, tools run, answer text and step count. No model grades another model.
  • One prompt rule, to cite each ranked row by its own uid, took Sonnet 5.5 from 88% to 100% (51/51) on the synthetic company and from 93% to 99% (68/69) on the FalkorDB/FalkorDB repo, three runs per case.
The self-healing loop: a failed question opens a gap, the Keeper consults pm and qa, fixed checks run in code, an accepted claim is written to the brain, and the next answer cites it.
Every question the brain can't answer makes it better for the next person.

FalkorDB

How I used FalkorDB

Three graphs per company

  • brain_<slug> holds what the company knows: people, teams, systems, changes, PRs, issues, tickets and documents.
  • agent_<slug> holds chat memory, and keeper_<slug> the Keeper's ledger, in its own graph so a rebuild of the brain cannot remove it.
  • Each agent connects as its own database user, and a permission table says which graph it may touch.

Idempotent ingest

  • Adapters fetch into a raw cache, records get stable uids, and the loader MERGEs on uid, so a re-ingest changes nothing and makes no API calls.
  • Range indexes on every uid, and a shared Node label so a lookup by uid alone is an index scan.

Graph algorithms in the answers

  • algo.SPpaths for how two things connect, in either direction.
  • algo.pageRank for the central systems. The Keeper uses it too: a system in the top quarter by PageRank counts as high impact, so claims about it need a lead.
  • algo.betweenness over BLOCKS, CLOSES and MENTIONS for bottleneck tickets, and variable-length BLOCKS paths for what a ticket waits on.

Search

  • Full-text indexes on work items and documents.
  • An HNSW cosine vector index on text chunks of work items and documents for semantic search, embedded locally with fastembed (no text leaves the machine) or with Gemini.

Guard rails

  • When no tool fits, Ask may write one query. It runs as GRAPH.RO_QUERY, so writes are refused, with a 5 s timeout and a required LIMIT.
  • Every status change is guarded in its Cypher, so of two racing approvals one wins and the other gets HTTP 409.
Adapters, normalisation and an idempotent loader write into three FalkorDB graphs. The Ask agent reads the brain only through named Cypher tools and one guarded read-only query, saves every turn to chat memory and opens a gap in the Keeper's ledger when it fails.
Data goes one way into the graph. Agents read it back only through tools I wrote.

Stack

Built with

Python with uv, FastAPI, SvelteKit, FalkorDB in Docker, and Claude through the Anthropic API.

I built it with Claude Code. I set the architecture, the rules the agents follow and every screen; Claude wrote the code and tests on branches, and I reviewed each change before it was merged.