Skip to main content

Operating SchemaBrain over time

init got you a working agent. This page covers what you do after — inspecting the local store, catching drift before it shows up as bad agent answers, previewing re-index costs, and the Docker-only path. For live observability (tail, audit log, OTel, PII refusal), see docs/observability.md.

See your schema (dashboard)

schemabrain dashboard opens a read-only, 127.0.0.1-only view of the indexed store — a Knowledge Graph of your entities and joins, the PII matrix, refusals, the audit log, a (copy-the-CLI) policy view, and drift. It requires the [ui] extra:
pip install "schemabrain[ui]"
schemabrain dashboard --store-path ./schemabrain.db
The dashboard reflects what’s in the store — it never writes to your database or edits your YAML. Full surface tour: docs/dashboard/overview.mdx.

Inspect what’s indexed

See what the agent has — same view it has, no LLM call, no source connection:
schemabrain inspect
Your output will vary. Entity names come from Sonnet’s read of your schema (you’ll typically see user not customer on the bundled fixture); join names follow your actual FK constraints. Operate on what inspect prints, not the names in this sample.
◆ store · ./schemabrain.db
12 tables · 84 columns · 12 entities · 5 metrics · 11 joins

Definitions
├── Entities (12)
│   ├── api_key
│   ├── billing_profile
│   ├── invoice
│   ├── payment_method
│   ├── plan
│   ├── session
│   ├── subscription
│   ├── subscription_item
│   ├── support_ticket
│   ├── usage_event
│   ├── user
│   └── workspace
├── Metrics (5)
│   ├── total_revenue
│   ├── active_subscriptions
│   └── … (3 more)
└── Joins (8)
    ├── workspace_users
    ├── subscription_plan
    └── … (6 more)

Drill into one: `schemabrain inspect <name>`
Drill into one entity for the full detail view — columns, PII tags, and the joins that reach it:
schemabrain inspect user
◆ public.users · entity:user · binding id

Description:  A workspace member account (login credential + contact details).

Columns:
  id             bigint       not null  pk identity  public
  workspace_id   bigint       not null              public
  email          text         not null              pii (contact)
  full_name      text         not null              pii (contact)
  password_hash  text         not null              pii (credential)   ← catastrophic; never reaches the agent
  role           text         not null              public
  created_at     timestamptz  not null              public

Related entities:
  session    incoming  many_to_one  via `user_sessions`
      user.id = session.user_id
  workspace  outgoing  many_to_one  via `workspace_users`
      user.workspace_id = workspace.id
This is the operator’s counterpart to the agent-facing MCP tools — anything describe_entity returns to Claude, inspect shows you locally. Exit codes: 0 rendered, 1 drilled name not found, 2 operational refusal.

Detect drift

schemabrain check walks every persisted entity, metric, and canonical join and confirms each one still matches the live source schema. Two classes of change surface as a structured drift report — before they become bad agent answers:
  • Structural — a referenced table or column was dropped/renamed (table_missing, identity_column_missing, measure_column_missing, time_dimension_column_missing, join_column_missing).
  • Shape — a column still exists but its type or nullability changed since you indexed (type_mismatch, nullability_change), compared against the indexed baseline. These catch the silent-correctness traps a pure existence check misses (e.g. a numeric measure column flipped to text, so SUM/AVG now errors or coerces). Shape drift is reported without cascade-suppressing dependent definitions.
schemabrain check --url-env DATABASE_URL --store-path ./schemabrain.db
8 entities (7 healthy) · 12 metrics (11 healthy) · 5 joins (5 healthy)

  ✗ entity   customer
        identity_column_missing  public.customers.legacy_email
        → update entity 'customer'`s `identity:` field and re-run
          `schemabrain entities apply`

2 drifts detected.
Exit 0 when everything lines up, 1 when at least one drift is detected, 2 for operational refusals. Drift cascading is suppressed — when an entity’s bound table is missing, downstream metric and join drifts on that table are suppressed so the output stays focused on root cause. Pipe-friendly: schemabrain check --url-env DATABASE_URL --json | jq '.exit_code'.

Preview the cost of catching up

Schedule re-indexes confidently. schemabrain index --dry-run --since <duration> previews what a real run would cost — no DB writes, no LLM calls, no ANTHROPIC_API_KEY required — and adds a freshness audit showing how much of the local store is stale relative to the chosen cutoff:
schemabrain index --url-env DATABASE_URL --store-path ./schemabrain.db \
    --dry-run --since 14d
Would index 87 table(s): 4 changed, 83 unchanged, 0 removed. Columns: +12/~6/-0. Estimated LLM: 18 descriptions ($0.0054). Estimated embeddings: 18. No changes made to the store.
Stale since 14d: 42 columns across 9 tables (estimated refresh $0.0126)
The “changed/unchanged” line accounts only for the source diff since the last index run; the “Stale since” line flags columns whose owning table was last enriched before the cutoff — useful for catching tables that haven’t been re-indexed even though they haven’t structurally drifted. Accepts compact durations (30s, 5m, 2h, 14d) or ISO 8601 timestamps with timezone.

Run via Docker

If you don’t want a host Postgres install at all, the repo ships a docker-compose.yml that brings up a Postgres container with the bundled fixture, indexes it, and leaves you with a populated store on a named volume:
docker compose up
Note on ports. The compose stack binds Postgres to host port 5433 (not 5432) so it never clashes with a developer-local Postgres already running on 5432. The MCP wiring below talks to the container over the internal Docker network (postgres:5432), so the host-side port mapping doesn’t matter for the Claude Desktop integration.
Point an MCP host at the indexed store via docker run:
// ~/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "schemabrain": {
      "command": "docker",
      "args": [
        "run", "--rm", "-i",
        "--network", "schemabrain_default",
        "-v", "schemabrain_sb-data:/data",
        "-e", "DATABASE_URL=postgresql+psycopg://postgres:local@postgres:5432/postgres",
        "schemabrain:local",
        "serve", "--url-env", "DATABASE_URL", "--store-path", "/data/store.db"
      ]
    }
  }
}
The docker compose up recipe builds SchemaBrain from the repo’s Dockerfile, so a checkout is all you need. A pre-built multi-platform image (linux/amd64 + linux/arm64) on a public registry is on the v0.3.x roadmap so you can skip the build step. Full Docker setup (env-var hygiene, host-uid mapping, containerised serve config) is in /setup/docker.