Add references/agent-evals.md documenting the official supabase/evals harness: eval/experiment concepts, the tools and local-stack runtimes, run and result-viewing commands, and a mapping of harness scenarios to the skill's operating references. Route to it from the supabase "Choose the path" table and from postgres, agent-evals-and-observability, backend-engineering, and data-engineering. Add two eval cases covering the new reference and keep the generated catalog artifacts current. Closes #271 Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
16 KiB
name, description, license, compatibility, metadata
| name | description | license | compatibility | metadata | ||||
|---|---|---|---|---|---|---|---|---|
| postgres | Operate PostgreSQL instances safely: configuration review, index and query-plan analysis, vacuum and bloat management, WAL archiving and point-in-time recovery, replication and failover, extensions, major-version upgrades, and evidence-based diagnostics with the bundled read-only pgdiag script. Use when running or inspecting a PostgreSQL server, diagnosing performance or backup health, or planning an upgrade or failover. Do not use for application-level data access patterns (that's backend-engineering) or schema design (that's data-architect/data-engineering). | MIT | The bundled pgdiag script runs on Python 3.9+ and needs no PostgreSQL server for --help. Live diagnostics require the psql client (PostgreSQL 10+ servers) and socket or network access to the instance. |
|
PostgreSQL Operations
Use this skill to operate PostgreSQL safely as the database engine it is: review configuration against workload, find index and query-plan problems, manage vacuum and bloat, set up and verify WAL archiving and point-in-time recovery, run replication with a defensible failover plan, handle extensions, plan major-version upgrades, and diagnose incidents with evidence. This is a tool skill for one named tool (PostgreSQL). Database methodology — backup strategy across engines, migration patterns, SQL analytical patterns — lives in data-engineering; application-level data access patterns belong to backend-engineering; schema and data modeling belong to data-architect and data-engineering. Supabase platform administration is supabase.
Operating contract
- Read-only discovery before any mutation. Inspect configuration, catalog statistics, and logs first. The bundled
pgdiagscript collects read-only evidence and opens every session withdefault_transaction_read_only=on. - Confirm the target, scope, and rollback path before acting. Read-only discovery may proceed without confirmation. Mutations — a
pg_ctlstop, a promotion, an extension install, apg_upgraderun — require an explicit human directive naming the instance. - A backup is not recovery evidence. Verify restore on a scratch instance on a schedule; never claim recoverability from a backup log alone.
- Keep evidence bounded. Summarize catalog queries and log excerpts; never dump full logs,
postgresql.conf, or connection strings with passwords into chat. - Verify at the delivery boundary. A
SELECT 1answer proves connectivity, not health; a replayedpg_basebackupproves recoverability, not that today's WAL is being archived.
The pgdiag script
scripts/pgdiag is an agent-first, read-only diagnostic collector. It shells out to psql, opens every session with default_transaction_read_only=on, and emits bounded JSON. --help works with no server and no psql installed.
scripts/pgdiag --help # no cluster needed
scripts/pgdiag --json # all checks, machine-readable
scripts/pgdiag --host db1 --dbname app --json
scripts/pgdiag --check identity --check wal_archive --json
scripts/pgdiag --plan-for "SELECT * FROM orders WHERE id = 42" --json
Exit codes: 0 ok, 1 runtime/collection error, 2 usage error, 127 psql binary not found, 124 timeout. --check runs a named subset; --plan-for adds an EXPLAIN (FORMAT JSON) plan for one read-only statement. The script never issues data-changing statements, and the server-side read-only session setting rejects any that slip through.
Operating loop
- Identify the instance: version, recovery state, configuration file locations, connection string shape, and whether this is primary or standby.
- Collect evidence:
pgdiag --jsonfor config, connections, index usage, bloat signals, WAL archiving, recovery, replication, extensions, and database sizes. - Triage against the symptom: map the reported problem to the evidence (slow queries → plans and index usage; stalled backups → archiver; drift → replication lag).
- Act with confirmation: bounded, scoped mutations after a human directive, with a rollback path named first.
- Verify: re-run the relevant check and confirm the observable at the delivery boundary.
Configuration
- The runtime source of truth is
pg_settings, not the file:SHOW/current_setting()reflect reloads and overrides (ALTER SYSTEM, command-line-c, envPGOPTIONS).pgdiag'sconfigcheck lists the operator-critical values. - Know which changes need a reload (
pg_ctl reload/SELECT pg_reload_conf()) versus a restart: memory (shared_buffers, max_connections, wal_level, max_wal_senders) requires restart; most tuning and logging parameters reload. - Check
log_destination,logging_collector, andlog_min_duration_statementso slow-query evidence exists before you need it;track_io_timing=onmakespg_stat_databaseI/O timing meaningful. - Connection pressure: compare
pg_stat_activitystate counts againstmax_connections; a connection pooler is an application-architecture decision for backend-engineering. - GUC rationale, reload-versus-restart tables, and parameter-change review patterns:
references/01-configuration.md.
Indexes and query plans
- Evidence first:
pg_stat_user_indexesshowsidx_scan/idx_tup_read/idx_tup_fetch; a table scanned sequentially with a largeseq_tup_readwhile a filter exists is a candidate for a missing index. EXPLAIN (ANALYZE, BUFFERS)on the real workload query beats guessing; compare estimated to actual rows — a large mismatch points at stale planner statistics (apg_statisticfreshness problem) or a bad parameter (random_page_cost, effective_cache_size).- Unused indexes (
idx_scan = 0over a long window) cost writes and maintenance; invalid indexes (pg_index.indisvalid = false) are dropped on next vacuum and should be repaired or removed deliberately. - Index choices (BRIN vs btree, partial indexes, covering indexes) are schema design and belong to data-architect; this skill owns measuring and operating what exists.
- Query-plan reading, index-usage SQL probes, and plan-review checklists:
references/02-indexes-and-query-plans.md.
Vacuum and bloat
- Vacuum reclaims dead tuples and refreshes planner statistics; autovacuum should do this on its own. Verify it is actually running:
autovacuum=on, worker count, and per-tablerelfrozenxid/n_dead_tuptrends. - Bloat is the gap between table file size and live data:
pg_stat_user_tables.n_dead_tuprising faster than vacuum runs is the leading signal; heap bloat from failed or skipped vacuum shows as largerelpageswith low live tuples. - If autovacuum lags, the response is a targeted, confirmed maintenance window (
VACUUMon specific tables, not a firehose), then a check of why autovacuum fell behind (long transactions, connection saturation, worker starvation). - Never treat
VACUUM FULLas routine: it rewrites the table, takes locks, and needs a maintenance window plus a verified backup path. - Bloat measurement probes and autovacuum tuning patterns:
references/03-vacuum-and-bloat.md.
Backups: WAL archiving and point-in-time recovery
- The recovery model: a base backup plus a continuous WAL archive gives point-in-time recovery (PITR) — restore the base, replay archived WAL up to the target time.
- Recovery targets come in two families: time-based (the
pitr|point.in.timepattern is the shorthand for this family — a wall-clock target such as "yesterday 02:00") and position-based (a specific LSN or timeline marker). Both are validrecovery_targetinputs. - WAL archiving readiness is
archive_mode=onwith a workingarchive_commandand a healthy archiver:pg_stat_archivermust showarchived_countgrowing,failed_countstable, andlast_failed_walempty or old. wal_levelmust bereplica(or higher) for both archiving and streaming replication; changing it requires a restart.- Back up with
pg_basebackup(or a dedicated tool) consistently with WAL: label each backup, record itspg_stop_backup()LSN / timeline, and test restore with the archive before trusting it. - PITR procedure,
recovery_targetoptions, restore-to-point-in-time steps, and RPO/RTO framing (methodology in data-engineering):references/04-backups-wal-pitr.md.
Replication and failover
- Streaming replication: standby connects with a replication slot, receives WAL continuously; verify with
pg_stat_replication(state=streaming,replay_lsnkeeping up, smallreplay_lag) and the standby's recovery state. - Decide synchronous vs asynchronous deliberately: synchronous (
synchronous_standby_names) trades commit latency for a durability guarantee; asynchronous risks losing the last commits on failover. - A failover plan is more than a
pg_ctl promote: it names who promotes, how clients are redirected, what happens to the old primary on return, and how to verify data (lag at promotion, timeline divergence). - Promotion is a mutation — confirm the target and scope first. With a replication-manager tool (Patroni, repmgr), use its switchover command instead of manual promotion; rejoin the old primary as a standby, never let two primaries write.
- Streaming setup, slot management, lag measurement, and failover runbooks:
references/05-replication-and-failover.md.
Extensions
- Inventory first:
pg_extension(installed) andpg_available_extensions(available) tell you what exists and what versions are on disk;pgdiag'sextensionscheck does this. - Extension installs change the shared catalog and some extensions change the database in ways that are hard to reverse — an install is a mutation with a rollback path, not a
CREATE EXTENSIONreflex. - Major-version upgrades usually require re-installing or re-building extensions (e.g., PostGIS, pgvector) on the new binaries; check each extension's upgrade notes before
pg_upgrade. - Trusted extensions can be installed by non-superusers into their own databases; extension policy and shared-library availability are infrastructure decisions for platform-engineering.
- Common extensions, lifecycle, and version-upgrade gotchas:
references/06-extensions.md.
Upgrades
- Minor upgrades are in-place binary swaps (restart); major upgrades (e.g., 15 → 16) change on-disk format and need
pg_upgradeor a logical dump/restore. - Plan the path first: read the release notes and upgrade guide for the full version span, check extensions and unsupported features, pick the method (
pg_upgradewith link mode, or logical), and rehearse in a scratch environment with the real data shape. pg_upgradeis a mutation requiring downtime and a verified backup: stop writes, run the upgrade with the--old/--newbinaries, runanalyzeon the new cluster, and verify at the application boundary before decommissioning the old.- Logical replication (publisher/subscriber) can serve as a near-zero-downtime major-upgrade path; it is also a migration pattern whose methodology lives in data-engineering.
- Version matrices, upgrade runbooks, and rollback decisions:
references/07-upgrades.md.
Diagnostics with evidence
Diagnose in evidence order: identity/version → configuration → connections → index usage and plans → vacuum/bloat → WAL archiving → replication → extensions.
pgdiag --jsongathers the first evidence layer in one bounded payload; re-run the affected check after any change.- Slow query →
EXPLAIN (ANALYZE, BUFFERS)pluspg_stat_user_indexes/seq_tup_read; check planner statistics freshness before touchingrandom_page_cost. - Backup stalled →
pg_stat_archiver:failed_count,last_failed_wal, and the archive target's disk/network. - Standby falling behind →
pg_stat_replicationlag columns, slot retention (pg_replication_slots), and network saturation between primary and standby. - Never present correlation as cause: a slow query and a high
n_dead_tupare evidence, not a diagnosis — state what was measured, what changed, and what was verified. - Failure-mode routing and symptom→probe→fix tables:
references/08-diagnostics.md.
Reference routing
| Load when | Reference |
|---|---|
| Tuning, GUC review, reload vs restart | references/01-configuration.md |
| Slow queries, index usage, plan review | references/02-indexes-and-query-plans.md |
| Autovacuum, dead tuples, bloat measurement | references/03-vacuum-and-bloat.md |
| WAL archiving, base backups, PITR, restore drills | references/04-backups-wal-pitr.md |
| Streaming setup, slots, lag, failover runbooks | references/05-replication-and-failover.md |
| Extension inventory and upgrade gotchas | references/06-extensions.md |
| Minor and major upgrades, pg_upgrade, rollback | references/07-upgrades.md |
| Symptom-to-probe diagnosis tables | references/08-diagnostics.md |
| Sources, version observations, refresh procedure | references/00-source-index.md |
Included artifacts
scripts/pgdiag: read-only diagnostic collector (stdlib-only,--json,--check,--plan-for,--helpwithout a cluster).tests/test_pgdiag.py: deterministic tests against a fake psql stub, including the read-only contract.references/: nine dated, source-indexed references covering the operational topics above.
Verification boundary
| Claim | Minimum evidence |
|---|---|
| Instance is reachable and versioned | pgdiag --check identity --json parses and reports version and recovery state |
| Configuration is known | pgdiag config check lists the operator-critical GUCs |
| Archiving is healthy | pg_stat_archiver: archived_count increasing, failed_count not climbing, last_failed_wal stale |
| Replication is current | pg_stat_replication: state=streaming and lag within the agreed bound |
| Backups support recovery | A restore of a base backup + WAL replayed to a target time on a scratch instance |
| A diagnosis is sound | Evidence was collected before the claim, and the fix was verified by re-running the check |
Hard boundaries
- Never run a mutation (
pg_ctl stop, promote,pg_upgrade, extension install, maintenanceVACUUM) without an explicit human directive naming the target and a stated rollback path. Read-only discovery may proceed freely. - Never present unverified claims as evidence: state what was measured, when, and how.
- Never expose full logs,
postgresql.confcontents, or connection strings containing passwords. - Never run
pgdiagwith a write-capable session; the tool itself is read-only by design.
When not to use
- Application-level data access patterns (connection pooling in app code, ORM usage, query construction, transactions in services) — that is backend-engineering.
- Schema design and data modeling (tables, keys, normalization, dimensional models) — that is data-architect and data-engineering.
- Database methodology across engines (backup strategy, migration patterns, analytical SQL) — that is
data-engineering. - Supabase platform administration (managed projects, CLI stack, the self-hosted Supabase stack) — that is supabase; plain PostgreSQL operations without Supabase conventions belong here. To measure an agent's Supabase task competence, use the skill's agent evals harness reference.
- Other database engines (Redis, MongoDB, Elasticsearch, vector stores) — those stay in
data-engineeringreferences; this skill owns PostgreSQL only.