Skip to main content

Migrating legacy code

Legacy migrations work well when you break them into small, repeatable graph nodes. Start by discovering patterns, then migrate in slices.

Identify migration patterns first

Run deterministic scans to find candidates and group them.

steps:
- id: list_candidates
run: rg "oldApiCall" src -l

- id: group_patterns
structured_prompt:
prompt: |
Group these files by migration pattern:
{{ outputs.list_candidates }}
returns:
type: object
required: [groups]
properties:
groups:
type: array
items:
type: object
required: [pattern, files]
properties:
pattern: { type: string }
files:
type: array
items: { type: string }

starts_with: list_candidates
ends_with: group_patterns

edges:
- from: list_candidates
to: group_patterns

Generate a migration guide artifact

Use a prompt or agent to write a guide, then save it as an artifact so the rest of the workflow can reuse it.

Guides are useful for:

  • codifying the new API or pattern
  • listing constraints and exceptions
  • defining test or verification steps

Migrate in slices

Use for_each to apply one pattern or file at a time. Keep instructions narrow and add constraints that prevent unrelated changes.

steps:
- id: group_patterns
structured_prompt:
prompt: "Group files by migration pattern."
returns:
type: object
required: [groups]
properties:
groups:
type: array
items:
type: object
required: [pattern, files]
properties:
pattern: { type: string }
files:
type: array
items: { type: string }

- id: migrate_one_file
name: Migrate one file
for_each:
from: '{{ outputs.group_patterns.groups[0].files | json_encode() }}'
agent:
extends: Coding
instructions: "Migrate {{ for_each.value }} to the new API."
constraints:
- "Do not change other files."
- "Keep public behavior the same."

starts_with: group_patterns
ends_with: migrate_one_file

edges:
- from: group_patterns
to: migrate_one_file

Handle long runs

  • Use continue_on_error: true on the migration step so you can collect failures.
  • Use task graphs if you want to branch to a recovery path.
  • Pair the workflow with Incremental workflow builds so every slice saves a resumable snapshot and you can restart from the last healthy step instead of replaying the entire migration.