Skip to main content

cite-citadel — an LLM-maintained, fully-cited personal wiki in the Open Knowledge Format, fed by a coding-agent CLI you already have logged in, with an MCP search server. Every fact is cited to its source; nothing is invented.

Project description

cite-citadel

CI codecov PyPI Python versions License: MIT

A fortress of cited knowledge. An LLM-maintained, fully-cited personal wiki — every fact is attested to its source, nothing is invented.

An LLM-maintained personal wiki in Google's Open Knowledge Format (OKF), with an MCP server (and a CLI that mirrors every MCP tool) so an AI can search and read it — a KISS, pure-Python 3.12 take on Andrej Karpathy's LLM-Wiki pattern.

Drop arbitrary files into raw/, in any sub-folder — if the agent CLI you use can open it, citadel can ingest it (few exceptions). One agentic CLI session per source folds it into a cross-linked OKF wiki under wiki/, routing each fact to the page it best fits and splitting/merging pages as the corpus grows rather than making one page per file. Built-in helpers cover the rest: Office text extraction, visual image reading, multi-pass folding for oversized files, duplicate-format dedup, and a record (with the reason) in wiki/sources/index.md for anything that can't be read. Every fact cites its raw/ source and the model uses only what is in raw/; an AI client then queries the synthesized wiki over MCP instead of re-reading your notes.

The CLI is citadel; the PyPI package is cite-citadel. The wiki/ directory is the database — no SQLite, no vector store. Ingest runs through a coding-agent CLI you already have (claude, copilot, or gemini), so it uses your existing subscription and needs no API key — that usage is under your account and your provider's terms (see License & third-party tools).

Three guarantees that hold as the wiki grows (full rules in citadel/rules/schema.md):

  • Stays organized — ingest merges, splits, and deletes pages by fit; it never piles up one page per raw file.
  • Links keep working — merges/renames repoint inbound cross-links; any dangling link fails citadel lint / citadel check.
  • Honest provenance — raw facts are restated faithfully and cite their source as [^sN]. A fact the model adds from its own knowledge must be labeled [^llmN], never disguised as a raw citation.

Quickstart

Ingest runs through a coding-agent CLI you already have — no API key, just your existing subscription.

uv init my-wiki && cd my-wiki
uv add cite-citadel
uv run citadel init
nano .env                 # pick your agent CLI (claude | copilot | gemini) — must be logged in
cp ~/notes/* raw/         # drop in anything your agent can open
uv run citadel ingest     # one agent session per source builds the cited wiki
uv run citadel view       # browse it offline

Every other knob is documented inline in the generated .env. A global install (uv tool install cite-citadel; plain pip install cite-citadel works too) drops the uv run prefixes; citadel doctor warns when a newer release is on PyPI and prints the update command matching your install (see docs/troubleshooting.md). On Windows, use uv run python -m citadel — the uv run citadel shorthand can be antivirus-blocked (see the contributor note below).

Local models. For a fully private wiki, point the same agent CLI at a local model (Ollama) so nothing you ingest ever leaves your machine or LAN — see Local models (Ollama).

Contributing? Run from a checkout: uv sync, then the portable uv run python -m citadel <subcommand> (identical on Linux/macOS/Windows and needs no .exe — on Windows, antivirus can quarantine uv's generated citadel.exe).

How it works

Three layers (Karpathy's split; citadel/rules/schema.md has the authoritative rules, which the ingest agent reads — referenced by path — every run):

  1. raw/ — immutable sources; ingest reads but never edits them.
  2. wiki/ — the LLM-owned OKF bundle: markdown pages with YAML frontmatter, routed by kind into concepts/, objects/, systems/, persons/, organizations/, projects/, abbreviations/, misc/, densely cross-linked, each fact carrying a citation. The reserved index.md, log.md, and sources/index.md are generated, not authored.
  3. citadel/rules/ — the schema/rules layer: schema.md (the format contract) + core.md (agent behavior) + per-lifecycle tasks/, per-file-type formats/, and agent-judged genres/ briefs. Editing them changes how the wiki is built with no code change. The rules live in the package so a pip install carries them.

Per-fact provenance is the load-bearing rule. Every factual sentence ends with a GitHub-Flavored Markdown footnote, defined in a trailing ## Sources section that links to the originating raw/ file:

Robusta has about twice the caffeine of Arabica.[^s1]

## Sources

[^s1]: [raw/coffee-guide.md](../../raw/coffee-guide.md) — coffee guide (ingested 2026-06-30)

This renders on GitHub, is trivially greppable, and needs zero custom tooling. A claim that can't be cited is dropped, never invented; conflicting sources produce a > [!CONTRADICTION] callout. The wiki/ folder also opens as-is as an Obsidian vault.

Every page's frontmatter records when it last changed and which cite-citadel release wrote it (timestamp + citadel_version, both stamped automatically), and citadel curate --stale-rules refreshes pages whose sources were ingested under an older rulebook. For a full audit trail, git init the wiki/ folder once (or set CITADEL_WIKI_GIT=1): citadel then auto-commits the wiki after every ingest/curate run — each change a reviewable diff — and can push to a remote (GitHub/GitLab) via CITADEL_WIKI_GIT_REMOTE. See docs/configuration.md § Wiki history.

Test corpora

Nine synthetic corpora live under corpora/, each ingestible on its own or all together and each shipping its own committed, CI-linted showcase wiki at corpora/<name>/wiki/:

  • beverages — the everyday coffee + tea showcase: overlapping facts that repeat, contradict, and hide in one place, plus a planted false sourced claim.
  • kelvarra — a coherent fictional world whose facts contradict reality, graded to appear as stated, cited, never corrected.
  • leuchtfeuer — a three-year programme ingested in dated waves: reconcile / delete / force, temporal supersession, German→English, attributed opinions.
  • pemberley — all of Pride and Prejudice as one ~730k-char source: large-source multi-segment chunking, relationship extraction, narrative supersession.
  • injection-resistance — mundane documents with adversarial instructions embedded, which the agent must treat as content and never execute.
  • clockwork — a whole git repository folded in as one digest (CITADEL_REPO_SUPPORT), with a second commit driving repo-reconcile: folder-keyed provenance and a documented default superseded.
  • flurfunk — informal genres (a chat export, a tweet thread, an interview, a job application, a forum thread): attribution kept intact ("X said Y" ≠ "Y is true"), in-thread reversal, and a CV timeline.
  • gazette — PDF sources (deterministically generated by a committed stdlib script): grades CITADEL_PDF_MODE text-vs-images (a figure-only number and an image-only page appear only when figures are read), the academic-publications genre, and references-are-not-sources.
  • kontor — binary Office documents (OOXML .pptx/.docx/.xlsx + legacy OLE .doc/.ppt/.xls, deterministically generated by a committed stdlib script): the Office text-extraction path, an embedded-chart image delta (CITADEL_IMAGE_SUPPORT), dedup-by-basename, and ignore-patterns.

These are test inputs, not reference material. Every wiki here is machine-generated by an LLM agent from the raw sources, and some corpora deliberately contain planted errors, contradictions, or entirely fictional "facts" — do not treat any of them as real-world knowledge.

See it without running anything: browse a showcase wiki on GitHub (e.g. corpora/beverages/wiki/index.md) or the interactive live demo gallery — one viewer per corpus. verify-corpus grades each against a hidden answer key it never sees; per-corpus detail lives in each corpora/<name>/README.md and CLAUDE.md.

Coverage matrix — which corpus exercises which capability

Each corpus targets a few capabilities hard rather than all of them shallowly; together they cover the pipeline. = a primary, load-bearing test of that capability; = present as a secondary check. (Bev = beverages, Kel = kelvarra, Leu = leuchtfeuer, Pem = pemberley, Inj = injection-resistance, Clk = clockwork, Flu = flurfunk, Gaz = gazette, Kon = kontor.)

capability Bev Kel Leu Pem Inj Clk Flu Gaz Kon
Single-source facts survive + cited
Cross-source merge / co-citation
Multi-source synthesis (answer needs ≥2 files)
Contradictions surfaced, not silently resolved
Near-miss / approximation ≠ contradiction
Counterfactuals kept as stated + cited
Temporal supersession (dated change)
Delete / reconcile / force lifecycle
Whole-repo digest
Large-source multi-segment chunking
Attribution ("X said Y" ≠ "Y is true")
Injection treated as content, never executed
Image-only fact behind a mode flag (PDF / Office media)
Office text extraction (OOXML + legacy OLE)
Dedup-by-basename + ignore-patterns
Cross-language carry-through (DE→EN)
Entity-spelling variance → one node
Relative-date resolution
Distractor noise / filler resistance
Locator precision (lines / § / page)
Abbreviations (defined + undefined-flagged)

Model results — Opus / Sonnet / Haiku

The same corpora double as a model benchmark: because grading is retrieval-first against a hidden answer key, a stronger and a weaker model produce measurably different wikis from identical inputs. The bench-model skill ingests a corpus with a pinned CITADEL_INGEST_MODEL, grades it, and applies a discriminative tier (locator precision, oblique-query retrieval, merge quality, judgment delta on contradictions + planted-false claims). It writes a per-run results file whose rows populate the cells below.

Scoring per cell: hard = passes every hard gate of that corpus's ground-truth; degrades = structurally valid but misses judgment-heavy work (uncaught contradictions, an adopted false claim, partial supersession); fail = a hard structural gate broke (a fabricated source, a non-zero check/lint); = not yet benchmarked on the current (hardened) corpora.

corpus Opus Sonnet Haiku
beverages hard¹ degrades²
kelvarra hard² hard² fail²
leuchtfeuer
pemberley
injection-resistance hard² hard² degrades²
clockwork
flurfunk degrades²
gazette hard² hard² degrades²
kontor hard² degrades² degrades²

¹ From the 2026-07 audit on the pre-hardening beverages corpus: Sonnet cleared the structural + judgment gates with no wiki-defects on its subset. The hardened corpus has not been re-run on Sonnet yet.

² From the 2026-07 three-tier benchmark: one pinned-model ingest per cell into a fresh sandbox (gazette in images PDF mode, kontor with image support on), graded strictly against the hidden answer key. The one-line rationales: kelvarra × Haiku fail = two abbreviation expansions invented and cited as if sourced (plus two dropped counterfactuals); kontor × Opus is the only run that read the embedded chart (the pixels-only 34.2 % gross margin) and surfaced the 142-vs-138 headcount conflict, both of which the kontor Sonnet ingests missed; every other Opus/Sonnet cell sits at or near its corpus's ceiling. Cells still are open — run bench-model <corpus> <model> to fill one.

How the three tiers actually differ

Opus is not uniformly better — the tiers separate on different axes, and whether the next tier up buys anything depends on the corpus.

Haiku is structurally reliable everywhere: check/lint green, every fact cited, dedup and ignore-patterns honored, and it resisted every embedded injection. It degrades on judgment and craft, and in one characteristic way it breaks: where a source leaves a gap that invites completion, it fabricates — kelvarra's never-expanded abbreviation got an invented full name cited as if sourced (the benchmark's only fail). Beyond that it drops facts buried in compound sentences or terse intraday reversals, flags a rounded restatement as a contradiction while missing a real one, writes locators that don't resolve (~half its sample: truncated or invented headings), fragments entities into thin micro-pages, and reads nothing visual.

Sonnet adds the judgment layer: on kelvarra, gazette, and injection-resistance it is at or near each corpus's ceiling — all seven counterfactuals preserved-as-stated and cited, contradictions surfaced as callouts, the preprint attributed and flagged not-peer-reviewed, boilerplate excluded, locator samples 10/10 precise. Where Haiku fabricates, Sonnet leaves the gap honest (the abbreviation stays unexpanded). Its measured weakness is reliability on cross-modal work: in two of three kontor ingests it never opened the extracted chart image (missing the pixels-only 34.2 %) and let the 142-vs-138 headcount conflict coexist unflagged — though the committed kontor showcase (also Sonnet) caught the chart, so this is a reliability gap, not a hard capability wall.

Opus did the hardest cross-modal work in one pass: it read the embedded chart and made the headcount tension explicit, catching all six kontor judgment traps, and added judgment beyond the answer key elsewhere (a second, temporal contradiction in gazette plus an honestly-labeled physics resolution of the area conflict). But it is not strictly better: Sonnet's kelvarra locator sample was cleaner (10/10 vs 8/9), Sonnet documented all four injections where Opus documented two, and Opus half-leaked one gazette boilerplate line that Sonnet kept out entirely.

So: does it depend on the corpus? Yes. The judgment corpora (kelvarra, gazette, injection-resistance) separate Haiku from Sonnet and are saturated above that; kontor — vision plus cross-source diligence over binary sources — is currently the only corpus that separates Sonnet from Opus; beverages' stretch tier (locator precision, fragmentation) separates Haiku's craft even when its hard gates hold. One caveat: each cell is a single non-deterministic ingest, so neighboring cells should be read as ties unless the delta reproduces (kontor × Sonnet's missed chart did, twice).

A defect every tier shares points at the rulebook, not the model: all three models canonicalized a merged vendor to a minority spelling from someone's meeting notes, and both strong tiers anchored citations to headings that legacy-OLE extracts don't have — both are explicit rules now (core.md canonical-name direction, formats/office.md OLE line locators). Conversely, Haiku's remaining failures (invented expansions, dropped buried facts, unread charts) persisted under already-clarified rules — that is capability, not clarity: rules help the models that can follow them.

Practical default: CITADEL_INGEST_MODEL=sonnet. Step up to Opus when sources are image-heavy (CITADEL_IMAGE_SUPPORT=1, CITADEL_PDF_MODE=images) and the numbers in charts matter. Haiku builds a valid, findable, fully-cited wiki — but expect missed contradictions, sloppy locators, and the occasional confident invention where a source leaves a blank.

MCP server

citadel serve exposes twelve tools over stdio — eleven read-only (wiki_search, wiki_define, wiki_read, wiki_raw, wiki_neighbors, wiki_index, wiki_sources, wiki_tags, wiki_validate, wiki_lint, wiki_status) and one mutating (wiki_ingest) — each with MCP behavior annotations (readOnlyHint etc.) so a client can tell them apart. Every tool has a CLI counterpart (citadel read, citadel index, citadel lint, …), so an AI without MCP access can do everything through the shell.

Wire it into any stdio MCP client (Claude Desktop, Claude Code, a generic stdio client) by launching citadel serve (portably: uv run python -m citadel serve) with CITADEL_WORKSPACE set to your workspace. An AI then wiki_index()s to orient, wiki_search(...)es to find pages, and wiki_read(...)s for full cited context — answering from your synthesized wiki instead of re-retrieving documents. Copy-paste config and "if the server won't start": docs/mcp.md.

Reference

  • docs/ — the docs hub: an "I want to…" table pointing at configuration (every CITADEL_* knob), MCP setup, curate/status/maintenance, troubleshooting, the OKF format, and the founding idea.
  • CLAUDE.md — architecture notes for contributors.
  • CONTRIBUTING.md · CHANGELOG.md · SECURITY.md

License & third-party tools

cite-citadel is released under the MIT License.

Not affiliated. cite-citadel is independent — not affiliated with or endorsed by Anthropic, GitHub/Microsoft, or Google. "Claude", "GitHub Copilot", and "Gemini" are their owners' trademarks naming only the user-supplied CLI; full disclaimer in NOTICE.md.

Bring your own CLI — your account, your provider's terms. Ingest runs your authenticated coding-agent CLI under your account, governed by that provider's terms, not by cite-citadel: Anthropic Consumer / Commercial Terms, the GitHub Copilot product-specific terms, and the Gemini Code Assist / API terms (credential handling is covered in NOTICE.md above). Honest caveat: heavy, unattended, or CI ingest against a consumer subscription can hit rate limits or a provider's automated-use expectations — for that scale prefer the tier the provider designates for programmatic use.

Your wiki is yours. The providers assign output rights to you, and cite-citadel claims nothing over wiki/ content — publish the generated wiki freely.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cite_citadel-0.4.0.tar.gz (461.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cite_citadel-0.4.0-py3-none-any.whl (300.1 kB view details)

Uploaded Python 3

File details

Details for the file cite_citadel-0.4.0.tar.gz.

File metadata

  • Download URL: cite_citadel-0.4.0.tar.gz
  • Upload date:
  • Size: 461.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for cite_citadel-0.4.0.tar.gz
Algorithm Hash digest
SHA256 a02545f7332d7eeaba732e2fe1db89c648480fb258b8e3e2ad1f06fb5dec1309
MD5 146f05166d36bbec9192e7dbda8ee972
BLAKE2b-256 f0a771cebef34776bdb54ca05e5efedae8aab4a63ba776794a24d9c067cd0192

See more details on using hashes here.

Provenance

The following attestation bundles were made for cite_citadel-0.4.0.tar.gz:

Publisher: release.yml on MarkusNeusinger/cite-citadel

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cite_citadel-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: cite_citadel-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 300.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for cite_citadel-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ad51dbbe472e9722dc1f241daca63191824e8127c400c09650356ab6add6ba13
MD5 3fa5cd9473fcfc923e449e2900861d7a
BLAKE2b-256 96bb052c561a4ec281bafdacd16b4b58aeb6becc830a452b3803c1c32458f6fb

See more details on using hashes here.

Provenance

The following attestation bundles were made for cite_citadel-0.4.0-py3-none-any.whl:

Publisher: release.yml on MarkusNeusinger/cite-citadel

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page