Migration safety
Skill logicleap-labs/claude-plugins/plugins/migration-safety/skills/migration-safety
MANDATORY before any destructive database or schema work — DROP TABLE/COLUMN, TRUNCATE, DELETE or UPDATE across rows, irreversible ALTERs, data backfills, schema migrations. Forces the method: state the exact target → dry-run to count what's affected → write the rollback → only then execute. Triggers on "drop the table", "delete the old rows", "clean up the data", "truncate", "remove the column", "write a migration", "alter the schema", "backfill", any raw SQL against a real database.From its SKILL.md
npx -y skills add logicleap-labs/claude-plugins --skill migration-safetyAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
3 things to look at
- skips confirmationTells the agent to proceed without asking first, 2 times: "touch .migration-safety-off in the project root" and 1 more.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
- runs commandsInstructs the agent to run 3 commands, including `SELECT count(*) FROM sessions WHERE created_at < now() - interval '90 days'` and 2 more.
SKILL.md
4.2 KB, 948 tokens by cl100k_base, as published. Nobody here has run it
Migration Safety
Destroyed data has no kill switch. Every other mistake in this toolchain
can be reverted — a bad edit, a wrong commit, a broken build. A DROP TABLE
against the wrong database, a DELETE that forgot its WHERE, an
ALTER TABLE … DROP COLUMN on prod: those are permanent, and the model
reaches for them with the same casual confidence it edits a README.
The rule
No destructive SQL without a declared plan. State the target, prove the blast radius with a dry-run, write the rollback — then execute. The plan comes first or the statement doesn't run.
What counts as destructive
DROP TABLE/DROP DATABASE/DROP SCHEMAALTER TABLE … DROP COLUMN(and any ALTER that discards data — type narrowing, NOT NULL on a column with nulls)TRUNCATEDELETE FROM …with noWHEREUPDATE … SET …with noWHERE
Not destructive (the gate never fires): CREATE, ALTER … ADD, SELECT,
INSERT, and any DELETE/UPDATE with a WHERE clause.
The method: target → dry-run → rollback → execute
Step 1 — State the target
Name exactly what is being changed, and where. Which database (dev? staging?
prod?), which table, which rows. "Clean up old records" is not a target;
"delete rows in staging.sessions older than 90 days, ~14k rows" is.
Step 2 — Dry-run
Prove the blast radius before touching it:
-- before: DELETE FROM sessions WHERE created_at < now() - interval '90 days'
SELECT count(*) FROM sessions WHERE created_at < now() - interval '90 days';
For a DROP COLUMN, check the column for non-null data first. For a schema
migration, run it against a dev copy. If the count surprises you, the plan
was wrong — good, that's the point.
Step 3 — Rollback plan
State how this gets undone before it happens:
- a backup/snapshot taken (
pg_dump, a point-in-time restore window), - a down-migration written alongside the up,
- or — if it genuinely can't be undone — say that out loud and get the human to confirm. "Irreversible" is a thing you declare, never a thing you discover.
Step 4 — Declare, then execute
Write the plan where the hook can see it. Either a .migration-plan file in
the project root:
target: staging.sessions — rows older than 90 days (~14,203 per dry-run SELECT)
dry-run: count verified 2026-06-11; matches expectation from retention policy
rollback: pg_dump of sessions taken to backups/sessions-20260611.sql; down-migration n/a
…or, for a one-off, a sentinel line in your reply:
MIGRATION-SAFETY: ALLOW — dropping staging.tmp_import (dry-run: 0 dependent FKs); rollback: table recreated from import script
The PreToolUse hook blocks destructive SQL — run via Bash or written into a
.sql/migration file — until one of those exists. Delete the
.migration-plan file when the migration ships so a stale plan can't
whitewash the next one.
Avoiding false alarms
The gate only fires on the irreversible shapes. WHERE-scoped deletes and
updates, additive migrations, SELECTs, and SQL in comments all pass. Writes
to files outside .sql/migration paths are never scanned — a DROP TABLE
in a test fixture or doc doesn't block.
Kill switch
False positive (a seeded test database, a scratch SQLite file):
touch .migration-safety-off in the project root, or
export MIGRATION_SAFETY_GATE=off.
Pairs with
verify-before-done— the dry-run is the verification; this skill just makes it happen before the destructive step instead of after.no-silent-assumptions— "assuming this only touches staging" is exactly the guess Step 1 forces into the open.scope-guard— scope the files; this scopes the data.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.