Documentation

Metatron captures your codebase's real implementation decisions as structured decisions and serves them to AI coding agents over MCP. Bootstrap once, curate what's worth keeping, serve it to your agent — and let the agent's feedback feed the next round of candidates.

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.

Nothing becomes canonical without a human. A canonical decision is one a human has approved — the only decisions Metatron serves to agents. Bootstrapped, agent-submitted, and feedback-refined decisions all start as candidates for curation. None self-promote.

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

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.

the loop
            ┌─────────── 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:

installation
$ 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:

installer script
$ curl -sSf https://getmetatron.com/install.sh | sh

To run it locally from source or contribute to the project, clone and sync instead:

build from source
$ git clone https://github.com/kerbelp/metatron.git
$ cd metatron
$ uv sync            # create venv and install dependencies

Run with Docker

A Dockerfile is included (it's also what the Glama.ai listing builds). The image's entrypoint is the metatron CLI and its default command serves the MCP server over stdio, so docker run with no arguments starts the server.

build
$ docker build -t getmetatron .

Decisions live in a SQLite database, so mount a volume to persist it across runs. Ingest a repo, then serve the curated decisions:

ingest + serve
# 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 \
    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 \
    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:

.mcp.json
{
  "mcpServers": {
    "metatron": {
      "command": "docker",
      "args": ["run", "-i", "--rm",
               "-v", "metatron-data:/data",
               "-e", "METATRON_DB=/data/metatron.db",
               "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):

.env
ANTHROPIC_API_KEY=sk-ant-...

Non-secret settings live in an optional metatron.toml. Environment variables METATRON_DB / METATRON_MODEL override it.

metatron.toml
[metatron]
db_path = "metatron.db"        # one SQLite file holds many repos
model   = "claude-sonnet-4-6"  # default extraction model

Quick start

three steps
$ 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.

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.

ingest
$ 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
FlagDefaultMeaning
--max-commits N500how much git history to read
--since DATEonly commits after e.g. 2024-01-01
--path SUBTREElimit ingest to a subtree, e.g. src/components
--repo IDorigin remoteoverride 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. One DB holds many repos; each is isolated on retrieval.

candidates

Review and curate — humans decide what becomes canonical.

candidates
$ 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.

triage
$ 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).

serve

Expose canonical decisions to agents over MCP (stdio). One served instance serves exactly one repo (--repo, the id printed by ingest), so an agent only ever sees that repo's decisions. It also records usage events to the same DB for the UI.

serve
$ metatron serve --repo github.com/acme/app
Normally you don't run this by hand — an MCP-capable agent launches it. See Connect an agent.

ui

The local curation web UI. Binds to localhost (bumping to the next free port if taken) and reads/writes the same store as the CLI.

ui
$ metatron ui
Metatron curation UI on http://127.0.0.1:1337  (Ctrl-C to stop)
  • Decisions — browse paginated; filter by status / scope / triage / origin; full-text search; approve/reject with a click.
  • Usage — how often agents query, coverage, most-queried scopes, recent queries.
  • Quality — decision quality by origin (ingest vs feedback) and one-time ingest cost.
  • Feedback — the agent feedback stream, filterable All / Unhandled / Handled, with a Refine into decisions button per report.

Flag: --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.

refine-feedback
$ 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 and check for an available update.

version
$ metatron version
metatron 0.7.0 (rev a3f1c2d)
→ update available: 0.8.0  (run: uv tool upgrade getmetatron)

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. The upgrade command shown matches how you installed (uv or pip); override it by setting METATRON_INSTALL_CMD or by editing ~/.metatron/install.json.

Connect an agent

So a coding agent reliably consults decisions rather than rediscovering conventions, run the onboarding script from inside the target repo:

onboarding
$ 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 UserPromptSubmit hook in .claude/settings.json that re-injects the directive every turn.
  • A Stop hook that reminds the agent (once per session) to call submit_feedback when it consulted Metatron but never sent feedback.
  • The metatron MCP server in .mcp.json.

Manual MCP client config

If you wire the server up yourself instead of using the script:

For PyPI / Global Installation:

.mcp.json
{
  "mcpServers": {
    "metatron": {
      "command": "metatron",
      "args": ["serve", "--repo", "github.com/acme/app"]
    }
  }
}

For Local Clone / Development:

.mcp.json
{
  "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

ToolPurpose
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)

A get_decisions_for_context call returns context like this:

served context
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, and candidates are fully local and need no API key.
  • No decision self-promotes — a human curates everything that becomes canonical.
Want a hosted version instead of running it yourself? Get in touch →