FISTA Solutions does not load Google Analytics until you accept. Rejecting keeps optional analytics off. Read the Cookie Policy.

All field notes

Playbook · 5 minute read

How to Modernize Legacy Code With AI Agents

Modernizing legacy code with AI agents means using agents for the volume work, documenting, characterizing, and transforming code module by module, under strict verification: characterization tests captured before any change, specifications that forbid behavior changes, gates that compare old and new behavior, and staged cutover with rollback. Agents accelerate; verification decides.

By FISTA Solutions· AI-Native Engineering Team·
How to Modernize Legacy Code With AI Agents article cover

Legacy modernization has always been throttled by reading: understanding code nobody documented, capturing behavior nobody specified, and transforming it without breaking the quirks the business quietly depends on. Coding agents change the reading and the transforming; they do not change the need for verification, and they can break legacy behavior with the same plausibility they fix it. This playbook sequences the work so agents do the volume and verification decides. It applies the agentic SDLC whitepaper to the program described in legacy system modernization and the legacy modernization with AI whitepaper.

Step 1: What can agents do in modernization, and what can they not?

TaskAgent roleHuman role
Explain code and map dependenciesGenerate explanations, call graphs, and data-flow summaries with citationsVerify against domain knowledge
Characterize behaviorGenerate characterization tests from code and observed inputsReview coverage; add business-critical cases
Transform codeMechanical migration within constraints: language, framework, API patternsSpecify constraints; review by risk class
Design target architecturePropose optionsDecide
VerifyRun gates and comparisonsDesign gates; judge failures
Cut overPrepare runbooksApprove and execute

Step 2: Inventory and slice the system

Use agents to document modules, dependencies, entry points, and data flows, with citations to the code. Slice the system into migration units by dependency and business function. Rank slices by value, risk, and independence. The first slice is chosen for learning: self-contained, understood, low risk.

Step 3: Why do characterization tests come first?

Before any transformation, capture what the code does: unit-level characterization tests generated by agents from the code and from recorded inputs and outputs, reviewed by engineers who add the business-critical cases the code alone does not reveal. Coverage of the slice's observable behavior, including its quirks, is the gate for proceeding. Behavior nobody captured cannot be preserved.

Step 4: Specify each slice

Each migration slice gets a specification: intent (migrate module X from A to B), scope, interfaces that must remain identical, the no-behavior-change constraint, prohibited changes (tests, interfaces, data formats), acceptance criteria (characterization tests pass; output comparison matches), and risk class. Intended behavior improvements are separate specifications after migration. The discipline is in spec-driven development with coding agents.

Step 5: Transform with constraints

Agents perform the transformation under the specification, with a constraints library that encodes the target architecture's rules. Access boundaries keep agents out of production and secrets; see the AI-generated code security checklist. Agents cannot modify the characterization tests within the same change.

Step 6: How is behavior preservation verified?

  • Characterization tests pass on the new implementation.
  • Differential testing: old and new implementations run on the same inputs, outputs compared, differences triaged as bugs in the migration or captured quirks to decide on.
  • Static analysis with target-architecture rules.
  • Performance comparison against the baseline.
  • Security scans on the new code.

Any difference blocks the slice until it is explained and either fixed or accepted as an intended change through a separate specification.

Step 7: Run shadow mode on real traffic

Where the module processes requests, run old and new side by side on production traffic with the new implementation's output compared but not used. Real traffic reveals inputs the tests never imagined. Continue until agreement is stable. The method is how to run shadow-mode deployments.

Step 8: Cut over with the strangler pattern

Route traffic to the new module incrementally with instant rollback, keep the old path available until confidence is established, then retire it. Repeat slice by slice. The legacy system keeps running throughout; there is no big-bang moment.

How do you handle data and integration boundaries?

Code is the easier half of most modernizations. Data formats, schemas, and the contracts other systems depend on are where migrations break in production.

BoundaryRiskApproach
Data formats and schemasNew implementation reads or writes differently; downstream consumers breakFreeze formats in the specification; migrate schemas as separate, reversible steps; differential-test serialized outputs byte for byte where possible
Integration contractsAPIs, files, and messages other systems consume change subtlyContract tests generated from recorded traffic; consumers notified only for intended changes
Shared stateOld and new implementations write to the same store during shadow modeShadow mode writes to a comparison store, never the live one, until cutover
Batch jobs and schedulesTiming and ordering assumptions hidden in cron and job dependenciesDocument with agent help; keep schedules identical through cutover

Agents are useful here for the reading: extracting every format, contract, and schedule a module touches and producing the inventory that the specification and the differential tests are built from. Humans decide which quirks in that inventory are load-bearing. Feature flags around each boundary allow the cutover to be reversed at the boundary level rather than the whole slice.

Step 9: Measure the program

MetricWhy
Defects per migrated slice, by phase foundWhether verification catches what it should
Rollback rateCutover safety
Characterization coverage before transformationGate discipline
Time per sliceProgram velocity, secondary to quality
Retired legacy footprintProgress

Lines migrated is a vanity metric; a fast migration that ships behavior changes is a regression.

What are the common mistakes?

  1. Transforming before characterizing.
  2. Letting agents "improve" behavior during migration.
  3. Big-bang rewrites.
  4. Trusting tests the agent wrote without review of business-critical cases.
  5. Skipping differential testing because the unit tests passed.
  6. Measuring lines instead of defects and rollbacks.

How does FISTA Solutions help?

FISTA Solutions runs modernization programs with coding agents under this playbook, through forward deployed engineers who work inside your teams on your systems, AI enablement to install the pipeline and gates, and staff augmentation for throughput once the pattern exists. FISTA has delivered 150+ projects for 50+ companies across 12+ countries with 99.9% uptime.

To scope a first migration slice, message FISTA on WhatsApp, or read AI code migration for the transformation techniques.

Share-ready article cover

Download the generated social format.

Download cover

Clear answers

Questions raised by this field note.

Straightforward guidance for evaluating scope, fit, and the next step.

01Can AI agents modernize a legacy system on their own?

No. They can document it, generate characterization tests, and perform mechanical transformations far faster than people, but the architecture decisions, the verification design, and the judgment about what behavior to preserve or change are human work. Used under that structure, agents compress the volume work dramatically.

02What is a characterization test and why does it come first?

A characterization test captures what the existing code actually does, including its quirks, rather than what it should do. It is the safety net that lets any transformation be checked for behavior change. Without it, an agent's plausible rewrite cannot be verified, and legacy quirks that the business depends on get lost.

03How do you keep agents from changing behavior?

Specify every migration slice with an explicit no-behavior-change constraint, gate the change on the characterization tests and on comparison of outputs between old and new implementations, forbid changes to tests within the same change, and run shadow mode on real traffic before cutover. Intended behavior changes are separate, later specifications.

04Where should modernization start?

With a module that is self-contained, well understood, and low risk, to build the pipeline, the test approach, and the team's habits. Then move to modules by business value and risk, using the strangler pattern so the legacy system keeps running while pieces are replaced.

Start with the hard problem

Need the outcome owned, not merely analyzed?

Tell us where delivery is constrained. We’ll map the fastest credible path from intent to verified production.

Start a project