Writing a custom checkup
The form, the three sections a good procedure has, and why finding keys have to be stable.
Org admins can write their own checkups: New checkup on the Checkups page, or Duplicate on a shipped one to start from a procedure that already works.
Authoring is admin-only and there is no private, member-authored variant. A checkup body is agent instructions that run over organization-wide data sources under the organization's own identity — an admin-plane artifact, like a shared credential or a playbook, not a personal note.
The form
| Field | What it does |
|---|---|
| Name | Max 80 characters. Identifies it everywhere. |
| Category | Which rail it appears in. See the categories. |
| Description | The card copy — one or two sentences on what it looks at. Keep it under about 160 characters so the card does not truncate it. |
| Required integrations | Providers the procedure genuinely cannot run without. A hard gate: the card offers Connect <provider> instead of Run until they are connected. Leave empty unless the checkup is meaningless without them. |
| Scope | The MCP servers the run may call. Empty means all of your organization's servers. |
| How the report is shaped | Optional. Structure guidance for the write-up: what to open with, how to section it, which tables to close with. |
| Procedure | The checkup itself. Everything below is about this field. |
| Enabled | A disabled checkup cannot be run or scheduled, but keeps its runs and findings. |
Curated checkups cannot have their content edited — that content is code, and the next app upgrade would revert your edits. Duplicate one and edit the copy; the copy is yours, including its scope and schedule. Your own checkups keep a revision history of every create, edit, duplicate and delete.
Three sections a procedure needs
Write for a competent new hire who does not know your systems. The shipped checkups all follow the same shape, and it is worth copying.
## Procedure
Numbered investigation steps. Name the concrete systems to read and what to compare them against — an ordered list is the single most valuable thing you contribute, because it is what turns twelve tool calls into four.
- List every Snowflake warehouse with its size, auto-suspend and last activity.
- Compare 30 days of credit spend per warehouse against the queries it actually ran.
- For anything above 100 credits with under 20% utilisation, pull the query history and say what is actually driving it.
"Check the warehouses" produces a different run every month, which makes the findings incomparable and the whole ledger useless.
Say what a non-answer looks like too. A system that could not be reached, or a control whose evidence lives somewhere the run cannot see, is a legitimate result and should be reported as one rather than guessed at.
## Finding keys
The stable slugs that identify each underlying issue, with a line on what each one means.
idle-warehouse-<name>— a warehouse with no queries in 30 daysno-auto-suspend-<name>— auto-suspend unset or over 15 minutes
## Severity rubric
What critical, high, medium, low and info mean in this domain, so two runs grade the same evidence the same way.
- critical — recurring monthly spend with no owner
- high — a warehouse over 100 credits a month at under 20% utilisation
- info — a warehouse that is correctly sized, recorded so a later run can detect it drifting
You do not have to write the findings block itself. The run agent is already told to emit one, with the fields and the severity vocabulary; your job is to define what the keys and the severities mean here.
Why finding keys must be stable
A key is hashed together with the checkup's key into the fingerprint that gives a finding its identity across runs. Get this right and a problem has one row with a history. Get it wrong and every run files everything as new, nothing ever auto-resolves, and the findings list becomes a pile.
Put the thing's own identifier in the key.
| Good | Bad | Why |
|---|---|---|
warehouse:REPORTING_WH:idle | finding-1 | Ordinal keys change meaning between runs. |
cc6.3:dormant-accounts:not-deprovisioned | dormant-accounts-2026-03 | A date makes every run a new issue. |
webhook:shopify-orders:signature-mismatch | 3-webhooks-failing | A count changes when one is fixed. |
A checkup's key is permanent once it has run
Findings are fingerprinted against the checkup's key as well as their own. Renaming a checkup's key orphans every finding it has ever produced — the history is not migrated, it is simply no longer reachable.
Before you schedule it
Run it once by hand and read the report end to end. Check that:
- every claim cites something the tools actually returned;
- the findings it filed are things you would want to see again next month;
- the keys look stable — no dates, no counts, no ordinals;
- nothing was reported as fine that the run could not actually see.
Then put it on a schedule.