Documentation
Metatron captures your codebase's real implementation decisions as structured decisions — git-tracked markdown files consulted by AI coding agents, curated through your ordinary pull-request review (the default, files-first mode). Prefer a serving layer? The same decisions ship over MCP with relevance ranking and an agent feedback loop. Metatron also records executable, human-reviewed verification contracts: how to prove a change works and what each failure means.
Overview
A decision is a typed record — pattern, scope,
rationale, confidence, source_refs — not a prose
doc. Metatron is self-hosted and runs against a private codebase: extraction sends only
structural signals (imports, decorators, base classes, commit subjects) to the
model, never raw source, and agent feedback is stored only in your local SQLite database.
How Metatron Compares
| Dimension | Code RAG (e.g., Cursor) | Code Graphs (e.g., Graphify) | Metatron (Decisions) |
|---|---|---|---|
| Primary Focus | Text similarity search | Code architecture & call chains | Intent, gotchas & conventions |
| Primary Data Source | Raw source files | Abstract Syntax Trees (AST) | Git logs + Developer feedback |
| What it Captures | What code is written where | How files/functions are connected | Why decisions were made |
| Curation Gate | None (fully automated) | None (fully automated) | Curated (Human-in-the-loop) |
| Best For | Finding code examples | System navigation & exploration | Writing code like a team senior |
The loop
In files-first mode the repo runs the loop by itself: agents consult
context/decisions/ before coding, author what they learn on their working
branch, and your PR review promotes or rejects. In MCP mode, bootstrap with
ingest, curate candidates into the canonical set, then
serve them to your agent over MCP. As the agent works it reports gaps via
submit_feedback; refine-feedback reshapes those gaps into new
candidate decisions — closing the loop on the conventions extraction can't see
(cross-file and workflow rules). Crucially, feedback returns as candidates, so
the human gate is never bypassed.
┌─────────── ingest ───────────┐ your repo ─┤ parse (tree-sitter) + git ├─▶ candidate decisions └──────── LLM extraction ───────┘ │ ▼ curate (human) ◀── triage (advisory) │ approve / reject ▼ coding agent ◀──── serve (MCP) ──── canonical decisions │ └── submit_feedback ──▶ refine-feedback ──▶ candidate decisions ──▶ curate
Install
To install Metatron as a global tool on your system:
$ pip install getmetatron # Or if you use uv: $ uv tool install getmetatron
Alternatively, you can use our installer script which handles Python, uv, and path configuration automatically:
$ curl -sSf https://getmetatron.com/install.sh | sh
To run it locally from source or contribute to the project, clone and sync instead:
$ git clone https://github.com/kerbelp/metatron.git $ cd metatron $ uv sync # create venv and install dependencies
Run with Docker
A prebuilt multi-architecture image is published as
kerbelp/getmetatron. Its entrypoint is the metatron CLI and
its default command serves the MCP server over stdio, so docker run with
no arguments starts the server.
$ docker pull kerbelp/getmetatron # Or build the included Dockerfile: $ docker build -t kerbelp/getmetatron .
Decisions live in a SQLite database, so mount a volume to persist it across runs. Ingest a repo, then serve the curated decisions:
# 1. ingest a repo into a persisted DB (needs an API key) $ docker run --rm \ -e ANTHROPIC_API_KEY \ -v metatron-data:/data -e METATRON_DB=/data/metatron.db \ -v /path/to/your/repo:/repo:ro \ kerbelp/getmetatron ingest /repo # 2. serve the curated decisions over stdio (no API key needed) $ docker run -i --rm \ -v metatron-data:/data -e METATRON_DB=/data/metatron.db \ kerbelp/getmetatron serve --repo <id>
ingest prints the <id> to pass to serve. The
-i flag on serve is required — stdio needs an open stdin. To point
a coding agent at the container, use it as the MCP command:
{
"mcpServers": {
"metatron": {
"command": "docker",
"args": ["run", "-i", "--rm",
"-v", "metatron-data:/data",
"-e", "METATRON_DB=/data/metatron.db",
"kerbelp/getmetatron", "serve", "--repo", "<id>"]
}
}
}
Configure
Secrets come from the environment only. The CLI auto-loads a
.env from the working directory (it never overrides an already-exported
variable, and .env is gitignored):
ANTHROPIC_API_KEY=sk-ant-...
Non-secret settings live in an optional metatron.toml.
Environment variables METATRON_DB / METATRON_MODEL /
METATRON_OUTPUT_LANGUAGE / METATRON_CONTEXT_DIR /
METATRON_REVIEW_GATE override it.
[metatron] db_path = "~/.metatron" # catalog dir: one .db file per repo model = "claude-sonnet-4-6" # default extraction model output_language = "english" # language of generated decisions context_dir = "context" # knowledge-base dir (files-first / mirror) review_gate = "pr" # pr (default) or candidates default_repo = "github.com/acme/app" # optional; repo set writes this
By default db_path is a catalog directory containing one self-contained
SQLite file per repository. Pointing --db,
METATRON_DB, or db_path at a file enters single-file mode,
which is useful for an exported repository database. Existing shared
metatron.db installations are split into the catalog automatically and
the original file is archived.
Quick start
$ metatron context setup # the repo now carries its own agent context $ metatron verification setup # optional: add verification contracts $ metatron ui --files # browse & curate the git bundle locally
Agents consult context/decisions/ before coding and author new decisions
on working branches; your PR review is the curation gate. Details in
Files-first mode. Want the serving layer
instead?
$ metatron ingest /path/to/your/repo # 1. bootstrap candidates (needs API key) $ metatron candidates list # 2. review … $ metatron candidates approve <id> # … and curate $ metatron serve --repo <id> # 3. serve canonical decisions over MCP
ingest prints the <id> to use for serve. To wire
it into a coding agent automatically, see Connect an agent.
repo
Inspect the repositories in the local catalog and optionally persist the default used by repo-scoped commands.
$ metatron repo list github.com/acme/app (canonical=606, candidates=290) (default) github.com/acme/lib (canonical=42, candidates=11) $ metatron repo set github.com/acme/lib # persist a default $ metatron repo unset # clear it
Repo-scoped commands resolve their target in this order: explicit
--repo, METATRON_REPO, the persisted default, the current
directory's normalized origin, or the sole repository in the catalog.
If several repositories remain possible, Metatron refuses to guess and lists the
available IDs.
ingest
Parses git-tracked source files (tree-sitter) and reads commit history, aggregates per-area signals, asks the model to infer decisions, and stores them as candidates.
$ metatron ingest /path/to/your/repo Ingested repo 'github.com/acme/app': parsed 214 files, read 500 commits across 38 scopes, created 271 candidate decisions. Review them with: metatron candidates list --repo github.com/acme/app
| Flag | Default | Meaning |
|---|---|---|
--max-commits N | 500 | how much git history to read |
--since DATE | — | only commits after e.g. 2024-01-01 |
--path SUBTREE | — | limit ingest to a subtree, e.g. src/components |
--repo ID | origin remote | override the repo identity |
Decisions are keyed by a repo identity derived from the origin
remote (constant across developers; a checkout path isn't), with a directory-name
fallback when there's no remote. Each repository has its own SQLite file inside the
catalog, and retrieval remains repository-isolated.
candidates
Review and curate — humans decide what becomes canonical.
$ metatron candidates list 1d2ab8e8… [high] (CheckoutSuccessRedirect (paid submit/finish flow)) After a paid submission completes, redirect to /my-dashboard/?thanks=1 … $ metatron candidates approve 1d2ab8e8… Decision 1d2ab8e8… approved. $ metatron candidates reject d672a984… Decision d672a984… rejected.
candidates list accepts --repo <id> and --scope <path>
filters. approve promotes a candidate to canonical; reject discards it.
triage
For large candidate queues, a separate LLM pass scores each candidate (recommended / borderline / not-recommended) with a reason, so you curate a ranked, pre-filtered queue. It does not curate — a human still approves.
$ metatron triage --repo github.com/acme/app Triaged 271 candidates: approve=88, borderline=96, reject=87 judge cost: ~$0.42
Flags: --repo <id> (limit to one repo), --limit N (max candidates to judge).
enrich-keywords
Backfill retrieval keywords on canonical decisions that do not have them. This improves lexical retrieval without changing decision status or crossing the human curation boundary.
$ metatron enrich-keywords --repo github.com/acme/app $ metatron enrich-keywords --limit 100
This is an LLM extraction step and requires ANTHROPIC_API_KEY. It does
not curate or promote decisions.
serve
Expose canonical decisions to agents over MCP (stdio). One served instance serves exactly
one repo, so an agent only ever sees that repo's decisions. Pass --repo
explicitly or let the normal repo resolution choose
from the environment, persisted default, current directory, or sole catalog entry. It
also records usage events to the same repository database for the UI.
$ metatron serve --repo github.com/acme/app $ metatron serve # infer the repo from context
ui
The local curation web UI supports both Metatron modes. Database mode reads and
writes the SQLite catalog; --files mounts the repository's git-tracked
OKF bundle.
$ metatron ui --files # files-first: the git bundle $ metatron ui # MCP/database mode: SQLite catalog Metatron curation UI on http://127.0.0.1:1337 (Ctrl-C to stop)
In files mode, promote and reject actions become working-tree edits
(git mv / git rm) for you to review and commit; the UI never
commits automatically. Knowledge Activity is reconstructed from git history.
- Impact — Agent Impact or git-derived Knowledge Activity, helpfulness signals, and the feedback loop.
- Knowledge — overview, searchable decisions, and the human-gated curation queue.
- Sources — decision origins plus ingest history, telemetry, and extraction cost.
Binds to localhost, advancing to the next free port when necessary.
Flags: --files, --root, and --port N (starting
port, default 1337).
refine-feedback
When an agent reports a missing convention via submit_feedback, this
reshapes those free-text gap reports into structured candidate decisions
(defaults to Opus, the higher-stakes step). Nothing it produces is canonical — it all
goes to curation.
$ metatron refine-feedback Refined 3 feedback report(s) into 13 candidate decision(s) for curation. refiner cost: ~$0.19
Flags: --repo <id>, --limit N, --model <name>.
version
Print the installed version, check for an available update, or upgrade in place.
$ metatron version metatron 0.13.0 (rev 33eb40f) $ metatron version --upgrade
The update notice is suppressed when already on the latest release, when running a
dev checkout, or when METATRON_NO_UPDATE_CHECK=1 is set. The PyPI check
is throttled to once every 24 hours and cached locally — it adds no latency to normal
commands. --upgrade uses the detected uv-tool or pipx install method. If
plain pip is ambiguous, it prints the command instead of risking a parallel install.
Override the command with METATRON_INSTALL_CMD or
~/.metatron/install.json.
Files-first mode
The default mode: no server, no API key, no MCP. In files-first mode the
git-tracked markdown under context/ is the source of truth and
the database is only a rebuildable serving index. By default agents author decision
files directly under decisions/ on a working branch; the pull request
that lands them is the human curation gate.
$ metatron context setup # onboard the current repo $ metatron context setup apps/web # monorepo: onboard one app $ metatron context setup --dir kb # custom knowledge-base directory name $ metatron context setup --review-gate=candidates # optional staging workflow
It is additive and idempotent — no MCP server, no hooks. It writes:
- A consult-first rule in
.roo/rules/, re-stated to the agent every turn. - Two skills in
.roo/skills/:context-okf-llm-ingest(author decisions as files — with any LLM, no API key) andcontext-okf-promote-candidates(the mechanical, human-gated promotion move). - The knowledge-base scaffold:
context/candidate/,context/decisions/, and a README. - A managed block in
AGENTS.md— appended to an existing file, never overwriting it. - A
CLAUDE.mdbridge (@AGENTS.md) so Claude Code sessions load the contract — headless Claude Code readsCLAUDE.mdonly. Your existingCLAUDE.mdis left untouched if it already references AGENTS.md.
The contract is a recipe, not a policy (since 0.12.0). The
consult-first block gives agents numbered steps with literal commands —
cat context.md, then cat context/decisions/<topic>.md
for the relevant files — because measured compliance with a prose contract was 2/20
for a local 8B model versus 20/20 for the procedural form.
The blog post has the full measurements,
including why "read the relevant files" silently fails on small models. If you
onboarded a repo before 0.12.0, re-run metatron context setup to refresh
the managed artifacts.
Default pr gate. The agent reads
context/decisions/ before touching code, then records a durable
convention directly in that directory on its working branch. It becomes canonical
only when a human approves and merges the pull request:
$ git add context/decisions/use-repo-pattern.md $ git commit && gh pr create # PR review is the curation act
Optional candidates gate. Agents instead stage
proposals under context/candidate/; a human promotes them with a
reviewed git mv. Use this when curation should be separate from feature
PRs or agents can write to the default branch.
$ git mv context/candidate/use-repo-pattern.md context/decisions/ $ git commit && gh pr create # promotion is reviewed
The selected gate is persisted as review_gate in
metatron.toml. Re-running setup with the other value refreshes every
managed rule, skill, README, and AGENTS.md block while preserving
hand-authored content. The canonical boundary stays human-gated in
both modes. The directory name is
context/ by default — configure another with
context_dir in metatron.toml,
METATRON_CONTEXT_DIR, or the --dir /
--context-dir flags (a legacy metatron/ bundle is still
recognized). No installed metatron? The equivalent script is
metatron_setup_files.sh in the repo.
files — maintain a git-authoritative knowledge base
Companion commands for authoring, validating, indexing, and measuring decision files
in files-first mode. Paths default to the configured
<context-dir>/decisions.
$ metatron files lint # validate decision files $ metatron files index # regenerate index.md $ metatron files new retry-policy --title "Retry policy" $ metatron files record --since "7 days ago" # update usage ledger $ metatron files report --days 30 # adoption, reuse, drift, curation $ metatron files check-fields --base origin/main --actor ci
record reads merged commit trailers into the usage ledger and rolls up
counts. report renders a Markdown digest for a time window.
check-fields enforces frontmatter ownership boundaries so human-owned
fields and CI-owned counters cannot overwrite one another.
mirror — decisions as a portable OKF bundle
Whichever mode you run, mirror moves decisions between the store and
the git-tracked bundle. Each decision is one markdown file with YAML frontmatter —
a valid Open Knowledge Format (OKF) v0.1 concept,
readable in any editor, renderable on GitHub, portable to any tool that speaks the
standard. The layout implements the
Repository Context Layer.
$ metatron mirror sync # DB -> files: write the bundle under context/ $ metatron mirror sync --okf # also emit an OKF concept index $ metatron mirror import # files -> DB: apply edits, promotions, new files
Human-owned fields (pattern, scope, rationale,
confidence) round-trip through the files; machine-derived fields (the
helpfulness score, retrieval keywords, timestamps) render read-only and edits to them
are ignored. sync is deterministic, and import detects
concurrent DB+file edits as conflicts instead of clobbering either side. A
hand-authored file with no id becomes a new decision at the
directory-derived status.
verification — Repository Verification Layer (RVL)
A verification contract is a git-tracked OKF file that records
how to prove a change works and what a failure implies. Contracts live under
<context-dir>/verification/, are scoped to a subsystem, and follow
the same human review gate as decisions. The agent that just built a feature drafts
the contract; a reviewer decides whether it becomes canonical.
$ metatron verification setup # AGENTS.md workflow + worked example $ metatron verification template # print the canonical skeleton $ metatron verification new auth --scope services/auth $ metatron verification audit # read-only contract lint $ metatron verification run # run every canonical contract $ metatron verification run --scope services/auth --tags smoke $ metatron verification run --dry-run # resolve and print; execute nothing $ metatron verification run --report junit --out report.xml
Each contract contains assumptions, setup, ordered checks, expected results, teardown, and a curated Failure Means section. The latter routes a red check to the subsystem or precondition most likely at fault instead of leaving the next engineer or agent to rediscover it.
Assertions
| Assertion | Example |
|---|---|
| Exit code | exit 0 |
| Substring | stdout contains wrote |
| Regular expression | stderr matches timeout after \d+s |
| JSONPath | stdout jsonpath $.accessToken exists |
| Shell escape hatch | shell test -f ./out/index.md |
metatron verification run, in its own foreground process and with its
own privileges. MCP exposes read-only contract retrieval and templates; it never
executes a contract. The optional --judge flag is a Phase 2 hook and is
skipped until a provider is wired.
See the complete contract format and security guide or the design introduction.
Team identity and database handoff
In MCP/database mode, Metatron stamps queries, submissions, and feedback with the local operator identity. Export and import move one repository's self-contained database between employees without requiring a hosted service.
$ metatron whoami $ metatron whoami --set-email you@corp.com --set-name "You" $ metatron export --repo github.com/acme/app --out app.db $ metatron import app.db
Identity is local metadata, seeded from git config and stored in
~/.metatron/config.toml; it is not an authentication server.
export creates a consistent compact snapshot. import merges
a repository database or catalog directory by ID, so repeating the same import is a
no-op and event attribution travels with the data.
Connect an agent
Files-first mode (the default) connects
any agent that can read a file — metatron context setup is the whole
onboarding. For MCP mode, run the script below inside the target
repo so the agent reliably consults the served decisions.
$ bash /path/to/metatron/metatron_setup.sh # or pass the repo dir as an arg
It is additive and idempotent — it adds (never deletes) four things to the target repo:
- A "query Metatron first" block in
CLAUDE.md(between markers). - A
UserPromptSubmithook in.claude/settings.jsonthat re-injects the directive every turn. - A
Stophook that reminds the agent (once per session) to callsubmit_feedbackwhen it consulted Metatron but never sent feedback. - The
metatronMCP server in.mcp.json.
Manual MCP client config
If you wire the server up yourself instead of using the script:
For PyPI / Global Installation:
{
"mcpServers": {
"metatron": {
"command": "metatron",
"args": ["serve", "--repo", "github.com/acme/app"]
}
}
}
For Local Clone / Development:
{
"mcpServers": {
"metatron": {
"command": "uv",
"args": ["run", "--project", "/abs/path/to/metatron", "metatron", "serve", "--repo", "github.com/acme/app"],
"env": { "METATRON_DB": "/abs/path/to/metatron.db" }
}
}
}
MCP tools exposed
| Tool | Purpose |
|---|---|
get_decisions_for_context |
the relevant canonical decisions as compact structured context, with a query_id to reference in feedback |
submit_feedback |
rate served decisions by [index] and report a convention Metatron should have known — captured for refine-feedback; never auto-applied |
submit_candidate_decision |
record a convention the agent learned as a new candidate (never auto-promoted) |
get_verification |
fetch canonical verification contracts for a scope and optional tags; declarations only, never execution |
get_verification_template |
return the canonical verification-contract skeleton so an agent can draft in the supported format |
A get_decisions_for_context call returns context like this:
metatron:query b1f2… · rev 1101886 (reference the query id in submit_feedback) [1] [medium] Record payment/sale events into the shared payments ledger when handling subscription billing. scope: src/routes/api/subscription why: A fix commit explicitly records sales into the payments ledger, establishing this as the expected billing-recording pattern.
Privacy
Metatron is self-hosted and built for sensitive, on-prem codebases:
- Extraction sends only structural signals — imports, decorators, base classes, commit subjects — to the model. Never raw source.
- Agent feedback and usage are stored only in your local SQLite database.
serve,ui, andcandidatesare fully local and need no API key.- MCP can read verification contracts and templates but can never execute them; only an operator or configured CI job can run a contract.
- No decision self-promotes — a human curates everything that becomes canonical.