The organization vault
Your team already wrote it down, in commits, sessions, docs, and issues. Citadel captures it as it happens and gives you, and the agents beside you, one place to ask.
This page is served by the system it describes. Live numbers, releases, and the roadmap are on the status page.
Self-host cost is mostly RAM: 24h 2026-08-17 about $23; 7-day 2026-08-14 about $58. Not a ceiling; method in the bench harness.
Most team knowledge tools ask you to file things. Citadel captures the work you were doing anyway, then keeps the personal and the shared strictly apart.
Clients
Claude Code, Cursor, Codex, or an agent you wrote. The client speaks hosted MCP with a seat-bound bearer token. It gets the same tools and the same read scope as the seat that minted the token: your Node plus Central, never another seat. A search, a share-session, or a mesh read all start here, then enter Hosted MCP.
The terminal route. You onboard a seat token, search, ingest, and promote from the command line. citadel capture summarises an Approved Capture Root (git metadata and README, not raw files) and POSTs it to your Node. Same token, same scope as MCP. Next hop is HTTPS REST.
The signed-in workspace: search, the knowledge graph, connected sources, and the promotion queue. Public pages such as /info hydrate aggregates from /api/state and never see vault content. Signed-in calls go through HTTPS REST with the seat token.
A git pre-push hook and a SessionEnd hook write into your Node while you work. They fail silently, so a vault problem never blocks a push or a session close. Both refuse a non-HTTPS Node URL (loopback is the exception), refuse redirects so the bearer token is not resent, and omit the dataset field so the write lands on your Node. Next hop is HTTPS.
FastAPI
Streamable HTTP at /mcp/. The same tools the CLI speaks, behind a bearer token, so an agent never gets a wider read than the seat that minted it. Search, mesh, share-session, and promotion tools mount here and call the FastAPI routes in-process. Next hop is the matching FastAPI route, with the seat token already attached.
Anything that carries a seat token refuses plaintext. Capture hooks, citadel capture, and the promotion client require HTTPS except loopback or a Railway private service, and they do not follow redirects. The hosted Node is served on HTTPS at the edge. This is the constraint on the wire, not a separate process.
HTTP ingest and search, plus the rest of /api/*. Health endpoints and /api/state stay unauthenticated. Everything that reads memory needs a seat token. CLI, web, and hooks enter here. Authenticated routes go to search, ingest, mesh, share-session, or promotion. /api/state is public and skips the seat gate.
Tokens are minted per seat (ctdl_ prefix) and SHA-256 hashed at rest. A reader can search. A writer can ingest, volunteer a share-session, and promote. Admin is operations. The token is the seat: search is scoped to that Node plus Central, and another seat's content returns 404 rather than 403, so there is no existence oracle.
One query reads your Node and Central together and tells you which one answered. Seat presence is universal; content is caller-scoped. Another seat's content is never in the result, and drilling into it returns 404 rather than 403. The recall path hits Qdrant for embeddings, Ladybug for graph expansion, and SQLite for rows, then applies the visibility filter. Agents reach this through Hosted MCP. CLI and web reach it through REST.
Seat-scoped writes land on the owning Node. Untagged writes to Central are rejected. Every write path (HTTP, MCP, hooks, capture) runs the seat write-policy guard and a secret scan. Accepted bytes go to the learning process, which commits them to the lifecycle ledger. This is the Capture step on the PATH: hooks and citadel capture enter here.
The graph API and the dashboard mesh read the same stores the search path uses. Each dataset has its own Ladybug graph; an org-wide read merges those stores. Seat presence is universal; content is caller-scoped. Next hop is the memory engine, which talks to Ladybug and Qdrant.
A volunteered Shared Session Trace. The MCP tool citadel_share_session posts here after explicit user approval. Writer seat only. The payload is secret-scanned, then dual-written: light into your Node, shared into the session-traces dataset. Traces stay reference-only. They do not promote to Central and they do not feed the improve loop. Next hop is the learning process.
Public snapshot for the /info page. Safe aggregates only: no vault content, no per-seat data, no tokens, no graph dumps. A sync hiccup degrades to empty, never a 500. Unauthenticated on purpose. The signed-in dashboard does not use this for memory reads.
Core
Accepted content is filtered, chunked, embedded, and projected. A document counts as searchable in a backend only when that backend's receipt says so. Ingest, share-session, and the evolve pass all enter here, then the lifecycle ledger records the acceptance. The memory engine runs the embed and graph work. This is not a separate service: it runs inside the FastAPI process.
The only seat-to-Central path. A candidate is secret-scanned and reviewed, then a person approves it from the dashboard, MCP, or the CLI. The evolve pass can enqueue candidates; it does not copy your Node on its own. Promotion is opt-in on the server. Approved bytes dual-write into Central. This is the Promotion step on the PATH.
A scheduled pass inside the web service, off by default, interval set by the operator. Stages run in order: GitHub sync, repo content, self-improve, promotion, Linear sync, then a verified cognify on the same process. This is not a cron phrase on the diagram: the default lives in config and operators change it. Outputs land in Central (org sources) or your Node (seat-scoped Linear mirrors).
Citadel handles embeddings and graph operations through this engine. Storage, access, sync, and the UI stay Citadel's. add is the fast write (no graph). cognify projects into Qdrant and Ladybug. Search and mesh both read through this client. The lifecycle ledger is what Citadel believes; the engine is how a backend is filled.
Seats, hashed tokens, roles, capture policy, and the promotion queue live in a JSON store outside the memory engine, so a graph rebuild cannot rewrite who is allowed to read. The seat-bound token at the edge is minted and checked against this store.
Storage
Your own memory, one dataset per seat. Capture hooks, citadel capture, ingest, and the Node copy of a share-session land here first. No other seat can read it. Linear issues assigned to you can mirror here. Promotion is the only way a note leaves this dataset for Central. Physically the bytes live in SQLite, Qdrant, and Ladybug, keyed by this dataset.
The organization's shared memory. It only ever holds what was promoted into it, plus what the evolve pass ingested from GitHub, repo content, and org-visible Linear. That is what keeps it small enough to trust. MCP tokens stay read-only on Central. Physically the same three stores, different dataset.
Ingest is an acceptance: source bytes, the revision head, projection jobs, and per-backend receipts commit in one SQLite transaction. A document is searchable in a backend only when that backend's receipt says so. Relational, vector, and graph are the three required backends (SQLite · Qdrant · Ladybug). Recovery replays failed jobs from this ledger, not from the internal engine.
The live relational store at head (DB_PROVIDER=sqlite in kb/lite_runtime.py). Rows, dataset membership, and the lifecycle ledger live here. Not Postgres. The three live stores together are SQLite · Qdrant · Ladybug. Search uses these rows after the vector and graph recall, under the same seat scope.
The live vector store: a separate Qdrant service (VECTOR_DB_PROVIDER=qdrant). Embeddings come from BAAI/bge-small-en-v1.5, baked into the image, so nothing is downloaded at boot. citadel_search starts here, then expands through Ladybug and filters through SQLite.
The live graph store (GRAPH_DATABASE_PROVIDER=ladybug). One Ladybug store per dataset; an org-wide mesh read merges the per-dataset stores. Mesh and graph expansion on search read here. Not Kuzu, not pgvector.
Sync sources
The organization's repositories sync as one stage of the evolve pass. Commits, pull requests, and issues land as org knowledge in Central, not as yours. This is a scheduled pull from the web service, not a GitHub App and not a webhook (the webhook flag is off by default).
Readmes, architecture decision records, and docs from org repositories are ingested as content, not just as filenames. Same evolve pass as GitHub metadata, landing in Central.
Linear issues assigned to you mirror into your Node. Org-visible issues go to Central during the evolve pass. Your own work stays yours; the org sees what was already shared.
A linked Obsidian vault mirrors into your Node. Push and pull are both implemented, so markdown notes you already keep are searchable alongside capture. Vaults are seat-owned: another seat addressing your vault by id gets 404, not 403.
You and your agents read via MCP, CLI or web: your Node plus Central, never another seat's.
Your Node
Everything you capture lands here. No other seat can read it, and no job promotes it into shared memory. Sharing is an act, not a setting.
Central
The org's shared memory only holds what a person promoted into it, so it stays worth trusting instead of everyone's scratch notes.
Claude Code, Cursor, or your own MCP client, same seat, same read isolation.
A commit, an issue, a session. Check the claim instead of taking the vault's word.
Citadel is a FastAPI service over a retrieval layer, but the moat is the governance around it.
citadel promotion).You install once. After that the interesting part is what you do not have to do.
A session hook and a git pre-push hook feed your Node while you work, and the evolve pass syncs the org's GitHub and Linear. Nothing to file, nothing to remember to save.
citadel search and the MCP tools read your Node and Central together, and tell you which one answered.
When something is worth the whole org knowing, you promote it. Until then it stays on your seat, out of reach of the rest of the org and of their agents.
Run it on your own work. Install the CLI, hand it a seat token, and your agents search the same memory you do. Self-hosted and Apache-2.0, so you can read every line of what it does.
Build it into your project. utxo AG joins consortia as a work-package partner, bringing the vault and the team that wrote it.
You need a seat token from us to try the live node. This is not a public sandbox. Contact us, we send an access token, then install the CLI and the agent skill.