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.
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?
| Task | Agent role | Human role |
|---|---|---|
| Explain code and map dependencies | Generate explanations, call graphs, and data-flow summaries with citations | Verify against domain knowledge |
| Characterize behavior | Generate characterization tests from code and observed inputs | Review coverage; add business-critical cases |
| Transform code | Mechanical migration within constraints: language, framework, API patterns | Specify constraints; review by risk class |
| Design target architecture | Propose options | Decide |
| Verify | Run gates and comparisons | Design gates; judge failures |
| Cut over | Prepare runbooks | Approve 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.
| Boundary | Risk | Approach |
|---|---|---|
| Data formats and schemas | New implementation reads or writes differently; downstream consumers break | Freeze formats in the specification; migrate schemas as separate, reversible steps; differential-test serialized outputs byte for byte where possible |
| Integration contracts | APIs, files, and messages other systems consume change subtly | Contract tests generated from recorded traffic; consumers notified only for intended changes |
| Shared state | Old and new implementations write to the same store during shadow mode | Shadow mode writes to a comparison store, never the live one, until cutover |
| Batch jobs and schedules | Timing and ordering assumptions hidden in cron and job dependencies | Document 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
| Metric | Why |
|---|---|
| Defects per migrated slice, by phase found | Whether verification catches what it should |
| Rollback rate | Cutover safety |
| Characterization coverage before transformation | Gate discipline |
| Time per slice | Program velocity, secondary to quality |
| Retired legacy footprint | Progress |
Lines migrated is a vanity metric; a fast migration that ships behavior changes is a regression.
What are the common mistakes?
- Transforming before characterizing.
- Letting agents "improve" behavior during migration.
- Big-bang rewrites.
- Trusting tests the agent wrote without review of business-critical cases.
- Skipping differential testing because the unit tests passed.
- 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.
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.
Continue exploring
Related capabilities
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.