
Mistral used AI agents to modernize the first 40,000 lines of a roughly 300,000-line Fortran 77 reservoir simulator. The number is impressive. The useful part came before most of the new C++ was written.
The legacy application had no test suite and no centralized documentation. Before scaling up the rewrite, Mistral built a way to check whether the new code still behaved like the old code. In its September 9, 2026 case study, Mistral says the team built a numerical parity harness, reconstructed documentation, and kept human review in the final migration workflow.
That is the practical AI legacy code modernization lesson. If a poorly documented application still runs the business, the first useful agent may be the one writing probes, fixtures, regression tests, comparison tools, and documentation. Give the model an answer key before asking it to rewrite the exam.
Key takeaways
Mistral built a numerical parity harness before the main migration. The old Fortran exported state snapshots, and the new C++ implementation had to reproduce important outputs and intermediate values.
Full agent autonomy produced functional code that still looked architecturally like Fortran. Global state survived as global structs, and old control-flow patterns survived the language change.
Mistral eventually settled on bounded modules, specialized coder, tester, and reviewer agents, plus a human who could approve architecture and unblock failures.
A test harness can show that captured behavior survived. It cannot show that the old behavior was correct or that an uncaptured edge case is safe.
The pattern extends beyond Fortran. A runnable legacy COBOL, C, C++, Perl, Java, or other application can often serve as the reference implementation while AI changes one bounded slice at a time.
Start AI legacy code modernization by making the old system observable
If you have an old application with weak documentation and poor test coverage, do not start with a prompt asking an agent to rewrite the whole application.
Start by making the existing application observable.
Capture representative inputs. Record outputs, state changes, error behavior, file formats, database effects, numerical tolerances, and important intermediate values. Turn those observations into automated comparisons. Ask domain experts which invariants cannot move without breaking the business or the science.
Only then start the modernization work.
Software testing already has a term for the reference that tells you whether a result is acceptable: a test oracle. ISO/IEC/IEEE 29119 defines a test oracle as a source of information for deciding whether a test passed or failed, and notes that another program or system can serve as the comparison.
For a legacy rewrite, the old application can become that answer key for the behaviors you intend to preserve.
AI can make replacement code cheap to produce. It does not make correctness cheap to establish. The faster an agent can change code, the more valuable a trustworthy automated failure signal becomes.
What Mistral actually did with the Fortran simulator
The original application was a physics-heavy Fortran 77 reservoir simulator. Mistral describes a codebase built around global state in COMMON blocks, implicit typing, old control-flow patterns, scattered documentation, and architectural assumptions accumulated over many years.
A direct line-by-line translation would have preserved too much of that structure. Moving a calculation into modern C++ can mean replacing global arrays with explicit data structures, changing function boundaries, moving loops to different layers, and integrating modern scientific libraries. Once the architecture changes, comparing line 4,212 in Fortran with line 4,212 in C++ tells you almost nothing useful.
Mistral instead instrumented the Fortran program so it could export state. The C++ side loaded those reference checkpoints and compared the migrated implementation against them. Reservoir engineers identified intermediate numerical values worth checking in addition to final outputs. That gave the agents a machine-readable target for behavioral parity.
The team also used agents to rebuild documentation. It parsed the Fortran into a caller-callee tree, then used more than 100 agents to work upward through that tree while pulling context from existing PDFs and source comments. Reviewer agents examined the resulting documentation pull requests.
That sequence is important. The agents were not asked to understand, redesign, rewrite, and validate a poorly documented system in one giant pass. The project first created better evidence about what the code did and a better mechanism for catching behavioral drift.
Why the first autonomous rewrite was disappointing
Mistral’s failed experiment is more useful than the headline number.
In the first attempt, the company assigned an autonomous agent to each Fortran subroutine. The agents spent about a week translating their assigned functions independently.
The result worked, but the architecture barely moved. Mistral says the COMMON blocks largely became global C++ structs while GOTO-driven logic survived instead of being redesigned around cleaner loops and returns.
That is a warning for one-shot AI rewrites. A model asked to translate code has a strong incentive to preserve the structure in front of it. Behavioral similarity can be easier to achieve by carrying old design decisions into the new language. You can end up with modern syntax wrapped around the same old architecture.
Mistral then tried a planner, coder, tester, and code-quality reviewer working together. Code quality improved, but agents could get stuck on difficult bugs and stall. The final process put a human back in charge of the loop, with agents operating inside a bounded workflow rather than owning the migration end to end.
Make the legacy application reproducible before touching architecture
Before changing architecture, make sure somebody other than the current caretaker can build and run the old system.
Freeze a known baseline in source control. Record compilers, dependencies, configuration, datasets, environment variables, external services, startup instructions, and the exact commands required to reproduce representative workloads. If a test depends on a particular database snapshot or input file, preserve that dependency too.
Mistral had a favorable starting point because the simulator was self-contained and runnable, while systems that depend on external services or lack a runnable baseline create additional migration problems.
That limitation is easy to miss when looking at a successful demo. A 30-year-old production application may depend on a dead service, an undocumented batch job, a database nobody can safely clone, or hardware the team cannot reproduce. Before an agent can modernize such a system, somebody has to reconstruct enough of its operating environment to make comparison possible.
This work can feel slow because it does not immediately produce shiny new code. It is still migration work. Without a reproducible baseline, every later comparison becomes weaker.
Map what the software actually does
Documentation is one of the safer places to use agents aggressively because the work can be divided without giving the model authority to redesign production behavior.
Generate dependency maps, caller trees, API inventories, data-flow notes, file-format descriptions, database schemas, and module summaries. Reconcile those drafts against manuals, source comments, production behavior, and domain-expert knowledge.
Keep uncertainty visible. “This function appears to calculate X” is not the same claim as “X is the business requirement.” Old code often contains dead branches, compatibility hacks, historical bugs, and behavior that survives only because another system quietly expects it.
AI can accelerate the inventory. It cannot decide which discovered behavior is intentional.
That difference becomes more important once the coding agent starts moving faster. Popular AI’s testing of local coding agents found that agent reliability depends on the model plus the tool parser, streaming path, SDK contract, and file-edit workflow. A strong model inside a brittle execution stack can still fail at basic file operations. Legacy modernization adds another layer of uncertainty on top of that.
More on AI agent reliability:
Capture behavior before defining the new architecture
Once the old application is reproducible and mapped well enough to inspect, build characterization or parity tests around the parts you expect to change.
For numerical software, that can mean checking final outputs and selected intermediate values within agreed tolerances. A billing system might compare invoices, tax calculations, rounding behavior, database writes, and failure cases. An old Perl integration service might preserve generated files, HTTP requests, field mappings, retry behavior, and strange formatting that another system quietly depends on.
Martin Fowler’s description of self-testing code explains the basic advantage: frequent automated tests can expose bugs soon after they are introduced, when the relevant change is still easy to isolate.
AI increases the value of that safety net. A coding agent can produce changes much faster than a reviewer can manually understand them. Without automated checks, the verification backlog can grow faster than the codebase improves.
A passing test suite still has limits. It tells you that the implementation matched the behaviors you captured. It does not prove that every important behavior was captured in the first place.
Decide which legacy behavior deserves to survive
A characterization suite records reality. Reality can contain bugs.
Suppose an accounting application has rounded one edge case incorrectly for 15 years. Downstream reports may have learned to expect the incorrect value. If a rewrite silently “fixes” it, the new implementation may be mathematically cleaner and operationally incompatible.
The regression test should expose the difference first. Then the team can decide whether to preserve the old behavior temporarily, change it deliberately, update downstream consumers, or add a migration rule.
Do not let an agent quietly combine architectural cleanup with behavioral correction. Reviewers need to know whether a changed result came from an accidental regression or an approved product decision.
This is also why the old program is a useful oracle without being a definition of truth. It can tell you what the existing system did. Domain experts still have to decide what the replacement should do.
Split the migration into bounded, testable units
Mistral worked with reservoir engineers to identify self-contained subtrees in the call graph. In this project, the team empirically kept individual modules below roughly 10,000 lines of Fortran and ran each through architecture, review, implementation, testing, and human PR review.
The 10,000-line figure is a project detail, not a universal agent limit. The reusable rule is to keep each migration unit small enough to understand, test, review, and compare against the legacy implementation.
One module should have enough captured behavior that the old and new versions can be compared without requiring faith in the rest of the rewrite.
Microsoft’s modernization guidance points in the same operational direction. It recommends incremental changes under source control, continuous testing, code review, and test environments that mirror production closely.
Small units also make failures cheaper. If the new module diverges, the team has a bounded diff, a known reference implementation, and a smaller set of assumptions to inspect. A 40,000-line autonomous patch gives reviewers none of those advantages.
Let agents work inside the boundary
Once a module has documentation, captured behavior, and a test oracle, AI can do more useful work.
Have one stage propose the target architecture. Let a human with domain knowledge approve or reject it. Break the approved design into implementation tasks. Let coding agents modify the module, run tests, inspect failures, and retry. Add a separate review pass that looks for architectural quality rather than mere test success.
That separation matters because a program can pass tests and still be unpleasant to maintain. Mistral’s first autonomous attempt demonstrated the problem directly. Functional parity did not automatically remove global state or old control-flow habits.
Independent research from Los Alamos National Laboratory and collaborators used a similar multi-stage idea for a different problem. Their Fortran-to-Kokkos workflow used specialized agents to translate, validate, compile, execute, test, debug, and optimize benchmark kernels. The functionality tester compared results before further optimization proceeded.
The scope deserves careful reading. The accompanying SC25 work evaluated five benchmark kernels across AMD and NVIDIA hardware and used specialized agents for translation, compilation, execution, error handling, testing, and optimization. That is useful evidence that structured agent workflows can handle bounded scientific code tasks. It is not evidence that an autonomous agent should be handed a 300,000-line production application and trusted to come back with a safe replacement.
Merge one proven slice at a time
A passing module-level parity test is a gate, not the finish line.
Run the broader regression suite. Test integration boundaries. Check performance when the workload is sensitive to it. Review security behavior and operational assumptions. Keep the old path available long enough to compare results or roll back where the architecture allows it.
AI-generated code still needs ordinary engineering discipline. Popular AI has already covered how cheap AI-generated pull requests can move expensive verification work onto the reviewer. The same cost transfer can happen inside a company. A migration agent should arrive with reproducible test evidence and small, reviewable diffs instead of handing a senior engineer a heroic patch and a green checkmark.
The point of agent speed is to reduce implementation time without turning verification into a manual archaeology project.
More on AI tokenomics:
The harness tells you what changed, not whether everything is correct
The test-first approach has an obvious failure mode: the oracle is only as good as the behavior you captured.
If your test suite contains five happy-path examples, an agent can pass all five while breaking the sixth case nobody knew existed. A green suite can create false confidence when the test inventory is shallow.
Nondeterministic systems add more work. Timestamps, random values, floating-point differences, concurrency, external APIs, database state, and environment-specific behavior may need normalization, seeded runs, tolerances, fixtures, or controlled substitutes before automated comparisons become useful.
Mistral had a favorable workload because numerical parity provided a strong signal and reservoir engineers could identify meaningful checkpoints. A 20-year-old enterprise application with human workflows, hidden dependencies, and messy side effects may offer a much weaker answer key.
That does not make the harness idea less useful. It changes the first assignment. The agent may need to spend substantial effort helping the team discover what should be observed before it writes replacement code.
Should AI rewrite a legacy application from scratch?
The useful question comes earlier: how will you prove the replacement behaves correctly?
Developers are already wrestling with the rewrite-versus-refactor choice. In a recent r/ClaudeCode thread, participants discussing fresh AI rewrites versus modifying legacy code recommended regression tests or test oracles to lock down useful existing behavior before larger changes.
A clean rewrite becomes easier to defend when the existing system cannot be made runnable, its current behavior is largely unwanted, the domain is specified well somewhere else, or the team can define acceptance tests independently of the old implementation.
If the legacy application is ugly but still quietly runs the business every day, deleting it also deletes years of accumulated behavioral knowledge.
The code may be terrible documentation. Sometimes it is still the most complete documentation available.
The same test-first technique works beyond Fortran
Nothing about the core workflow requires Fortran.
A COBOL batch system can run against historical input files and compare records. A C or C++ service can expose outputs and state transitions. A Perl pipeline can be tested against archived jobs. A Java monolith can put characterization tests around APIs and database effects before individual domains are extracted.
The best candidates have a runnable reference implementation, representative inputs, observable results, and people who can tell an intentional behavior change from an accidental one.
The programming language is secondary. The valuable asset is a trustworthy comparison between old and new behavior.
That is also why benchmark scores alone are a weak basis for planning a migration. Legacy modernization depends on build systems, tools, permissions, test runners, repository structure, execution environments, and human review. The model is only one component in that chain.
Keep sensitive code inside an appropriate boundary
Legacy modernization projects often involve repositories containing proprietary business logic, old credentials, customer-data paths, infrastructure details, and security assumptions that were never designed for an AI coding agent.
Hosted agents can still be the right tool, but repository sensitivity should affect the deployment choice. Popular AI’s coverage of private-repository risk explains why coding agents introduce questions about model access, telemetry, enterprise controls, jurisdiction, and provider policy. Enterprise-controlled endpoints, isolated workspaces, secret removal, restricted tool permissions, and local or self-hosted models all deserve consideration before an agent receives a decades-old production repository.
For smaller or more sensitive jobs, Popular AI’s guide to local coding agents without cloud accounts explains the privacy and capability tradeoff. Local agents can keep more repository data on hardware you control, but weaker models, brittle tool use, and smaller hardware budgets can limit the work they handle reliably.
A portable agent setup can also reduce dependence on one hosted provider. Popular AI’s guide to building an independent AI development stack covers the appeal of keeping more of the workflow under your control and retaining fallback options.
The testing discipline stays the same whichever deployment model you choose. Local inference does not turn an unverified rewrite into a safe one.
More on AI agent security:
Frequently asked questions
What is a test oracle in legacy code modernization?
A test oracle is the reference used to decide whether the new implementation still produces acceptable behavior. It can include outputs from the old program, captured state, specifications, invariants, historical data, or domain-expert judgments.
Are characterization tests the same as proving the old software is correct?
No. Characterization tests record behavior you intend to monitor. If the old system contains a bug, a characterization test can preserve that behavior until the team deliberately changes the expected result.
Can AI build the regression harness too?
Yes. This may be one of the highest-value jobs for an agent early in the project. Agents can trace callers, generate instrumentation, assemble fixtures, propose edge cases, write comparison scripts, and document gaps. Humans still need to decide which behaviors are important and whether the captured result is trustworthy.
Does Mistral’s case prove autonomous agents can rewrite large production systems?
No. Mistral’s final workflow retained human architecture review and pull-request review. Its published work covers the first 40,000 lines of a larger 300,000-line simulator, while the independent Los Alamos research tested a structured workflow on benchmark kernels. Both support test-driven agent workflows. Neither makes a one-shot autonomous rewrite a safe default.
Build the answer key before you let AI rewrite the code
Mistral’s 40,000-line result is interesting because of the machinery around the agents.
The old application became observable. Its documentation was reconstructed. Domain experts identified important values. A parity harness supplied an objective failure signal. The system was split into manageable modules. Different agents received different jobs. Humans approved architecture and reviewed the resulting changes.
The model could move quickly because the project had built ways to catch it being wrong.
That is a better blueprint than pointing an agent at a COBOL, Fortran, C++, or Java repository and asking for a clean rewrite in one pass. The first milestone should be a runnable baseline and a trustworthy comparison harness. The first successful AI output may be tests rather than replacement code.
For risky AI legacy code modernization, build the answer key first. Then let the agent take the test.
Explore more from Popular AI:
Start here | Local AI | Builds & gear | Autonomy & policy | Fixes & guides | Popular AI podcast










Would you trust AI agents to modernize a production legacy codebase, or is human review still non-negotiable?