Hi everyone,
in this article I want to tell you about a project that has kept me busy over the last few months: documenting a legacy project built in Delphi over almost 30 years, without a single line of documentation and without anyone able to describe the business logic without opening the code and rebuilding it by hand.
The context is a migration: I’m part of a new team with the goal of rewriting the current product, a Delphi client, as a web-based solution, with a .NET Core backend and an Angular frontend, which I’m responsible for. Before writing even a single line of the new software, though, we ran into a serious problem: nobody really knew what the old software did. The (little) knowledge lived in a handful of people’s heads, and worse, there was no documentation at all, aside from fragments that were almost never up to date.
Let’s walk through the path that led us to build a fairly complex Claude skill to tackle this problem, including the failed attempts along the way and the results we got.
The starting project
Let’s start by understanding the context and the application. The product we had to migrate was a Delphi application grown over almost three decades, built as a UI on top of an Oracle database. Three quarters of the business logic sits in the database, split across stored procedures, packages, and triggers. The remaining quarter lives in the client application.
Documentation? Practically nonexistent. The few documents that existed were unreliable because they were outdated and never maintained, so the only way to extract logic was to open the code and read it. On top of that, the development process itself was completely unstructured: analysis happened at the coffee machine, changes were discussed out loud or over MS Teams, and version management was manual.
In the middle of all this chaos, my role was to manage and coordinate the development of the new web application, in a context anchored to the mantra “we’ve always done it this way, better not change it.” The premise wasn’t great, but I learned a lot, and one thing in particular is what I want to tell you about in this article: rebuilding documentation starting from the code.
We live in a world where AI is a huge novelty for everyone, and projects like the one I’m about to tell you about are exactly what makes us grow.
The first attempts (and the first failures)
Building a Claude skill was never our starting point, it was where we ended up. Here’s how we got there.
Step 1: the domain experts
The first approach was the classic one: put two domain experts (the tech lead and a second experienced person) to work documenting a specific context, permissions, with Github Copilot Support. After a month of work they had produced about ten documents on Confluence, describing how users, roles, and permissions were managed in the legacy application.
The first warning sign was time: two “expert” people had spent a month analyzing a relatively simple context, with no complex business logic. How long would it take to document the entire project? The estimate was a few years just for the documentation, absolutely not sustainable.
The second problem showed up when we connected Claude to Confluence as a support tool. Confluence held a huge amount of old, outdated documents, and this confused the model. Part of the hallucinations we saw came directly from there.
Step 2: the first MCP server
At the same time as the documentation effort, the tech lead had tried writing an MCP server, driven more by enthusiasm than by careful analysis. The MCP pulled information from comments on Oracle table columns and from a helper data structure used by the legacy application. In this case the MCP server was consumed by GitHub Copilot (before it moved to usage-based pricing), and it acted as a support to help Copilot understand the nature of certain fields while analyzing the source code.
The first problem with this approach was that, once again, the data wasn’t always correct, and at times it was outright inconsistent.
The second problem was the limited scope of the data being used. Even assuming the data was correct, not everything was documented: a lot of metadata was missing, and the model got confused or tried to guess the meaning from the field name.
Third and last problem: every documentation request burned through a huge amount of tokens and produced no output document. If three people made the same request, you’d end up with three instances doing the exact same analysis, wasting time and resources.
The documentation project
At this point we changed approach completely. The goal became building a system able to read the source code and the database dump directly to build documentation, domain by domain, providing an accurate and up-to-date foundation for whoever was building the new product.
The first move was creating a new project dedicated to documentation, containing the Oracle database dump and the Delphi sources. This step was necessary because the original project was versioned with CVS, and we needed a stable, readable environment based on Git for Claude to work on.
Skills for reading the legacy code
The first step was building skills dedicated to reading the Delphi project and the patterns used inside it. We classified the recurring structures in the code: how permissions were handled, how shared functions were organized, and so on.
In parallel, we created a markdown index file explaining the physical structure of the project: which file types were stored where, the directory tree, the semantic meaning of each directory, and so on.
Since a lot of the business logic lived in the database, we also built dedicated documentation on the recurring patterns and structures in the database.
Agents that orchestrate the extraction
With the skills and the new documentation as a foundation, we built agents that orchestrated the extraction of the business logic, connecting the database and the client application and leaning on what we’d built in the previous step. Unlike the MCP server, which only had visibility into the source code, this approach built documentation by weaving together the application logic with the database logic.
Commands to analyze from multiple angles
The next step was defining our first commands, built to run analysis from different angles:
- analizza-modulo (module analysis): analyzes a single application module. In the legacy software, a module was a portion (standard or paid) that added functionality to the software.
- analizza-tabella (table analysis): analyzes an Oracle table starting from the DDL dump and produces complete documentation. This was useful because tables were an aggregate of many entities (hundreds of tables had more than 500 columns). This analysis also helped figure out how many entities lived in a table, with an eye toward splitting them apart later.
- documenta-dominio (domain analysis): runs a complete documentation pass on a functional domain (e.g., users, master data, products, orders).
- verifica-docs (docs checks): checks the completeness of a domain’s documentation against the expected format.
This way we could go from a single column in a table all the way up to an entire functional domain, picking the level of detail we needed each time. The output of each command was a set of “standard” documents, each focused on a specific aspect.
Optimizing to improve
From this point on, we focused on generating documentation for the same domain the two experts had already documented manually. Having a “human” benchmark let us spot hallucinations and gaps, and optimize the skill accordingly.
The workflow was disciplined: for every area of improvement we created a dedicated branch, did the optimization work on the skill, validated the output, and only then merged into the main branch. Every improvement was validated before landing in the stable branch.
Fun fact: the more optimized the skill became, the more aspects surfaced that the two experts hadn’t considered or mapped in their first round of documentation.
Wider and wider domains
As the skills became more reliable, we started tackling broader and broader aspects, pushing beyond simple as-is documentation, since the goal was rewriting the legacy software.
We built a new step in the skill to extract how data was organized in the legacy project’s forms, producing a document summarizing how to reorganize it in the new Angular app.
Then we added a new step dedicated to proposing REST APIs for the new backend. Here the problem was structural: the current project had no split into domains, and plenty of tables handled dozens and dozens of different domain entities as a single entity. I won’t go deep into this topic, since it’s outside the scope of this skill.
The result
After all this work, the system reached a steady state with a well-defined workflow after about a month of work, the same amount of time it had taken to map the permissions domain.
Running a role/permission domain-mapping command took Claude (Opus 4.8) almost 4 hours.
The workflow
Following this work, our way of working and moving forward with the rewrite settled into the following shape:
- Decide which area to migrate next
- Generate the documentation with Claude, in a dedicated branch
- Domain experts validate the documentation
- Merge the documentation into master
- The resulting documentation is used as a guideline for development, both frontend and backend, and stays available to everyone
What we gained is that developers are far more autonomous: they no longer have to constantly depend on the people who’ve worked on the product for years.
The benefits
To make the benefits concrete, it’s worth comparing the old and the new method:
| Aspect | Old method | New method (with Claude) |
|---|---|---|
| Documentation time | 2 domain experts, 1 month of work | around 4 hours + 1-2 days of review |
| Quality | variable, depends on the person | higher, with standard development guidelines |
| Developer autonomy | low, constant dependency on experts | high, the docs are the guideline |
Beyond speed and quality, there’s a benefit I didn’t expect at the start: the documentation became the foundation for a skill on the frontend project. Starting from the generated docs, a new skill was created to generate Angular components in the new project while keeping the same UI and the same behavior as the old application (obviously only in cases where the forms or the processes don’t need to be rethought from scratch).
Observations
Let me close with a few practical observations from along the way, useful for anyone considering a similar approach:
- Claude Opus 4.8 with a Max license was mandatory: the Pro license simply doesn’t have enough tokens for a project this big and complex (this application come with 4222 client form 🙃)
- Sonnet and Deepseek 3.6 couldn’t produce documentation on par with Opus 4.8, even with all the skills available. We haven’t tried it with Fable, so I don’t have feedback on that model. It would be interesting to try GLM 5.2, but we haven’t had the chance yet.
- The domain expert’s role as validator still remains essential. AI massively speeds up the work, but human validation is still the step that guarantees the result is reliable.
Conclusions
What I’m taking away from this experience is that documenting a legacy project with AI can be the winning move to fill a gap built up over many years of neglect. Another key takeaway is to patiently build the right tools, skills, agents, and commands, and above all to feed the model only reliable sources: the source code and the database, not secondhand, outdated, or unmaintained documentation.
The jump from a month of work down to a few hours plus review is huge, but the real value is something else: turning knowledge that was locked inside the code and a handful of people’s heads into versioned and up-to-date documentation the whole team can use. And, as often happens, solid groundwork opens doors you didn’t see coming: in our case, a skill that directly generates the new frontend’s components.
Hope you enjoyed this one, thanks for stopping by my blog!