The engine of an LLM Wiki: a compounding, git-versioned knowledge base of synthesized, cross-linked Markdown pages, written and maintained by a model and read by both people and agents. It is not a vector database, and there are no embeddings in it. Knowledge is synthesized once into pages and kept current, instead of being rediscovered from raw sources on every question.
This repository holds the code. Your pages, your captures and your own
scripts live in a data directory you own, and the two find each other through
one file, syntopica.config.json. Nothing here knows whose wiki it is running
against.
brain indexrebuildsindex.mdfrom every page'ssummary:line, so the map is derived from the pages rather than maintained beside them.brain findanswers where a question is already answered: the ranked pages, and on each one the heading and the line that carried the words. The same model-free keyword baselinetools/evalmeasures, over the configured page directories only -- so it never walks the captures beside them, which is what makesgrep -runusable once a wiki has an archive.brain graphbuilds the link graph: orphans, dangling links, clusters reachable from nothing, and related-but-unlinked pairs scored by shared vocabulary. It writes an HTML viewer alongside the report.brain lintchecks the conventions this engine enforces - frontmatter, filenames, summaries that exist, links that resolve, and whether the index is current. Orphans arebrain graph's report, not a lint failure.brain doctoranswers whether this instance is set up: configured paths present, repositories where the configuration says, the API versions supported, the executables and credentials the commands need.- Machine-readable output for a dashboard or a script. Each document carries
"schemaVersion": 1and exits 0 once it is printed; findings are fixed codes, never messages, so a reader can store them without page content.brain lint --jsongivesissues(page,code) andindexStale;brain doctor --jsongiveschecks(name,ok,code), and--skip NAME(repeatable) reports a check as passing with codeskipped, for a poller that deliberately runs without credentials;brain graph --json --no-htmlgives nodes (id,type,degree), edges, orphans and dangling links and writes nothing;brain graph --json --related --limit Ngives the top N related-but-unlinked pairs; `brain page --json --id /` gives one page's frontmatter, body (capped at 1 MiB) and links, and refuses any id outside the configured page directories. tools/evalmeasures retrieval over your own wiki: a query set, keyword and PageRank scoring, and recall@k, so a change to the page conventions can be judged rather than argued about.
There are no embeddings in this engine, so a brain-only instance searches by
words: brain find over the pages' own text, and the link graph for what a page
connects to. That is the whole retrieval surface, and it is enough for "which
page says this" -- but it will not find a paraphrase, and it will not answer a
question asked in another language than the page.
Semantic search over these same pages comes from
atrium, which indexes the wiki beside
your agent conversations and serves both over one call. Declare it under
engines.atrium in syntopica.config.json and brain doctor says which of the
two you have:
PASS retrieval: keyword only (`brain find`); add the atrium engine for semantic search
PASS retrieval: keyword (`brain find`) and semantic (atrium)
Neither line is a failure. A wiki with no semantic lane is a supported instance; a session assuming a paraphrase would have been found is the problem this line exists to prevent.
The engine never runs inside your data: this repository is one checkout, your
wiki is a directory of its own, and one file, syntopica.config.json, tells
the engine where the pages are. The quickest route is the
Syntopica hub, which writes that file
and the directories the schema expects:
uv tool install git+https://github.com/syntopica/syntopica
mkdir -p wiki/engines && cd wiki
git clone https://github.com/syntopica/brain.git engines/brain
(cd engines/brain && uv sync)
syntopica init --with brain
cat > pages/start.md <<'PAGE'
---
title: Start
type: concept
updated: 2026-09-16
summary: 'The starting point for this wiki.'
sources: []
---
Decisions live in [[pages/decisions]].
PAGE
cat > pages/decisions.md <<'PAGE'
---
title: Decisions
type: concept
updated: 2026-09-16
summary: 'Decisions recorded as linked pages.'
sources: []
---
Back to [[pages/start]].
PAGE
engines/brain/bin/brain index # write index.md from your pages
engines/brain/bin/brain graph # orphans, dangling links, related pairs; writes graph.html
engines/brain/bin/brain lint # frontmatter, filenames, summaries, links, index freshness
engines/brain/bin/brain doctor # what is still missing, by nameExpect index.md: 2 pages, pages 2 links 2 orphans 0 dangling 0, zero
lint issues and a passing doctor. Links carry the page directory, as in
[[pages/decisions]]; a bare [[decisions]] resolves when exactly one page
carries that filename.
A brain-only instance needs no other checkout: the Clips engine belongs to the
clips component, and building an index, a graph or a lint report never asks for
it. The hub's brain-only quickstart above is the tested route, and it keeps
data and engine source apart - engine checkouts go under the data directory's
ignored engines/, while the manual layout below uses sibling checkouts.
Without the hub, write syntopica.config.json by hand from
schema/syntopica.config.example.json, keeping only the brain and
engines.brain sections, and run git init in the data directory. doctor
then names every directory and file it still expects.
Every command takes --data PATH to select an instance explicitly. Without it,
SYNTOPICA_DATA is used, and without that the commands walk upwards from the
working directory to the nearest syntopica.config.json, stopping at a
repository boundary so one instance can never be read while standing in another.
schema/syntopica-config.schema.json is the authority: a closed schema, so an
unknown key is an error rather than a setting that silently does nothing.
schema/syntopica.config.example.json is a complete instance to copy from.
Paths resolve relative to the file that declared them, which is what lets a
local override sit beside the tracked configuration without either one guessing
about the other. syntopica.local.json, when present, overlays the tracked file
and belongs in .gitignore.
SCHEMA.md is the page format the engine expects. CLAUDE.md is what a coding
agent working on this repository needs to know.
Python 3.12 or newer with uv, and Git.
brain graph writes a self-contained HTML file and needs no server.
MIT. See LICENSE.