Crane: verified code migration

Crane is a migration assistant for GitHub repositories that plans, executes, and verifies code migrations in small agentic steps while keeping humans in control.

Russell Horton Russell Horton
A white crane flying across a blue circular background.

Introducing Crane, our newest Agentic Workflow, designed to make code migrations fast and sure-footed. To get started right away:

Install Crane using https://github.com/githubnext/crane/blob/main/install.md

Migrating existing code to more modern or more performant languages is one of the highest-return projects you can undertake. It’s also one where agents are especially capable.

Agents are excellent at executing work against a detailed spec, and when you already have a working, tested implementation, that’s about as good a spec as you can ask for. Migrating that project to another language becomes a matter of porting the existing tests, possibly writing new tests for more complete coverage, and then doing the work to make them pass. Because agents can quickly get deterministic feedback on their progress, they know exactly what work remains to be done, and they can fix their errors as they go.

Migration as a ratchet

The central idea in Crane is simple: migration progress should advance verifiably.

Every Crane migration defines four things:

  1. Source: the language, runtime, and paths being migrated from
  2. Target: the language or languages, runtime, and paths being migrated to
  3. Strategy: in-place, greenfield, or auto
  4. Verification: a command that prints a JSON health score

On the first run, Crane inventories the source, picks a strategy if you left it on auto, and writes a living plan broken into milestones. On later runs, it reads the plan, chooses the next milestone, implements one bounded step, runs verification, and accepts the change only if the new health score is at least as good as the previous one.

If verification passes and CI is green, Crane commits to a long-running branch for that migration, updates the plan, and advances the draft pull request. If verification fails, the change is discarded and the failed approach is recorded so the next iteration can try something else.

The health score

Crane expects each migration to define a verification command that outputs JSON with a migration_score between 0.0 and 1.0. The recommended convention is:

migration_score = correctness_gate * progress

The correctness gate is 1.0 only when the important correctness checks pass: source-side tests, target-side tests, parity tests, or whatever other project-specific evidence proves behavior is preserved. If correctness fails, the gate collapses to zero and the iteration is rejected.

Progress is the fraction of the migration that has been completed and verified. That can be measured by modules ported, APIs covered, parity cases passing, routes migrated, or a custom evaluator for the project.

A typical verifier might print something like this:

{
  "migration_score": 0.42,
  "progress": 0.55,
  "source_tests_passing": true,
  "target_tests_passing": true,
  "parity_passing": 18,
  "parity_total": 32,
  "perf_ratio": 1.4
}

This is intentionally strict. If a migration has no useful tests, Crane will not pretend otherwise. The first useful milestone is often to characterize the existing behavior with tests or a parity corpus, then migrate against that evidence.

In-place or greenfield

Crane supports two migration strategies, with auto as the default.

StrategyBest whenHow it moves
in-placeThe system is live, large, or has external consumersPort one unit at a time, route callers through the new implementation, and remove the old unit only after verification passes
greenfieldThe source is small, self-contained, or too tangled to interleave safelyBuild the target in parallel, prove parity against the source, and cut over when the target is complete

State management

All of Crane’s migration state lives in markdown on a dedicated memory/crane branch. It is a human-readable, version-controlled artifact with inventory, strategy rationale, milestones, current focus, lessons learned, blockers, and iteration history.

Each migration also gets its own long-running branch:

crane/<migration-name>

The branch accumulates accepted work. The draft pull request gives humans the familiar review surface: diffs, CI, comments, and merge control.

Starting a migration

Crane migrations can be defined in three ways:

  1. A GitHub issue with the crane-migration label
  2. A markdown file under .crane/migrations/
  3. A directory under .crane/migrations/<name>/ with a migration definition, evaluator, fixtures, and parity corpus

The issue path is the quickest way to begin. A migration issue defines the source, target, strategy, verification command, and out-of-scope paths. Crane discovers labeled migration issues and runs them on schedule.

The directory path is better when verification needs supporting code: a parity corpus, custom evaluator, fixtures, or staged source and target trees.

Crane also registers a /crane slash command, so you can steer a migration from an issue or pull request comment:

/crane stats_py_to_ts: port the quantile family next

That instruction becomes part of the next iteration’s context, without requiring you to manually edit workflow files.

What Crane is for

Crane is for migrations with a clear before, a clear after, and an executable definition of “still works.”

Good candidates include:

Begin your migration today

Just ask your coding agent:

Install Crane using https://github.com/githubnext/crane/blob/main/install.md