Skip to content

How to Migrate Code and Frameworks With AI Safely

Python 2→3, a framework major, a language port — migrations are where agents shine or set fires. The incremental, test-guarded playbook that keeps prod up.

The Vibe Father 8 min read

Playbook

Migrations are where AI enthusiasm meets reality hardest. "Upgrade this to React 19," "move us from Express to Fastify," "get us onto the new ORM" — the agent dives in, rewrites forty files in one heroic pass, and hands you a diff that doesn't build, can't be reviewed, and can't be rolled back to a known-good point. Now you're not migrating; you're archaeology. The fix isn't a smarter agent. It's a method: small test-guarded steps, the build green between every one, and a checkpoint before each run so any step can be undone in seconds.

We migrate with agents regularly, and the ones that go smoothly all share the same shape. Here's the playbook.

Step 1 — Read the upgrade guide first

Before a single line changes, the agent reads the official migration or upgrade guide for the version or framework you're moving to — and summarizes the breaking changes that actually touch your code. This matters because the agent's training data remembers the old API; the guide has the new one and the exact renames, removals, and behavior changes. Skip this and the agent will confidently write code against the version it half-remembers, which is the version you're trying to leave. Have it produce a short list: what breaks, what's renamed, what's deprecated, and which of those your codebase actually uses.

👑
The build stays green between every step. A migration is a sequence of small correct states, never one big broken one.

Step 2 — Make it green before you start

You cannot migrate safely without a test suite that passes now, because that green suite is your only detector for "did this step break something." If coverage is thin around the code you're migrating, add tests first — see writing tests with AI that actually catch bugs. A migration with no tests is a rewrite you're doing blind; the tests are what turn each step from a leap into a check.

Step 3 — Slice into the smallest steps that build

The single biggest mistake is one giant pass. Instead, break the migration into the smallest units that each leave the build green: one module, one API surface, one deprecated call pattern at a time. After each slice: run the build, run the tests, confirm green, commit. A migration done in twenty small commits is reviewable and reversible; the same migration in one 2,000-line commit is neither. Tell the agent explicitly: change one coherent slice, get to green, stop, and let me confirm before the next.

Step 4 — Checkpoint before every run

Migrations fail mid-slice — the agent hits a case the guide didn't mention and starts thrashing. When that happens you want to be one command from a clean state, not untangling a half-applied change by hand. So take a checkpoint (a commit, a tag, or a worktree snapshot) before each slice runs. If the slice goes wrong, discard and retry from a known-good point instead of debugging the wreckage. This is exactly what checkpoints and worktrees exist for, and migrations are their best use case.

Step 5 — Write both directions for data migrations

If the migration touches the database schema, every change gets both an up and a down. The up applies the change; the down reverses it cleanly. Agents love to write the up and skip the down, which means the moment something's wrong in production you have no way back. Insist on both, and test the down by actually running it: apply, verify, roll back, verify the schema returned to its prior shape. A migration you can't reverse is a decision you can't unmake.

The step loop, as a table

Per sliceWhat it guaranteesOrder
Checkpoint before runningYou can undo instantly1
Apply one small changeReviewable, reversible2
Build + full testsNothing silently broke3
Commit on green, then stopA known-good point to build on4

The copy-paste migration prompt

We are migrating <from X> to <to Y>. Follow this method strictly.

1. Read the official upgrade guide for <Y>. List the breaking
   changes that touch OUR code specifically: renames, removals,
   behavior changes. Do not migrate from memory of the old API.

2. Confirm the test suite is green right now. If coverage is thin
   around the affected code, add tests first and stop for my OK.

3. Migrate in the SMALLEST slices that keep the build green - one
   module or one call pattern at a time. After each slice: run the
   build and tests, paste real output, commit on green, then STOP
   and wait for me before the next slice.

4. For any schema change, write BOTH the up and the down migration,
   and test the down by actually rolling back.

Never make one large pass. Green between every step or we revert.

Choosing a model for the job

Migrations reward reasoning over speed — the hard part is untangling how the old and new APIs differ across your specific code. For a big, high-stakes framework migration, use your strongest model (Fable 5 leads our benchmarks at 95.0 SWE; Opus 4.8 for daily driving). For mechanical, repetitive slices — a deprecated call replaced the same way across fifty files — a fast, cheap model like Gemini Flash or DeepSeek runs the loop economically once you've verified the pattern on the first slice.

A migration is really a long chain of small changes, each of which needs the same discipline as any other: verify it, review it, and keep a green suite behind it. When a slice does break something, fixing bugs with AI applies, and a cross-model pass via the AI code review workflow catches the subtle behavior changes a migration hides. In The Vibe Father, checkpoints and git worktrees make "revert this slice" a single click and the AutoVibe gate re-runs your real build between steps — but the method above is just git commits and discipline, and it works anywhere.

Run every AI coding tool. Keep every conversation. Own your work.

The Vibe Father is the model-agnostic command deck we built for ourselves — 22 CLIs, multi-agent teams, your own keys.

Keep reading