Skip to content
Back to skills

Check

ASecurity

Migration safety check. Finds the database migrations in a change without a model and, only when there are some, runs one read-only migration-reviewer agent against them for what breaks in production — old code running against the new schema during the deploy, table locks and rewrites, data loss, constraints existing rows violate, edited history, and missing rollbacks — then writes one report and a findings.json in the shared finding contract. Use when the user asks whether a migration is saf...

  • 3 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 4, 2026
ai-agentspythonshellbashgitdatabase

Works with

  • cli
  • mcp

Security analysis

A100/100

Pro scans all 6 files and shows the line behind each finding

Scanned October 4, 2026

npx -y skills add Jarryd-W-Hoffman/agents --skill check --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Check?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Check
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/jarryd-w-hoffman-check/badge)](https://www.skillsdirectory.com/skills/jarryd-w-hoffman-check)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: check
description: Migration safety check. Finds the database migrations in a change without a model and, only when there are some, runs one read-only migration-reviewer agent against them for what breaks in production — old code running against the new schema during the deploy, table locks and rewrites, data loss, constraints existing rows violate, edited history, and missing rollbacks — then writes one report and a findings.json in the shared finding contract. Use when the user asks whether a migration is safe to deploy, for a migration review, or to check a PR or branch that touches migrations. Read-only; never runs a migration or connects to a database.
argument-hint: "[target] [--threshold 80]"
allowed-tools: Agent, Read, Grep, Glob, Write, Bash(git:*), Bash(gh pr view:*), Bash(gh pr diff:*), Bash(gh issue view:*), Bash(mktemp:*), Bash(python3:*)
---

# Migration safety check

Find the migrations in a change, and only if there are any, have one `migration-reviewer` agent judge what happens when they run against a production database that holds data and serves traffic while the previous release is still live. The agent type is namespaced `migrations:migration-reviewer` when this skill is installed as a plugin; use whichever form appears in your available agent list.

You are the **lead**. You do not review migrations yourself. You resolve the target, find the migrations with a script, brief the reviewer, wait for it, and write the report.

The check costs nothing when the change has no migrations: Step 2 stops before any agent is launched. Keep it that way.

## Arguments

Arguments received: `$ARGUMENTS`

| Form | Meaning |
|---|---|
| *(empty)* | Working tree against `HEAD`, including untracked files. If that has no changes, the current branch against its merge-base with the default branch. |
| `123`, `#123`, or a PR URL | That pull request, via `gh`. |
| `feature/x`, `abc123`, `main...HEAD` | A ref or ref range; a single ref means `<default-branch>...<ref>`. |
| `--threshold N` | Minimum confidence to report (default 80). |

## Repository state

There is no launch-time preamble on purpose. A shell command run at launch, the exclamation-mark-and-backtick form, stops the whole skill from loading if it fails, and then the model carries on without these instructions: `git rev-parse HEAD` fails in a repository with no commits, and every git command fails outside a repository. So the lead reads the state itself, in Step 1, where a failure is visible and handled.

## Procedure

### Step 1 — Resolve the target

First read the repository state:

```bash
git rev-parse --show-toplevel           # fails outside a repository: say so and stop
git branch --show-current               # the current branch; empty on a detached HEAD
git symbolic-ref --short refs/remotes/origin/HEAD   # the default branch as origin/<name>; if it fails, assume main
git status --short                      # the working tree
```

If `git rev-parse --verify --quiet HEAD` prints nothing, the repository has no commits yet: every file is new, so take the base as the empty tree (`git hash-object -t tree /dev/null`) and the head as the working tree.

Determine the **base**, which is what production runs now, and the **head**:

- Working tree: base `HEAD`, head = working tree.
- Branch or ref: base = `git merge-base <default-branch> <ref>`, head = `<ref>`.
- PR: `gh pr view <n> --json number,title,body,url,state,baseRefName,headRefName,headRefOid`. Fetch the head if needed (`git fetch origin <headRefName>`), then base = `git merge-base origin/<baseRefName> <headRefOid>`, head = `<headRefOid>`. Keep the title and body, and any linked issue (`gh issue view <n> --json title,body`), as the change intent. Stop if the PR is closed or merged.

Stop and tell the user if the target cannot be resolved.

### Step 2 — Find the migrations

```bash
python3 "${CLAUDE_SKILL_DIR}/scripts/find-migrations.py" --base <base>                # working tree
python3 "${CLAUDE_SKILL_DIR}/scripts/find-migrations.py" --base <base> --head <head>  # a ref or PR
```

It prints JSON: the migrations with their status and framework, whether an added one sorts before a migration already at base (`out_of_order`), and the schema dumps, deploy and database config, and rule files at base.

**If `migrations` is empty, stop.** Say in one line that the change touches no migrations and nothing was reviewed. Do not launch the reviewer, and do not write a report or findings file. If the script exits 1, show its error and stop.

### Step 3 — Brief and launch the reviewer

Read `${CLAUDE_SKILL_DIR}/references/reviewer-brief.md` and fill it in from Step 1 and the script's output, verbatim. Note which external context sources the session has (an authenticated `gh`, MCP servers for GitHub, Jira, Linear and the like) and list them so the reviewer uses them, read-only, instead of guessing.

Launch **one** `Agent` call: `subagent_type` the migration-reviewer agent type, the filled-in brief as the prompt, `name` `migrations`. Then wait. Do not review anything yourself while it runs.

If the reviewer returns nothing usable, the review did not happen. The verdict is `INCOMPLETE`, and you say so; never read its silence as a pass.

### Step 4 — Report

1. **Filter** the reviewer's findings to confidence at or above the threshold.
2. **Verdict**, computed: `FAIL` if any critical; `REQUEST_CHANGES` if any major; `PASS_WITH_NOTES` if only minor; `PASS` if none; `INCOMPLETE` if the reviewer did not report.
3. Write the report using `${CLAUDE_SKILL_DIR}/references/report-template.md` exactly. Keep every finding's `MIG-` ID so the user can ask about it by name. Carry the reviewer's deploy model line: a PASS against an assumed deploy model says less than one against a written one.

Then save the result as two files, in a temporary directory outside the repository (your scratchpad directory if one is listed in your system prompt, otherwise `mktemp -d`), never in the working tree:

1. `report.md`: the report exactly as you showed it.
2. `findings.json`: the same findings in the **finding contract**, defined by `${CLAUDE_SKILL_DIR}/scripts/finding.schema.json`. One object per reported finding: `id` (`MIG-1`, …), `title`, `severity`, `confidence`, `pass` (always `migrations`), `path` (repo-relative), `line` (in the head version; for a deleted migration, the base-version line with `side` `LEFT`), `body` (the failure scenario and why it matters), and optionally `end_line`, `fix`, `suggestion`. Use a finding's first location if it has several; mention the others in `body`. No other fields. With no findings, write `[]`.

Validate it before saying anything about it:

```bash
python3 "${CLAUDE_SKILL_DIR}/scripts/finding_contract.py" <dir>/findings.json
```

If it reports errors, fix the file and validate again. End your reply with one line giving both paths.

## Rules

- **Read-only.** Never edit files in the repository, never run a migration, seeder, `artisan`, framework CLI or database client, not even with `--pretend`, and never check out a different ref in the user's working tree. `Write` is in this skill's `allowed-tools` for `report.md` and `findings.json` in the temporary directory and nothing else.
- **The reviewer is read-only by enforcement, not just instruction.** The plugin's PreToolUse guard (`hooks/readonly-guard.py`) denies edits, state-changing shell commands, database clients and write-style MCP tools for the `migration-reviewer` agent. If the reviewer reports a denial, treat the gap as a Note, not a reason to do it yourself.
- **Do not review yourself.** If the reviewer missed something, say so under Notes; do not add findings of your own.
- **No migrations, no agent.** Step 2's early stop is the plugin's cost model. Do not launch the reviewer "just in case" on a change the script found no migrations in. If the user names a migration the script did not find, say that its layout is not one `find-migrations.py` recognises, which is a gap in the script to fix, and stop; do not guess at what else it missed.
- **Do not paste large diffs into the brief.** Give commands.
- **Do not soften or inflate.** Report the computed verdict. Do not post anywhere.

Files in this skill

  • SKILL.md8 KB
  • references/report-template.md1.8 KB
  • references/reviewer-brief.md3.2 KB
  • scripts/find-migrations.py8.9 KB
  • scripts/finding.schema.json2.9 KB
  • scripts/finding_contract.py5.6 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.