Migrationpilot

io.github.mickelsamuel由 GitHub 帳號 mickelsamuel 發布v1.6.4更新於 Oct 25, 2026

112 rules that catch dangerous PostgreSQL migrations, plus a pass/fail gate to call before any DDL.

已驗證STDIO僅桌面資料庫開發者工具

概覽

AI 產生的概覽

一個本機 MCP 伺服器,用 112 條規則檢查 PostgreSQL 遷移,並在執行 DDL 前為助理提供通過/不通過的關卡。

可以做什麼
在寫入或執行 DDL 前對擬議遷移做通過/不通過判定,回傳違規項目和摘要。分析單一遷移或整個目錄,給出規則違規、風險評分和鎖定分析。查詢某條規則的意義及是否可自動修復,並取得自動修復後的 SQL 和仍需人工處理的違規。解釋某條 DDL 語句會取得什麼鎖定、會阻塞什麼,並列出完整規則目錄。
適用情境
適合助理撰寫或修改 PostgreSQL 遷移、希望在進入審查或正式環境前做確定性檢查的情境。也適合已在 CI 中把關遷移、希望助理在本機看到相同結論的團隊。
執行需求
透過 npx(套件 migrationpilot-mcp)以本機程序執行,需要 Node.js 22 或更新版本;PostgreSQL 解析器已內建。不需要帳號、API 金鑰或環境變數。設定檔的解析方式與 CLI 相同,但伺服器本身不會讀取它。
安裝前請注意
分析為唯讀且在本機進行,沒有遙測。suggest_fix 工具會回傳改寫後的 SQL,套用前請先審閱產生的修正。未連線資料庫時風險評分有上限,因此在大表或繁忙資料表上可能低估鎖定的代價。README 說明 Windows 執行檔未做程式碼簽章。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Migrationpilot,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

MigrationPilot

[npm version] [npm downloads] [CI] [Node] [VS Code] [License: MIT]

Block unsafe Postgres migrations before merge.

Local, deterministic analysis for PostgreSQL migrations. Uses PostgreSQL's parser, checks 112 rules, and exits non-zero in CI. No account required. MIT.

bash
npx migrationpilot analyze migration.sql

Try it in your browser · GitHub Action · Documentation

Benchmark

ToolStrict detectionFalse positives
MigrationPilot31/33 (93.9%)1/17 (5.9%)
Squawk20/33 (60.6%)1/17 (5.9%)
pgfence25/33 (75.8%)3/17 (17.6%)

56 labelled files. Author-built corpus. Tools pinned.

Methodology · Corpus · What MigrationPilot missed · Reproduce: pnpm build && node bench/run.mjs

A finding

sql
-- migration.sqlALTER TABLE users ADD CONSTRAINT users_email_unique UNIQUE (email);
console
$ migrationpilot analyze migration.sql
  ✗ MigrationPilot —  RED  Score: 80/100  migration.sql  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  ─  1 statement · 2 critical · rollback GREEN
┌─────┬─────────────────────────────────────────────┬─────────────────────────┬────────┬────────────┐│ #   │ Statement                                   │ Lock Type               │ Risk   │ Long lock? │├─────┼─────────────────────────────────────────────┼─────────────────────────┼────────┼────────────┤│ 1   │ ALTER TABLE users ADD CONSTRAINT users_e... │ ACCESS EXCLUSIVE        │  RED   │ YES        │└─────┴─────────────────────────────────────────────┴─────────────────────────┴────────┴────────────┘
  Violations:
  ✗ [MP004] CRITICAL (line 1)    DDL statement acquires ACCESS EXCLUSIVE lock without a preceding SET lock_timeout. Without a timeout, this statement could block the lock queue indefinitely if it can't acquire the lock, causing cascading query failures.
    Safe alternative:    -- Set a timeout so DDL fails fast instead of blocking the queue    SET lock_timeout = '5s';    ALTER TABLE users ADD CONSTRAINT users_email_unique UNIQUE (email)    RESET lock_timeout;
    Why: Without lock_timeout, if the table is locked by another query, your DDL waits indefinitely. All subsequent queries pile up behind it in the lock queue, causing cascading timeouts across your application. GoCardless enforces a 750ms lock_timeout for this reason.    Docs: https://migrationpilot.dev/rules/mp004
  ✗ [MP027] CRITICAL (line 1)    Adding UNIQUE constraint "users_email_unique" on "users" scans the entire table under ACCESS EXCLUSIVE lock. Create the index concurrently first, then use USING INDEX.
    Safe alternative:    -- Step 1: Create the unique index concurrently (non-blocking)    CREATE UNIQUE INDEX CONCURRENTLY users_email_unique_idx ON users (...);
    -- Step 2: Add the constraint using the pre-built index (instant)    ALTER TABLE users ADD CONSTRAINT users_email_unique UNIQUE USING INDEX users_email_unique_idx;
    Why: ALTER TABLE ADD CONSTRAINT UNIQUE builds a unique index while holding ACCESS EXCLUSIVE lock, blocking all reads and writes for the entire scan. Instead, create the unique index concurrently (non-blocking), then attach it as a constraint with USING INDEX.    Docs: https://migrationpilot.dev/rules/mp027
  Risk Factors:    Lock Severity        ██████████ 40/40 — ACCESS EXCLUSIVE (long-held)    Rule Violations      ████████░░ 80/100 — 2 critical
  112 rules checked in 11ms

Exit code is 2. The Risk column combines what a statement's lock does with what the rules found in it, so a statement carrying a critical violation reads RED whatever its lock costs. The lock half of that is capped without a database connection — table size and query frequency need one. See Production context.

Contents

Install · AI coding agents · CI · What it checks · Beyond one file · Configuration · Output · Production context · Comparison · Pricing · Architecture · API

Install

bash
npx migrationpilot analyze migration.sql   # no installnpm install -g migrationpilot              # global

Node 22 or newer. The PostgreSQL parser ships compiled in, so there is nothing else to set up. Exit codes are the same everywhere: 0 clean, 1 warnings under --fail-on warning, 2 critical.

Packaged builds land with each release, including single-file executables for Linux, macOS and Windows on the release page for machines without Node. The Windows .exe is not code-signed, so SmartScreen and most browsers will warn about it on download — SHA256SUMS on the same release is how you check you got the file we published, not a signature.

bash
brew install mickelsamuel/migrationpilot/migrationpilotdocker run --rm -v "$PWD:/work" ghcr.io/mickelsamuel/migrationpilot:1 analyze migration.sql

On Windows in Git Bash, MSYS rewrites paths inside the mount flag, so use the Windows-form working directory instead:

bash
docker run --rm -v "$(pwd -W):/work" ghcr.io/mickelsamuel/migrationpilot:1 analyze migration.sql

AI coding agents

Agents write migrations now. They are good at SQL and bad at knowing which statement takes an ACCESS EXCLUSIVE lock on a table with 40 million rows, and by then the outage has already happened.

MCP server. Seven tools, the important one being check_before_apply: a pass/fail gate the agent calls before it writes or runs DDL. It resolves your .migrationpilotrc.yml exactly like the CLI does, so its verdict is the verdict CI will give.

json
{  "mcpServers": {    "migrationpilot": { "command": "npx", "args": ["migrationpilot-mcp"] }  }}
ToolPurpose
check_before_apply{sql, pgVersion?, configPath?} returns {verdict: pass|fail, failOn, violations[], summary}
analyze_migrationViolations, risk score and lock analysis for one migration
analyze_migration_dirPer-file results plus an aggregate for a whole folder
get_ruleWhat a rule reports, why it matters, whether it auto-fixes
suggest_fixAuto-fixed SQL plus the violations that need a human
explain_lockThe lock one DDL statement takes and what it blocks
list_rulesThe full catalogue

Claude Code plugin. integrations/claude-code/ pairs a skill that tells Claude to check migrations with a PreToolUse hook that blocks the tool call when it doesn't. It fails open on purpose: a missing install, unparseable SQL, or a timeout lets the call through with a note on stderr, because a guardrail that breaks your workflow when it can't run gets uninstalled.

bash
claude plugin install ./integrations/claude-code

Cursor and Copilot. Copy integrations/cursor/migrationpilot.mdc into .cursor/rules/, or paste integrations/copilot/copilot-instructions-snippet.md into .github/copilot-instructions.md. Both tell the agent when to run MigrationPilot and that suppressing a rule to get past a violation is the user's call, not the agent's.

CI

GitHub Action

yaml
# .github/workflows/migration-check.ymlname: Migration Safety Checkon: [pull_request]
# New repositories default the workflow token to read-only; the report comment# needs pull-request write.permissions:  contents: read  pull-requests: write
jobs:  check:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v4      - uses: mickelsamuel/migrationpilot@v1        with:          migration-path: "migrations/*.sql"          fail-on: critical

Posts a report as a PR comment, fails the check on critical violations, and writes a SARIF file. To feed it into Code Scanning, add an upload step (needs Advanced Security on private repos):

yaml
      - uses: github/codeql-action/upload-sarif@v3        if: always()        with:          sarif_file: migrationpilot-results.sarif

Without the permissions block the Action still runs. It warns, analyzes every file matching the glob instead of only the ones the PR changed, and skips the comment. The check verdict, the SARIF file and the inline annotations come from the analysis either way.

A migration the Action can't read or parse fails the check, since nothing analyzed it, and the failure names the file and the parser's error. Files that aren't plain SQL, like ones with psql meta-commands or template placeholders, go under ignore in the config. With fail-on: never they're reported and the check passes.

The Action reads the same config file as the CLI, so ignore, rules, failOn, pgVersion and extends all apply there. An input you set in the workflow wins over the config. With an Org license key, so do the config's policy block and audit log, and the policy wins over the inputs: exclude can't drop a required rule, and a blocked statement fails the check even under fail-on: never.

InputDescriptionDefault
migration-pathGlob for SQL files, or a directory for every .sql file under it (required)
github-tokenToken for PR comments${{ github.token }}
pg-versionTarget PostgreSQL versionconfig pgVersion, else 17
fail-oncritical, warning, irreversible, neverconfig failOn, else critical
excludeComma-separated rule IDs to skip
config-filePath to the config filenearest .migrationpilotrc.yml
database-urlConnection for production context
license-keyOrg plan key from a secret. Turns on the config's policy block and audit log; every rule runs without itMIGRATIONPILOT_LICENSE_KEY env

Outputs: risk-level, violations, sarif-file.

Pre-commit

migrationpilot hook install writes a plain git hook and is Husky-aware. With the pre-commit framework instead:

yaml
repos:  - repo: https://github.com/mickelsamuel/migrationpilot    rev: v1.6.0    hooks:      - id: migrationpilot        args: [--fail-on, warning]

Clean files print nothing. Only migrations with violations are reported.

If pre-commit install answers Cowardly refusing to install hooks with 'core.hooksPath' set, something else already owns your hooks directory — Husky sets it. Check with git config core.hooksPath, then either git config --unset-all core.hooksPath and let pre-commit manage the hooks, or keep Husky and run migrationpilot hook install, which appends to .husky/pre-commit instead of fighting it.

GitLab CI

yaml
include:  - remote: 'https://raw.githubusercontent.com/mickelsamuel/migrationpilot/v1.6.0/integrations/gitlab/.gitlab-ci-migrationpilot.yml'
migrationpilot:  variables:    MIGRATIONPILOT_PATH: db/migrate

Runs on merge requests that touch migrations, keeps the JSON report as an artifact, and annotates the MR diff through GitLab Code Quality.

What it checks

112 rules: 34 critical, 78 warning, 20 auto-fixable with --fix. Ten that matter most:

RuleFixWhat it catches
MP001YesCREATE INDEX without CONCURRENTLY blocks writes for the whole build
MP002SET NOT NULL scans the full table. Use the validated CHECK pattern
MP003ADD COLUMN with a volatile DEFAULT rewrites the table and its indexes
MP007ALTER COLUMN TYPE rewrites the table under ACCESS EXCLUSIVE
MP008Several DDL statements in one transaction compound the lock duration
MP025YesCONCURRENTLY inside a transaction is a runtime ERROR, not a warning
MP027UNIQUE constraint without USING INDEX scans the table under an exclusive lock
MP055Dropping a primary key breaks logical replication
MP070A failed concurrent build leaves an invalid index the retry silently inherits
MP097Dropping the index behind a constraint is rejected and aborts the migration

Browse all 112 rules, or run migrationpilot explain MP027 for one. The handbook is 20 chapters on why each hazard bites and what to do instead.

Rules adapt to --pg-version (9 through 18): REINDEX CONCURRENTLY from 12, DETACH PARTITION CONCURRENTLY from 14, the native NOT NULL ... NOT VALID path from 18.

Beyond one file

analyze --fix rewrites the 20 fixable violations in place. The rest of the surface:

CommandWhat it does
check <dir>Whole directory, plus cross-file sequence analysis
simulateRuns the migration against an ephemeral in-process PostgreSQL 18 (PGlite) and reports what actually happened
plan-fixStep-by-step expand-contract plan for violations with no one-line fix, with deploy boundaries
mutation-testMutates passing migrations into dangerous near-neighbours to find holes in your config
predictDuration estimate for an operation, calibrated by --row-count and --size
templateGenerates expand-contract SQL for renames, type changes, NOT NULL, and more
planVisual execution timeline: lock, duration, blocking impact, transaction boundaries
rollbackReverse DDL, graded by how recoverable it is
driftDiffs two live schemas
precommitMulti-file entry point the pre-commit framework calls

Twenty-four commands in total. migrationpilot --help lists them.

Sequence analysis is what a per-file linter cannot see. Three migrations that each look fine can still take one table down together:

console
$ migrationpilot check migrations/
  ⚠ [SQ001] WARNING cumulative-lock-budget    "orders" is locked for an estimated 2m across 2 statements in 2 files — over the 1m budget for one deploy.  ⚠ [SQ002] WARNING hot-table-multi-touch    "orders" is locked by 3 files in this sequence. Each one queues behind live traffic on its own — fold them into one migration so the table takes the hit once.

Tune it with --lock-budget <seconds> and --hot-table-threshold <files>, turn it off with --no-sequence, and make it blocking with --fail-on-sequence.

--fail-on irreversible is stricter than critical: it also blocks migrations that destroy data with no down file.

Configuration

Zero-config is the default. check with no directory detects your framework, finds its migrations, and analyzes them in apply order. Fourteen are supported: Flyway, Liquibase, Alembic, Django, Knex, Prisma, TypeORM, Drizzle, Sequelize, goose, dbmate, Sqitch, Rails, Ecto. Force one with --framework prisma, or pipe any generator through --from-command:

bash
migrationpilot check --from-command "python manage.py sqlmigrate myapp 0042"
yaml
# .migrationpilotrc.ymlextends: "migrationpilot:strict"pgVersion: 16failOn: warningrules:  MP037: false                 # off  MP004: { severity: warning } # downgrade  MP013: { threshold: 5000 }   # retuneignore:  - "migrations/seed_*.sql"

Five presets: recommended (default), strict, ci, startup, enterprise. Inline, -- migrationpilot-disable MP001 suppresses a rule for the next statement and -- migrationpilot-disable-file MP001 does it for the whole file. Name no rule and it suppresses all of them.

Org policy

With an Org plan key in MIGRATIONPILOT_LICENSE_KEY (or --license-key, or the Action's license-key input), analyze, check, precommit and the Action apply the config's policy block. watch, plan, simulate and mutation-test keep the required rules on and hold the floor too, but only the gates fail on a blocked pattern.

yaml
policy:  requiredRules: [MP001, MP004]   # run whatever rules:, a preset, --exclude or a disable comment says  severityFloor: critical         # a critical rule can't be set below critical  blockedPatterns: ["DROP TABLE", "TRUNCATE"]   # fail the run whatever --fail-on says  requireReviewPatterns: ["ALTER TYPE"]         # reported for team reviewauditLog:  enabled: true                   # one JSONL line per check

Each override prints a note saying what it kept on. A rule that ships as a warning stays a warning under a critical floor. Patterns match whole words, ignoring case, whitespace and comments. Without a valid key, the run says the policy isn't applied rather than passing quietly. --no-config skips the config file and the policy with it, so enforce from CI, where the config gets reviewed like code. The MCP server doesn't read the config.

Ed25519 license keys validate client-side, with no network call. --offline skips update checks and every other network call. There is no telemetry.

Output

--format text (default), json, sarif, or markdown, plus --quiet for one gcc-style line per violation and --verbose for per-statement pass/fail.

json
{  "$schema": "https://migrationpilot.dev/schemas/report-v1.json",  "version": "1.6.0",  "file": "migrations/001.sql",  "riskLevel": "RED",  "riskScore": 80,  "violations": []}

SARIF feeds GitHub Code Scanning, VS Code and IntelliJ: migrationpilot analyze migration.sql --format sarif --output results.sarif.

Production context

Pass --database-url and MigrationPilot opens one read-only connection to read pg_class, pg_stat_statements and pg_stat_activity. It reads no user data and runs no DDL.

That turns risk scoring from a guess into a measurement, and gives three rules the numbers they have nothing to say without: MP013 (DDL on a high-traffic table), MP014 (long-held locks on a table with millions of rows), MP019 (ACCESS EXCLUSIVE while connections are piling up).

FactorWeightNeeds --database-url
Lock severity0-40No
Table size0-30Yes
Query frequency0-30Yes

GREEN is 0-24, YELLOW 25-49, RED 50-100.

Comparison

MigrationPilotSquawkAtlas
Rules, all free1124050+ analyzers, lock analyzers Pro-only
Auto-fix20 rules00
Cross-file sequence analysisYesNoNo
Real execution against ephemeral PGYesNoYes, needs Docker
MCP server for agentsYesNoNo
Framework detection1400
Config presets500
SARIF for Code ScanningYesNoNo
LicenseMITApache-2.0 / MITApache-2.0 core, no free lint

Squawk: 40 rules as of v2.62.0 (Aug 2026). Atlas gates migrate lint behind a Pro login in the official binary since v0.38 (Oct 2025); the Community build keeps a basic analyzer set, but the PostgreSQL lock analyzers are Pro-only. It could not be benchmarked without a paid account. The methodology records the exact command and its refusal.

Pricing

Everything the linter does is free and unmetered: all 112 rules including the production-context ones, auto-fix, sequence analysis, simulate, every output format, the GitHub Action, the MCP server. No account, no seat count, no telemetry, MIT.

The $499/year Org plan turns the free linter into an enforceable control: one policy across repositories that developers cannot quietly disable, a JSONL audit trail of every check, and direct support from the maintainer.

Org plan · Full pricing

Architecture

src/├── parser/ locks/         # libpg-query WASM, lock classification├── rules/ fixer/          # 112 rules and the 20-rule auto-fixer├── analysis/ scoring/     # shared pipeline, transaction boundaries, risk 0-100├── sequence/ lockqueue/   # cross-file SQ rules, lock queue modelling├── simulate/ mutate/      # PGlite execution, mutation-testing operators├── cascade/ graph/ schema/ prediction/ templates/├── production/ frameworks/ plugins/ output/ generator/├── mcp/ action/ config/ hooks/ watch/ drift/ history/├── policy/ auth/ license/ team/ audit/ billing/ usage/ doctor/├── index.ts               # programmatic API, 69 value exports plus types└── cli.ts                 # 24 commands

Programmatic API

typescript
import { analyzeSQL, allRules, parseMigration, classifyLock } from 'migrationpilot';
const result = await analyzeSQL(sql, 'migration.sql', 17, allRules);console.log(result.violations, result.overallRisk);

Sixty-nine value exports plus full TypeScript types. allRules is the same rule set the CLI runs.

Development

bash
pnpm installpnpm test        # 1945 tests across 72 filespnpm build       # CLI 1.4MB, Action 1.7MB, API 639KB, MCP 1.7MBpnpm lint && pnpm typecheckpnpm dev analyze path/to/migration.sql

CONTRIBUTING.md · SECURITY.md · CHANGELOG.md

License

MIT

來源:README.md,提交 157bcc5

工具

0
SourceWeft 尚未在沙箱中啟動過該軟體包,因此其工具未知。

版本歷史

3
  1. v1.6.4最新Oct 13, 2026
  2. v1.6.3Oct 13, 2026
  3. v1.6.1Sep 16, 2026

評分

已滿足適用檢查項的 50%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分