pgbot: a read-only Postgres health check for agents and humans
Postgres intelligence for ai agents & apps
At a glance
- What is it?
- pgbot is a single Go binary that connects to PostgreSQL read-only and prints a findings-first health report. The design is sound for triage; it is not a monitoring platform.
- Who is it for?
- Adopt pgbot if you need a fast read-only answer about a Postgres instance you do not operate, or if you are wiring structured database findings into an agent through `pgbot mcp`. Do not adopt it as a replacement for pganalyze, Percona PMM or pgwatch: the README states plainly that it does not replace them, and there is no alerting, retention or multi-host rollup.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What pgbot is for, and who should care
The README positions pgbot as "in-database observability for PostgreSQL": one static binary that connects read-only, reads Postgres's own statistics views, and prints a findings-first health report plus what changed since the last run. The target user is not the person who owns a fleet. It is the engineer who has been handed a slow database, has no collector installed, and wants an answer in ten seconds. The README names three such situations: triaging a database you do not own, wanting an answer without deploying anything, and giving an AI agent structured Postgres findings it can reason over.
The scope is deliberately narrow. There is no agent, no external service, and no write privilege anywhere in the path. That last point is the whole pitch. A tool you point at a production database needs a permission story, and pgbot's is that the guarantee comes from the role, not from a flag you might forget.
Read-only by role, and why the flag is not the guarantee
pgbot's read-only promise is enforced by a `pg_monitor` login role with no write grants. Session pinning is described as defence in depth on top of that: `default_transaction_read_only`, `statement_timeout=15s`, `lock_timeout=2s`, and `BEGIN READ ONLY`. The ordering matters. If you create the role correctly, the session settings are redundant; if you create it carelessly, the session settings are what stops a runaway statement from holding a lock on a busy table. Neither layer is a substitute for the other, and the README treats the role as the primary control.
The second design decision is memory. Every run writes a local baseline, so from the third run on it reports what changed and why it matters: a query that got slower, a table that started sequential-scanning, an index that stopped being used. That baseline is local, which means the tool has state but no server. Copy the binary to a new machine and the history does not follow. For a CI job that runs on ephemeral runners, that is a real constraint: each fresh runner starts with no baseline, so the first runs cannot produce the comparison that is the tool's main differentiator.
Findings are computed in Go, and the AI layer only explains them
This is the part worth reading closely. The README states that every finding is computed in Go from SQL, and that the optional AI layer explains findings but never generates them. The deterministic path covers `inspect`, `queries`, `indexes`, MCP and CI, and needs no key at all. Nothing leaves your machine on that path.
The AI layer is opt-in and lives behind `pgbot ask` and `pgbot explain`. It accepts one model key from a set of environment variables: `OPENAI_API_KEY`, `GEMINI_API_KEY`, `ANTHROPIC_API_KEY` or `XAI_API_KEY`, or any OpenAI-compatible endpoint including local ones. The README's example output shows `pgbot ask "what's wrong?"` returning a plain-language reading with a likely cause and a recommendation.
The separation is the right call. A model that invents a finding about your production database is worse than no tool, and by keeping generation in Go the worst case for the AI layer is a bad explanation of a real fact. The trade-off is that the AI layer can only be as good as the findings the collectors produce; it cannot notice something the Go code does not look for.
Install and a first run
The README gives a curl install and a one-line invocation. The install script is served from the project's own domain, and the binary is static, so there is nothing to compile and no runtime to install first.
curl -fsSL https://pgbot.dev/install | sh
pgbot inspect "postgres://pgbot_ro@host:5432/db"If you would rather keep the connection string out of your shell history and out of `ps`, set it once in the environment and drop the argument. pgbot resolves the connection in a fixed order: the argument first, then `$DATABASE_URL`, then `$PGBOT_DATABASE_URL`, then `$PGSERVICE`.
export DATABASE_URL="postgres://pgbot_ro@host:5432/db"
pgbot inspectThe README notes a shell detail that trips people up: `export DATABASE_URL="…"`, with no `$` on the left and no spaces around `=`. It also points at PostgreSQL's connection service file: if your connections live there, `export PGSERVICE=mydb` and drop the argument too.
What you should see is a graded read. A four-row gauge strip of vital signs (cache hit, lock wait with the culprit query, rollbacks, idle index bytes as a share of the database), a `checked` line naming the subsystems that came back clean, a health score, then findings bucketed CRITICAL, WARNING and NOTE. `pgbot inspect --full` adds a subsystem status board plus section tables and per-finding caveats. The focused commands `indexes`, `queries`, `tables` and `vacuum` each drill into one signal.
For anything scripted, use `--json`. The README is explicit that the human-readable report is not a stable interface and that you should parse `--json`, not the terminal output. That contract is versioned at `1.2.0` with a JSON Schema published in the `schema/` directory, and breaking changes to it are treated as breaking changes to the tool.
If you prefer to build from source, the Makefile builds a static binary and installs it:
make build
make install PGBOT_INSTALL_DIR=/usr/local/binThe `build` target sets `CGO_ENABLED=0` and `-trimpath`, which is what makes the single-binary claim hold. The repository also ships a Dockerfile that wraps the release binary in `gcr.io/distroless/static:nonroot`, with the entrypoint set to `/usr/bin/pgbot`.
The AI layer has a certificate dependency worth knowing
The Dockerfile carries a comment that is easy to skim past: distroless/static ships the CA root bundle because `pgbot explain` makes an HTTPS call, and without roots under `sslmode=verify-full` that call fails with an opaque x509 error. If you are building your own minimal image and stripping certificates to save space, the deterministic commands will keep working and the AI commands will fail in a way that does not point at the cause.
More generally, the AI layer is the only part of pgbot that talks to the network beyond your database. The README frames the rest as needing no key and leaving nothing on your machine. That framing is accurate for `inspect`, `queries`, `indexes`, MCP and CI, and it is worth stating the boundary clearly: the moment you set a model key and run `ask` or `explain`, findings leave your environment for whichever provider that key belongs to.
Where pgbot is the wrong tool
pgbot is a point-in-time diagnostic you run, not a monitoring platform you operate. The README says this directly in a comparison with pganalyze, Percona PMM and pgwatch, and names what those tools have that pgbot does not: dashboards, alerting, long retention and multi-host rollups. If any of those four is a requirement, pgbot is not a candidate.
The practical consequence is that pgbot will not tell you about a problem at 3am. It tells you about a problem when someone runs it. Scheduling it from cron or a CI job narrows that gap, but the baseline problem returns: the comparison depends on local state, and ephemeral runners do not keep it.
There is a second boundary around the report itself. The README labels the project beta and states that the human-readable report is not a stable interface. Anyone building a dashboard or an alert rule on top of parsed terminal output is building on sand. The versioned `--json` contract is the supported surface, and even that is versioned rather than frozen, with breaking changes treated as breaking changes to the tool.
Finally, version coverage. The README's badge claims PostgreSQL 14 to 18, and the Makefile's `matrix` target describes a collector matrix against PG 13 to 18 that needs Docker. Those two statements do not line up, and the README does not resolve the discrepancy. If you run PostgreSQL 13, verify support yourself rather than assuming it from the Makefile comment.
Alternatives and how the approach differs
The README names pganalyze, Percona PMM and pgwatch as the tools to reach for when you want dashboards, alerting, long retention and multi-host rollups. The difference is architectural, not a matter of feature count. Those are platforms you operate: they collect continuously, store a time series, and expose it through a UI or an alert channel. pgbot collects once, computes findings in Go, and exits. There is no server to keep running and nothing to page you.
That makes the two categories complementary rather than competing. A team already running Percona PMM has the retention and alerting covered; pgbot's contribution there would be the versioned JSON contract and the MCP surface, not the health check. A team with no monitoring at all gets a useful answer from pgbot in one command, but should not mistake that for having monitoring.
The MCP angle is the genuinely different one. `pgbot mcp` exposes the same findings over the Model Context Protocol, with a skill and a Claude Code plugin on top, and the README describes the `--json` contract as PII-free. That is a narrower and more specific claim than "AI-powered database tooling": the model receives structured findings that were computed deterministically, and its job is to reason over them.
Maintenance, licensing and upgrade cost
The repository is not archived, and the last push was on 2026-09-10. Releases are frequent and closely spaced: v0.7.1 and v0.7.2 on 2026-09-01, then v0.8.1 on 2026-09-06. The project self-describes as beta, and the version numbering is consistent with that. Treat upgrade cost as non-trivial if you depend on the JSON contract, because the README states that breaking changes to it are treated as breaking changes to the tool. Pin a version and read the CHANGELOG before moving.
On licensing, the GitHub repository metadata reports NOASSERTION, while the README's badge and the LICENSE file it links to say Apache-2.0. The two signals disagree, and the README does not explain why. If the licence matters to your organisation, read the LICENSE file in the repository rather than either badge. This is a description of what the material states, not legal advice.
The dependency list is small and unremarkable for a Go CLI: `pgx` for the driver, `cobra` for commands, `lipgloss` for terminal rendering, `invopop/jsonschema` for the published schema, and `modernc.org/sqlite` for local storage. Because the release binary is static and CGO-disabled, upgrades are a binary swap with no library resolution to worry about.
Editorial conclusion
Adopt pgbot if you need a fast read-only answer about a Postgres instance you do not operate, or if you are wiring structured database findings into an agent through `pgbot mcp`. Do not adopt it as a replacement for pganalyze, Percona PMM or pgwatch: the README states plainly that it does not replace them, and there is no alerting, retention or multi-host rollup. Before rolling it out, verify that you can create a `pg_monitor` role with no write grants, that your server is in the PostgreSQL 14 to 18 range, and that your parsers target the versioned `--json` contract rather than the terminal output, which the README calls not a stable interface.
Frequently asked questions
Does pgbot need write access to my PostgreSQL database?
No. The guarantee is a `pg_monitor` login role with no write grants, and session pinning (`default_transaction_read_only`, `statement_timeout=15s`, `lock_timeout=2s`) plus `BEGIN READ ONLY` sit on top of it as defence in depth.
Do I need an API key to run pgbot?
Only for the optional AI layer. `inspect`, `queries`, `indexes`, MCP and CI are fully deterministic and need no key, and the README states nothing leaves your machine on those paths.
What does pgbot use the AI layer for?
`pgbot ask` and `pgbot explain` put a plain-language reading on top of findings that were already computed in Go. The README states that the AI layer explains findings and never generates them.
Which PostgreSQL versions does pgbot support?
The README's badge states PostgreSQL 14 to 18. The Makefile's `matrix` target describes a collector matrix against PG 13 to 18, and the README does not resolve that discrepancy, so verify your version rather than assuming.
Can pgbot replace pganalyze, Percona PMM or pgwatch?
No. The README states that pgbot is a point-in-time diagnostic you run, not a monitoring platform you operate, and that the tools to reach for when you want dashboards, alerting, long retention and multi-host rollups are pganalyze, Percona PMM and pgwatch.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/pgrundev-pgbot)