Open-source project
pgrundev/pgbot avatar
pgrundev/pgbot

pgbot: read-only PostgreSQL diagnostics that remember the last run

Postgres intelligence for ai agents & apps

1,279 stars59 forksGoNOASSERTION

At a glance

What is it?
pgbot is a single Go binary that connects to PostgreSQL with a pg_monitor login role, reads the database's own statistics views, and prints a graded health report plus a diff against a local baseline. It is a point-in-time diagnostic, not a monitoring platform.
Who is it for?
Adopt pgbot if you need a fast, read-only read on a Postgres instance you do not operate, or if an AI agent needs structured findings rather than raw statistics views. Do not adopt it as a replacement for pganalyze, PMM or pgwatch if you need dashboards, alerting, long retention or multi-host rollups; the README states plainly that it does not replace them.
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 1 day 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 September 16, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The gap pgbot fills: a second opinion on a database you do not own

Most PostgreSQL observability assumes you control the host. You install an agent, you keep a time-series store, you own the retention policy. That assumption breaks in two common situations. The first is triage on a managed or borrowed instance where you have credentials and nothing else: no shell on the box, no permission to deploy a collector, and a limited window to say something useful. The second is an AI agent that needs to reason about a database. Handing a model raw pg_stat views produces guesses; handing it precomputed findings with severities produces something closer to an answer.

pgbot targets both. The README describes it as a point-in-time diagnostic you run rather than a monitoring platform you operate, and it names the cases directly: an answer in seconds without deploying anything, triaging a database you do not own, or feeding an agent structured findings. The audience is therefore DBAs doing incident triage, backend engineers who inherited a database, and anyone wiring Postgres into an agent toolchain. It is not aimed at teams that need alert routing or month-long retention, and the README says so instead of pretending otherwise.

Read-only by role, with session pinning as a second layer

The access model is the most interesting design decision here. The guarantee is not a flag on the command line; it is a pg_monitor login role with no write grants. Session pinning sits on top as defence in depth: default_transaction_read_only, statement_timeout=15s and lock_timeout=2s, plus BEGIN READ ONLY. That ordering matters. A tool that promises read-only via a --read-only switch is trusting its own code path. pgbot is trusting the database's privilege system first, and its own settings second.

The timeouts are worth noting separately. A diagnostic that opens a transaction against a busy production instance can itself become the incident. Capping statement time at 15 seconds and lock time at 2 seconds bounds the blast radius of the tool's own queries. Those are the documented defaults; the README does not state whether they are configurable, so treat them as fixed until you check the flags.

Everything the tool reads comes from Postgres's own statistics views. No extension, no sidecar, no external service. The README frames this as in-database observability, and the practical consequence is that there is no data pipeline to break and no second system to keep in sync.

Findings are computed in Go, and the AI layer only explains them

The pipeline is deliberately split. Deterministic checks run in Go against SQL results and produce findings bucketed CRITICAL, WARNING and NOTE. The optional AI layer, reached through pgbot ask and pgbot explain, reads those findings and puts a plain-language interpretation on top. The README states that the AI layer explains findings and never generates them. That is the right boundary. A model that invents a finding about transaction-id age is worse than no model at all, because the output looks authoritative.

The default report is a graded read rather than a wall of numbers. Four gauges (cache hit, lock wait with the culprit query, rollbacks, idle index bytes as a share of the database) carry a status. A checked line names the subsystems that came back clean, which the README justifies as reading like a colleague who looked rather than an alarm. Then a numeric health score, then the findings. pgbot inspect --full adds a subsystem status board plus section tables and per-finding caveats. Focused commands (indexes, queries, tables, vacuum) drill into a single signal.

One consequence of the split is that the deterministic path needs no API key. inspect, queries, indexes, MCP and CI work without one, and nothing leaves the machine. Only ask and explain require a provider key.

The baseline file is what makes pgbot more than a snapshot

A single health check tells you the state of a database. It cannot tell you that orders queries went from 8 ms mean to 26 ms, or that an index stopped being used. pgbot addresses this by writing a local baseline on every run, so from the third run onward it reports what changed and why it matters. The example output in the README shows exactly that shape: a warning that orders queries are 3.2 times slower, a note that three unused indexes consume 18 GB, a warning that connection usage reached 87 percent.

The third-run detail is a real constraint, not a footnote. A first run against a new database gives you a static report and no deltas. If you invoke pgbot from CI on ephemeral runners with no persistent working directory, the baseline never survives and you get the snapshot behaviour permanently. The README does not document where the baseline is written or how to relocate it, so if you plan to run this in CI, that is the first thing to confirm from the flags or the repository layout.

There is also a correctness question the material does not answer: how the tool decides that a change is meaningful rather than noise. The README presents deltas as findings, but gives no threshold policy. Treat the change detection as a pointer to investigate, not as a verdict.

Getting it running: install, role, connection resolution

Installation is a shell one-liner from the project's own domain, followed by an inspect against a connection string:

curl -fsSL https://pgbot.dev/install | sh pgbot inspect "postgres://pgbot_ro@host:5432/db"

The connection argument is optional. Resolution order is the argument first, then DATABASE_URL, then PGBOT_DATABASE_URL, then PGSERVICE. The PGSERVICE path matters for anyone who already keeps connections in a libpq connection service file: export PGSERVICE=mydb and drop the argument entirely. The README also flags a shell detail that trips people up, that the export line takes no dollar sign on the left and no spaces around the equals sign.

On the database side, the setup is a pg_monitor login role with no write grants. The README's setup section names this explicitly, and it is the one step you cannot skip if you want the read-only property to hold.

For the optional AI layer, one environment variable is enough, and the provider is inferred from which key is present: OPENAI_API_KEY, GEMINI_API_KEY, ANTHROPIC_API_KEY or XAI_API_KEY. The README lists default models per provider (gpt-5.6-terra, claude-opus-5, grok-4.6) and notes that any OpenAI-compatible endpoint works, including local ones. Provider pinning and model overrides are documented in the AI layer section rather than repeated in the quickstart, so read that page before pointing pgbot at a self-hosted model.

The --json contract is the stable interface, and the terminal output is not

This is the single most important thing to internalise before building on pgbot. The README states that the --json contract is versioned, currently 1.2.0, with a JSON Schema published in the schema directory, and that breaking changes to it are treated as breaking changes to the tool. It then states the inverse for the human-readable report: it is not a stable interface, and you should parse --json rather than the terminal output.

That is an unusually honest split, and it has a practical consequence. Any script that greps the gauge strip or the CRITICAL heading is building on sand. The project has committed to the JSON shape and has not committed to the text shape. If your integration reads the terminal, you will absorb cosmetic changes as breakage.

The JSON is also described as PII-free, which is what makes it usable as an agent input. For the MCP path, pgbot mcp exposes the same findings over the Model Context Protocol, with a skill and a Claude Code plugin on top. The tool is in beta, and the README says so, but the versioning discipline on the JSON contract is the part that makes beta tolerable for a tool you wire into automation.

Where pgbot is the wrong tool, and what to use instead

pgbot has no dashboards, no alerting, no long retention and no multi-host rollups. That is not an oversight; the README's own comparison section says that if you want those things you should run pganalyze, Percona PMM or pgwatch, and that pgbot does not replace them. The difference in approach is structural. Those are platforms you operate: they collect continuously, store history, and push notifications when a threshold trips. pgbot is a binary you invoke, which reads current statistics views and compares against a local baseline file on the machine where you ran it.

The consequence is that pgbot cannot tell you what happened at 03:00 last Tuesday. It has no retention beyond whatever baseline it keeps locally, and it has no way to alert anyone. If your requirement is a pager that fires when replication lag crosses a line, pgbot is the wrong shape entirely.

A second boundary is version support. The README states PostgreSQL 14 through 18. Anything older is out of scope, and the statistics views pgbot depends on have changed across major versions, so do not assume a clean run on an unsupported release.

A third is the beta status combined with the licence field. The repository metadata reports the licence as NOASSERTION while the README's badge and the LICENSE link say Apache-2.0. Those two signals disagree, and only the LICENSE file itself resolves which terms actually apply. Check it before you ship the binary inside a product.

Maintenance cost and the upgrade surface you actually own

The deployment cost is close to zero: one static binary, no collector, no time-series database, no service. Upgrades are a binary swap. The maintenance cost sits elsewhere, in two places.

The first is the JSON contract. Because the project treats breaking changes to --json as breaking changes to the tool, a version bump can require a change on your side. That is the price of a stable contract, and it is a better deal than parsing text. Pin the contract version you consume and read the release notes for v0.8.1, v0.7.2 and v0.7.1 before upgrading anything automated.

The second is the baseline. It is local state, and local state has lifecycle questions: what happens when the machine is rebuilt, when the database is renamed, when two people run pgbot against the same instance from different laptops and get different deltas. The README does not address any of this. The baseline is the feature that makes pgbot more than a snapshot, and it is also the part with the least documented operational story.

On licensing, the README and the LICENSE link point to Apache-2.0, while the repository metadata reports NOASSERTION. Resolve that discrepancy from the LICENSE file before relying on either. This is not legal advice; it is a statement that the two sources in front of you conflict.

Editorial conclusion

Adopt pgbot if you need a fast, read-only read on a Postgres instance you do not operate, or if an AI agent needs structured findings rather than raw statistics views. Do not adopt it as a replacement for pganalyze, PMM or pgwatch if you need dashboards, alerting, long retention or multi-host rollups; the README states plainly that it does not replace them. Before rolling it out, verify three things: that your target is PostgreSQL 14 through 18, that you can create a pg_monitor login role with no write grants, and that the local baseline file survives between runs, because the change detection only appears from the third run onward. Parse --json, not the terminal output: the README marks the human-readable report as not a stable interface.

Official sources

  1. Issues
  2. pgrundev/pgbot on GitHub
  3. Project website
  4. README
  5. Releases
Community notes

Community notes