pgverdict
Status: pre-alpha, feature-complete for v1. All four milestones work against the bundled testbed: M1 (hotspots, plan explanation, dead-weight detection), M2 (grounded HypoPG index simulation), M3 (measured verification on a disposable clone, with a write-cost benchmark and regression check) and M4 (evidence-carrying migrations, auto_explain parameter recovery, weekly digest). Not yet released to PyPI beyond a name-reservation placeholder.
Postgres performance MCP server with a verification loop. Instead of "I think this index will help", pgverdict aims for:
"This index reduced query X from 340 ms to 18 ms on a data clone, cost ~0.3 ms per write across 3 400 writes/day, no regression across the top 20 queries — here is the migration."
Every recommendation carries evidence. When evidence cannot be produced, the tool says so explicitly instead of guessing. A recommendation without a measurement is a bug, not a feature.
Why
Small teams run production Postgres without a DBA. When something gets slow they either ask an LLM and apply a plausible-sounding index blind, or open a dashboard they lack the expertise to interpret. Existing index advisors emit suggestions from planner cost estimates — they don't measure the result, don't account for write amplification, and don't check whether the new index regresses other queries.
pgverdict is an MCP server: the agent (e.g. Claude Code) drives the iteration, pgverdict provides the method — identify, ground, simulate, measure, check regressions, and only then deliver a verdict with the migration.
The verification loop
- Identify — rank real hotspots from
pg_stat_statementsand table/index statistics - Ground — recover realistic bind parameters (real values matter: three orders of magnitude can hide behind a
$1) - Simulate — HypoPG virtual index,
EXPLAINcost delta — estimates only - Measure — real index on a data-bearing clone,
EXPLAIN (ANALYZE, BUFFERS)— estimates become evidence - Regress — re-run the top-N workload, estimate write amplification, produce a net verdict
Every tool output carries an evidence_level: estimate_only | simulated | measured. Only measured results can become a verdict and a migration.
Safety posture
- Local developer tool, stdio transport, no listening port
- Production is opened read-only (
pg_monitor-based role, read-only transactions, strict timeouts); no code path writes to production - Generated migrations are files, never executed
- Database-derived text is treated as data, never as instructions; literals are redacted by default
Try it in five minutes (no real database needed)
The repo ships a synthetic testbed — a Docker Postgres with a multi-tenant schema, a workload generator, and deliberately planted pathologies (a missing index, a dead index, duplicate and prefix-redundant indexes, a heavily skewed tenant). It doubles as the acceptance-test suite: every pathology must be findable by the corresponding tool.
git clone https://github.com/Svaca33/pgverdict && cd pgverdict
docker compose -f testbed/docker-compose.yml up -d --wait
uv run pgverdict-workload --iterations 300
Then register the MCP server with Claude Code (from the repo directory):
claude mcp add pgverdict --env PGVERDICT_PROFILES=./testbed/profiles.toml -- uv run pgverdict
and ask things like "what are the hotspots in the testbed profile?" or "is there dead weight among the indexes?". To point it at your own database, write a ~/.config/pgverdict/profiles.toml (see testbed/profiles.toml for the format) — a read-only role is all it needs.
MCP tools (M1)
| Tool | What it does |
|---|---|
list_profiles |
The configured target databases; every other tool requires an explicit profile |
list_hotspots |
Queries ranked by total execution time (frequency × cost) from pg_stat_statements |
explain_query |
EXPLAIN by SQL or queryid, with a plain-language reading of what's expensive |
find_dead_weight |
Never-scanned indexes, exact duplicates, prefix-redundant pairs, low leaf density |
propose_index |
Candidate indexes cost-simulated with HypoPG, grounded from pg_stats (typical + worst + selective case). evidence_level: simulated — never a recommendation |
verify_index |
The verdict: real CREATE INDEX on a disposable Docker clone, EXPLAIN (ANALYZE, BUFFERS) before/after with grounded parameters, a measured write-cost micro-benchmark, and a regression check across top queries. evidence_level: measured, ACCEPT/REJECT with reasons |
recover_parameters |
Real production parameter values from an auto_explain log (jsonlog or stderr format) — always a better grounding source than statistics |
generate_migration |
Turns an ACCEPT verification into a migration file (raw SQL / Alembic / EF Core): CREATE INDEX CONCURRENTLY with the measured evidence embedded as a comment. Refuses non-ACCEPT verdicts; overrides are stamped into the comment |
There is also pgverdict-report — a CLI for cron/Task Scheduler that writes a markdown digest (hotspots, dead weight, simulated candidates) with no server and no port:
pgverdict-report --profile myapp-prod --out reports/weekly.md
Every response echoes profile + environment and carries an evidence_level (estimate_only / simulated / measured). Only measured results carry a verdict: net_ms_per_day = Σ Δread × reads/day − Δwrite × writes/day, REJECT on any top-query regression. Clones are provisioned per verification (clone_provider = "docker") and always destroyed afterwards — data never leaves your machine, and never lingers on it either. Text values sampled from pg_statistic are redacted by default (redact = false per profile to opt out).
Roadmap
- M1 — hotspot listing, plan explanation, dead-weight (unused/duplicate index) detection; bundled Docker testbed with a synthetic workload so you can try it in minutes without risking a real database
- M2 — HypoPG simulation and index proposals, parameter recovery
- M3 — data-bearing clones and real measurement with regression checks
- M4 — migration generation,
auto_explainparsing, weekly report mode
See docs/pgverdict-spec-v0.3.md for the full working spec.
License
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pgverdict-0.1.0.tar.gz.
File metadata
- Download URL: pgverdict-0.1.0.tar.gz
- Upload date:
- Size: 108.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6a5d12e12108849b1f82b77a4b031d23a72823c208eebc16637b869829a9db7f
|
|
| MD5 |
711d17d164c2b775edde3fd25ad2dc7d
|
|
| BLAKE2b-256 |
28efc0f6c1c21c6ff248c262e71bc18fd9a876cb02a486be1da88224219798b8
|
File details
Details for the file pgverdict-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pgverdict-0.1.0-py3-none-any.whl
- Upload date:
- Size: 42.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
53da4960b1edbaa16bdf9437e6e1121bd7b98df269e3f09292539f71689ea9b2
|
|
| MD5 |
37bd2d6911bc37454b144b85cc38bcdb
|
|
| BLAKE2b-256 |
7b620eaa9119d387224bc35bf7eba517d2b993c8e4c624d694b04903df4f9b20
|