WritingMistral AIMistral AIpublished Sep 9, 2026seen 3h

Modernizing complex legacy code with AI agents.

Open original ↗

Captured source

source ↗
published Sep 9, 2026seen 3hcaptured 3hhttp 200method plain

Modernizing complex legacy code with AI agents | Mistral Solutions Modernizing complex legacy code with AI agents. September 9, 2026 By Mistral

Back to Blog

7 min read

Share this post

Copy url to clipboard Copied

Thinking Summary

Mistral helped a European energy operator migrate 40,000 lines of Fortran 77 to C++. Learn how it was done, and the lessons to carry forward.

Legacy scientific codebases accumulate over decades, and when original authors leave, the knowledge embedded in the code becomes hard to recover. Moreover, using languages with no active developer ecosystem means missing out on the opportunity to build on top of others’ work. Mistral helped a European energy operator migrate 40,000 lines of Fortran 77 to C++, a physics-intensive reservoir simulator with no test suite and no centralized documentation. Moving beyond code translation in legacy code modernization. Translating syntax from one language to another is a largely solved task. Asking any recent model to translate a snippet from a non-completely-obscure language to another, will likely converge to an acceptable outcome in few iterations. However, migrating a full system from a procedural language to object-oriented C++ creates the need for architectural refactors that make the task non-trivial. Fortran 77 was standardized in 1977, as the name may suggest, and code written in it reflects those constraints directly: no modules, no namespaces, no structured types. State lives in COMMON blocks—global memory shared across the entire program. Variables are implicitly typed by their first letter, so a misspelled name silently creates a new variable instead of raising a compiler error. For a simple but illustrative example, take the following implementation of a first-degree Taylor expansion. Inputs and outputs are globals in a COMMON block, and IC is an integer only because its name starts with a letter between I and N. Variable names are quite cryptic, as their length is capped to 6 characters. SUBROUTINE GASDEN

INCLUDE 'common.h'

DO 10 IC = 1 , NCELL

10 RHOG(IC) = ROG(IV) + DROG(IV)*(P(IC)-PTAB(IV))

END

In C++, one will be able to leverage explicit types, write object-oriented code, and return a value returned instead of a global write: double gasDensity (const GasProperties & gas, double pressure) {

size_t i = lookup (gas. pressure , pressure);

return gas. density [i] + gas. slope [i] * (pressure - gas. pressure [i]);

}

The scattered COMMON arrays become a single GasProperties parameter and the grid loop moved out to the caller, so there's no line-for-line correspondence to check, which is what makes verifying the migration hard. These structural differences, plus the requirement to integrate modern scientific computing frameworks such as PetSc, raised a few important questions even before starting the migration: How to prove the migrated codebase matches the legacy one numerically

How to split the migration into manageable chunks

How to best use autonomous agents to speed up the process

Building a parity harness before migrating legacy code. Before letting agents loose, we needed a way to prove the two codebases agreed. Here, "agreement" meant numerical equality of the outputs—both the final results and a set of critical intermediate points flagged by the client's reservoir engineers. We added: subroutines allowing to export the state of the Fortran codebase

a test framework to load the checkpoints into C++

Skill.md files to steer agents into using them correctly

In the migration workflows, agents successfully instrumented the Fortran codebase to dump state snapshots and used the C++ test framework to verify correctness of migrated modules. Building this part of the harness first was a net-positive investment for the project: it made long agent runs safer, and numerical parity is an easy-to-verify and compelling argument to show a piece of code has been successfully migrated. We believe this should be one of the first steps for any code modernization engagement. The example below illustrates this. We first inserted a line into the Fortran code to dump the value of the RHOG variable (42.71834 in this run), and then used that same value as the reference checkpoint when testing the migrated C++ module. Using AI agents to understand and document legacy codebases. The project’s documentation was scattered across old PDFs and comments buried in the Fortran itself, and one of the largest side-wins of the whole effort was reconciling this documentation and moving it next to the code. Luckily, procedural code like Fortran has a convenient property: the whole program can be drawn as a single caller-callee tree. We generated that tree by parsing the codebase with a custom parser, then used Vibe CLI to spawn over a hundred agents to document it. Each agent could pull in the relevant PDFs through document libraries and Mistral OCR . Starting from the leaves of the tree and working upward, each node spawned a subagent to document it and open a PR to the original repository. A reviewer agent running in a loop on a cron schedule looked for newly opened PRs, reviewing them and scheduling fix tasks when necessary. Utilizing the AI agents for code modernization. On our first attempt, we gave agents full autonomy: one agent per Fortran subroutine, each translating its function to C++ independently over the course of a week. The result was functional, but it couldn't be called code modernization. COMMON blocks became global structs, one-to-one. GOTO-driven control flow stayed intact instead of being restructured into loops or early returns. It looked like Fortran retyped in C++ syntax rather than modernized code. In the second attempt, we addressed this by giving agents structure instead of just autonomy: a planner, a coder, a tester and a code quality reviewer working together on each module. Code quality improved substantially over the first attempt. But the source code's complexity caught up with the agents eventually. They would hit a bug, attempt a few fixes, and stall, with no one available to intervene. We landed on a middle ground: a human operating a workflow of coder, tester, and reviewer agents, migrating the codebase module by module. This preserved the code quality of the second attempt while adding a human checkpoint to unblock agents when they got stuck. The next section covers this workflow in detail. Running structured AI agent workflows for complex code migration. With the codebase...

Excerpt shown — open the source for the full document.

Notability

notability 6.0/10

Substantive technical post from Mistral on AI code migration.