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:
docs/dashboard/overview.mdx.
Inspect what’s indexed
See what the agent has — same view it has, no LLM call, no source connection:Your output will vary. Entity names come from Sonnet’s read of your schema (you’ll typically seeusernotcustomeron the bundled fixture); join names follow your actual FK constraints. Operate on whatinspectprints, not the names in this sample.
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 totext, soSUM/AVGnow errors or coerces). Shape drift is reported without cascade-suppressing dependent definitions.
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:
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 adocker-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:
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:
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.