migrate-check
Skill2 starsChanged 4 months agoMITView on GitHub
Pre-flight safety check for Prisma/SQL migrations. MUST be run before creating or applying any migration in a project whose database is shared Postgres. Opens with a written GO or NO-GO verdict, then classifies every SQL statement additive vs destructive, checks migration-history drift and folder reuse, enforces create-only plus deploy discipline, and identifies the backup path first. Never fixes anything - it blocks and explains.
- Reads credentials
In this repository27 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- auditSkill
- challengeSkill
- contract-checkSkill
- depsSkill
- design-auditSkill
- designSkill
- doSkill
- eval-runSkill
- eval-specSkill
- healthSkill
- investigateSkill
- journalSkill
- learnSkill
- plan-reviewSkill
- planSkill
- qaSkill
- refactorSkill
- resumeSkill
- retroSkill
- secureSkill
- shipSkill
- ticketSkill
- triageSkill
- verifySkill
- whySkill
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 2 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 21
Run before the skill's steps — per invocation, not per session (4.36).
- Very specific: line 39
Never delete a decision. Supersede it: ~~old~~ → Verdict (YYYY-MM-DD): new call — reason.
- Distinctive: line 40
Never fix, tune, or delete a test or eval case to raise a score.
- Very specific: line 56
No-database autodetect: When db: is *unset* AND the project shows
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
/migrate-check — the gate before the shared database
A teammate's migration once dropped a table from a shared production
database. This skill exists so that never happens again. It is structurally
read-only: the tool whitelist has no Edit, no Write, and no prisma
subcommand that mutates anything. It blocks and explains; it never fixes.
(One residual: git log and git diff accept --output=FILE, which a
prefix grant can't exclude; the skill never uses it — see check.sh §13.)
Adjacent skills: /secure (security review; /migrate-check is DB-change
safety) · /audit code (defects in code; this gates schema changes).
<!-- acstack:runtime -->Run before the skill's steps — per invocation, not per session (4.36); failures degrade to markdown:
link="$(readlink "$HOME/.claude/skills/health" 2>/dev/null || true)" # empty = not symlinked
pack="$(dirname "$(dirname "$link")")" # NEVER trust this unless $link was non-empty
if [ "${link#/}" != "$link" ] && [ -x "$pack/bin/acstack-config" ] && ! "$pack/bin/acstack-config" runtime | grep -q '=off'; then
"$pack/bin/acstack-config" || true # resolved keys, with sources
"$pack/bin/acstack-update-check" || true # ≤1 fetch/day; silent ONLY if already checked today
"$pack/bin/acstack-recall" || true # LEARNINGS.md + bug-class names, capped 3KB
else
echo "runtime off — proceeding without recall/update-check"
fi<!-- /acstack:runtime --><!-- acstack:principles -->Operating principles
- Be direct. Push back in writing when the plan or the user is wrong. No sycophancy.
- Never delete a decision. Supersede it:
~~old~~ → **Verdict (YYYY-MM-DD):** new call — reason. - Never fix, tune, or delete a test or eval case to raise a score. Log the miss honestly and leave the case unchanged.
- Name exact things: regex patterns, function signatures, model names, before → after numbers. Never "fixed bugs".
- Attribution: follow the project's
attributionsetting (defaultnone) — no AI-tool mentions in generated docs, no attribution trailers in commits or PRs. Commit with explicit-m/-Fmessages only. - Config: read
.claude/acstack.mdat the project root (fall back to~/.claude/acstack.md) before acting.## Settingskeys override pack defaults; a## <skill-name>section overrides both. Unknown keys and sections are ignored. - Docs: BRIEF.md (frozen seed) / PLAN.md (living plan) / JOURNAL.md (rolling journal). If the repo uses legacy names (PLANNING_PROMPT.md / PLANNING.md / STATUS.md), use those instead — never create both.
- Recall: if
LEARNINGS.mdexists at the project root, read it before starting. - Conduct: follow the
acstack-conductblock in this repo's AGENTS.md — the word is the mode; the user sets the pace. - Hackathon lane: if the project's AGENTS.md carries the
acstack:hackathon-laneblock, only/dochanges the repository during the event. Any other skill that would write a tracked file, commit or push says what it would have done and stops; a change that is not a task goes through the lane's operator route.
<!-- /acstack:principles -->Procedure
Resolve the safety level from config
db:. Default when unspecified is shared-prod — the conservative assumption.local→ lighter path (step 8).none→ say so in one line and stop.No-database autodetect. When
db:is unset AND the project shows no database signal at all — noprisma/, nomigrations/directory, no*.sql, noalembic.ini/Gemfile, no ORM or driver dependency in a manifest, noDATABASE_URLin.env/.env.example— open with "no database in this project — nothing to pre-flight" and stop there. That is the honest answer up front, rather than reaching it the long way through a failed stack lookup in step 2. The conservative default is unchanged whenever a database MIGHT exist: any one signal present, ordb:set explicitly, means shared-prod strictness as before. Absence of every signal is the only trigger — never a partial match, and never an inference from "I couldn't find the stack."Identify the target: the folder or file named in the arguments, else the newest unapplied migration. Resolution is stack-dependent —
npx prisma migrate statusfor Prisma; otherwise the newest unapplied file in the project's migrations directory (Drizzle, Rails, Alembic, Flyway, plain SQL). If the stack cannot be determined or the target cannot be resolved, say exactly that and ask for the target path — never assume Prisma.Honest scope on non-Prisma stacks. Steps 3 (backup path) and 4 (classification) are stack-agnostic and run normally. Steps 5, 6, 7, and 8 name Prisma commands specifically, and the
allowed-toolswhitelist deliberately permits no migration CLI exceptprisma migrate status— running an arbitrary stack's CLI is exactly the mutation risk this skill exists to prevent. So on Drizzle/Alembic/Rails/Flyway/plain SQL, say plainly: "history-drift and command-discipline checks skipped —<stack>CLI is outside this skill's read-only whitelist; verify applied-migration history manually before the GO." A narrowed verdict stated is honest; a full verdict implied from a partial check is not.- Backup and undo path FIRST. Name the exact backup command (default
pg_dump "$DATABASE_URL" > backups/pre_<timestamp>.sql; config## migrate-checkbackup-commandoverrides) and the restore step. If no undo path can be identified, the verdict is NO-GO — automatically. - Classify every statement in the migration SQL per
references/sql-classification.md. Output a per-statement table: statement / class / risk / safe alternative where one exists. - History drift and folder reuse. Compare
migrate statusoutput withprisma/migrations/. Enforce the re-land rule: re-landing a previously dropped migration requires a NEW timestamped folder — a reused folder name already recorded in_prisma_migrationsis silently skipped and the table never created. Flag any drift between recorded history and the folder set. - Command discipline (shared-prod): author with
npx prisma migrate dev --create-only, apply withnpx prisma migrate deploy. NEVER plainmigrate devand neverdb pushagainst a shared database — both can reset or drift it. - Sequencing. Migrations are applied manually BEFORE merging code that
depends on them: CI/hosting builds run
prisma generate && next build(or equivalent) and never run migrations, so merged code referencing a not-yet-existing column fails at runtime. Confirm the ordering plan. db: locallighter path: file backup (cp prisma/dev.db prisma/dev.db.backup_<timestamp>), plainmigrate devacceptable, but statement classification (step 4) still runs — destructive is destructive on any database.
The verdict
The verdict is the report's FIRST line, then the evidence that earned it — a reader who stops after one line must still get the answer. Restate it at the end as a written block, always:
**Verdict: GO**— only when every statement is additive, history is clean, and the backup path is named. Include the exact next commands in order.**Verdict: NO-GO — <reason>**— for any destructive statement without an explicit user-acknowledged plan, missing undo path, folder reuse, or history drift. Include: what to check (expected row counts, expectedmigrate statusoutput), and a symptom → cause → action table for the likely failure modes.
Destructive operations are never a hard stop forever — they are a stop until the user explicitly acknowledges the classification table and the backup is confirmed taken. The skill's job is to make "I didn't realize it would drop that" impossible.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

