Plumber metrics SQL
SkillDatabases & dataTurns plain-English business-metrics questions about Plumber's pipes, executions, and users into Postgres SQL. Use whenever asked for a metrics count/aggregate, a retention/activity metric, or a Grafana panel query. Resolves Plumber-specific traps — soft-delete filtering, opaque app/trigger/action keys, ambiguous terms like "active," and timestamptz timezone handling.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Plumber metrics SQL skill
What this skill tells your AI
The instructions your AI receives, as published by opengovsg/plumber in .claude/skills/get-metrics-sql/SKILL.md and read by ahel’s review.
Turn a business-metrics question into correct Postgres SQL against Plumber's domain tables
(flows, steps, executions, execution_steps, users, connections). Reading the
model files directly gets you most of the schema — the
reference docs below cover what a single model file won't tell you.
Hard rules (non-negotiable):
- Never write to the database. All validation runs read-only (see step 5) — never
INSERT/UPDATE/DELETE, never skip theREAD ONLYwrapper. - Ask, don't guess, on genuine ambiguity — (not an exhaustive list) e.g. an unclear "active," an
unspecified Grafana panel design, or a display name that doesn't uniquely resolve to one
(app_key, type, key).
Workflow
1. Restate the question in concrete tables/columns
Read reference/glossary.md and reference/gotchas.md.
Restate the question in terms of concrete tables/columns, reading the relevant
model file(s) directly for schema details. Pin down every
ambiguous business term against the glossary — in particular, decide whether "active" means
published (flows.active) or active pipe/user (flowed within a period); ask the user if the
question doesn't make this clear.
2. Resolve any named app/trigger/action
If the question names an app, trigger, or action ("slack action," "gathersg trigger"), follow
reference/resolving-app-keys.md to resolve display names to
app_key / key / type — never guess a key from the display name.
3. Compose the SQL
Mandatory checklist:
deleted_at IS NULLfor every table referenced, table-qualified in joins — by default. Drop it for a specific table only if the user explicitly wants deleted rows included there, or a specific question intentionally doesn't care about that table's soft-delete state; ask if unsure, and call out which table(s) got the guard relaxed and why in the final explanation.- Exclude
test_run = truefor execution-volume questions, unless the user explicitly wants test runs included. - Qualify ambiguous columns (e.g.
f.user_idvs.u.id). - If bucketing by calendar period (quarter/month/day), convert to SGT before truncating — but check
reference/gotchas.md first for which conversion applies: the core tables'
timestamp columns are
timestamptz(a singleAT TIME ZONE 'Asia/Singapore'conversion), not naive as a migration'stable.timestamps(true, true)call might suggest. Don't assume; verify against the live schema if unsure. - If the query touches
execution_steps(large and growing on prod), or otherwise aggregates over a row count you're not confident fits in memory, wrap it in the OOM-guard settings block from reference/gotchas.md before delivering it for prod execution.
Check the composed query against reference/recipes.md — if the question matches one of those shapes, the recipe is the reference implementation.
4. Grafana output (if applicable)
If the output targets a Grafana panel, follow reference/grafana.md: cast macro expansions explicitly before passing them into any overloaded function or timezone conversion, and pick the panel design (single window vs. fixed trailing window of N periods) — ask the user if it's ambiguous; this is a real design decision, not something inferable from the question alone.
5. Validate locally
Validate the query read-only against the Postgres container brought up by npm run setup (the human
runs this themselves — don't start it yourself; if it doesn't seem to be running, ask). Run psql
inside that container via docker exec, rather than a locally-installed client — find the running
container's name with docker ps (it's derived from the postgres service in
docker-compose.dev.yml), and read the database and
user from the same file.
Wrap in a read-only transaction:
docker exec <postgres container name> psql -U <user from docker-compose.dev.yml> \
-d <database from docker-compose.dev.yml> \
-c "BEGIN; SET TRANSACTION READ ONLY; <query> LIMIT 0; ROLLBACK;"
or EXPLAIN <query> for a syntax/reference-only check. For queries containing Grafana macros,
substitute a literal timestamp for each macro first (see
reference/grafana.md) — psql doesn't expand them there. Self-correct on
error, up to a few retries; if it still fails, report the error rather than guessing further.
State plainly that counts of 0 are expected against this container's (test-only) data — the SQL's correctness is what's being validated, not the numbers it returns there.
6. Output
Present:
- the final SQL in a fenced block (with Grafana macros restored, and any OOM-guard block from step 3 included),
- a one-paragraph plain-English explanation of what it computes and the assumptions made,
- any Grafana panel configuration notes (query format, visualization type, X-axis, units), and
- a note that the query is meant to be run against a prod read-replica, not local data.
Keeping this skill in sync
There are no source-code markers pointing back at these docs, so they only stay accurate if updated deliberately. If a session surfaces something worth capturing — (not an exhaustive list) e.g. the user clarifies an ambiguous term, you find a column whose meaning isn't self-explanatory from its model file, or validation reveals that reference/glossary.md or reference/gotchas.md is stale or wrong — ask the user whether to update the relevant doc with what you learned. Don't edit these docs unprompted.
Signals
- GitHub stars
- 27
- Forks
- 15
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
get-metrics-sql- Source
- github.com/opengovsg/plumber