The Problem
Whether it is a due-diligence review, a handover between teams or simply inheriting a system, the first weeks on an unfamiliar codebase go on working out what it actually does. The documentation that exists is usually aspirational, out of date, or both. LLMs can read code far faster than people, but left to their own devices they produce confident, well-formatted prose that is hard to verify and occasionally describes a function that does not exist.
This tooling pairs the two. Deterministic extraction establishes the facts, an LLM does the judgement work within a structured process, and automated checks verify what it wrote against those facts before anything moves on. The examples here come from running it against well-known open-source projects.
What It Produces
Everything is a single self-contained HTML file named after the project, with no build step, no server and no hosted viewer. You open it from disk, or share a standalone copy, and it works on a laptop or a phone. That matters when the audience is a board, an acquirer or an auditor rather than an engineer.
| Artefact | What it gives you |
|---|---|
| Symbol index | Every file, class and function, with callers, callees and the exact source of each, searchable and sortable. Generated without an LLM. |
| Architecture document | How the system is built: 18 sections covering structure, flows, security, configuration, infrastructure, data, integrations, resilience, performance, observability and dead code, with diagrams checked against the code. |
| Technical assessment | How well that design holds up: 12 sections with an overall health rating, key-person risk, change hotspots, dependency and licence health, cost drivers, a severity-rated risk register and a prioritised roadmap. |
| README truth pass | Corrections to the project's own documentation so it matches what the code actually does, done first so stale claims never reach the other documents. |


The Architecture Document
This is the largest of the set, and it describes how the system is designed, not whether the design is any good. Keeping that line clean is what stops the two documents disagreeing with each other. Its 18 sections fall into three groups:
- The structural spine (1 to 7): what the system is in plain English, the business process it serves, every entry point, module boundaries, the layered call graph, flows that cross a process or network boundary, and any genuine state machines.
- Cross-cutting concerns (8 to 16): the security model and trust boundaries, every configuration setting and secret, infrastructure and deployment topology, every data store and what personal data it holds, every external integration and what breaks when it is down, error handling, availability and recovery, performance limits, and observability.
- Closing (17 and 18): code that could be deleted without changing behaviour, each item with the reason it is redundant, and the diagram types that were deliberately not drawn.
Three rules make it something you can work from rather than something that sends you back to the source:
- Every section is required, including the empty ones. Most repositories have no high-availability story and many have no authorisation layer. The document says so in one plain line and carries the gap into the assessment as a finding. A missing section and a missing capability must never look the same to a reader.
- Inventories are counted, not sampled. If the evidence found fourteen environment variables, the configuration table has fourteen rows, each with the line that reads it and what happens when it is absent. The counts come from the extracted facts, so they are checked.
- Every function named is explained. Anywhere a function appears, a table says in plain words what it does, so a reader who has never opened the file can follow along.
Diagrams, drawn on purpose
Diagrams are chosen by rule, not by habit. A business process, a layered call graph, a deployment topology and a data model are always drawn. Sequence diagrams only appear where a flow crosses an asynchronous or process boundary, and state machines only where you can name the states. Flowcharts of ordinary control flow, per-module diagrams and class diagrams without real inheritance are never drawn, because the code already says that and never goes out of date.





The Technical Assessment
The second document rates what the first one describes. The first section is written for a reader who reads nothing else, and the order after it front-loads what a technical reviewer opens the document to find.
| Section | What it answers |
|---|---|
| Executive summary | An overall health rating (Sound, Adequate, At risk or Critical) with one sentence why, the top three risks and the top three actions, each sized for effort. |
| The architectural bet | The one or two decisions hardest to replicate and hardest to reverse, and what they cost. |
| Security posture | Every finding and its real status, open ones included, assessed against the trust boundaries the architecture document drew. |
| Quality evidence | Test counts, coverage and the scope limits stated plainly, not buried. |
| Ownership and key-person risk | Commits, authors, the top author's share and the bus factor for each part of the codebase, from the repository history. |
| Change hotspots | Where change is frequent and expensive, and what makes each hotspot hard to change. |
| Dependency health and licences | One row per runtime dependency: pinning, lockfile, licence and known vulnerabilities from an audit that was actually run. |
| Operations | How a deploy happens, its prerequisites, and honestly whether it only runs from someone's workstation. |
| Cost drivers | What makes the bill grow and where it is called. Drivers and their scaling unit only, never a price it cannot cite. |
| Risk register | Every risk rated High, Medium or Low, key-person risk and every gap from the architecture document included. |
| Remediation roadmap | Each High item and the Medium ones worth doing, sorted into Now, Next and Later, with effort and the risk it retires. |
| What the repo cannot tell you | Real usage, actual spend, incident history, the SLA, the team: what someone still has to ask a maintainer. |

How It Works
- Facts first. A knowledge graph of the repository and exact source ranges for every function are built with no LLM involved, using real language parsers. Where an exact range cannot be determined, it is labelled approximate rather than guessed.
- Evidence, not impressions. Before the LLM writes a word, the facts each section needs are gathered mechanically: entry points, configuration reads, data stores, integrations, module boundaries, ownership and hotspots from the repository history, dependencies and their licences, and candidates for dead code.
- The README is fixed before it is read. The project's own documentation is audited against the code first, so a stale claim cannot propagate into two polished documents where it is much harder to spot.
- One phase, one fresh session. A session that has just done one phase tends to repeat its remembered version of the next. Running each in isolation removes a whole class of failures that look like success.
- Checks throughout. Automated checks run after every stage: that everything named actually exists in the code, that inventories have every row, that every link works, that the documents render properly on a phone, that risks are rated and that nothing is stale. A failure stops the process.
- Cheap to maintain. Styling changes are applied to existing documents in seconds, and a refresh always rebuilds the facts first so nothing is written from stale data. The cost of each run is recorded per phase, so runs and repositories can be compared.
- Provider-neutral. The LLM step can be run by a coding agent automatically, by a different provider per run, or by a person following the prompts.
| Language | Source ranges |
|---|---|
| JavaScript, TypeScript, Python, PHP | Exact, from each language's own parser. A missing range is treated as a defect. |
| Kotlin | Exact for around 96% of a real codebase; the rest are labelled approximate by design. |
| Anything else | A full, valid index, with every symbol labelled approximate rather than guessed. |
Sharing It Safely
Sending the set outside the team is a different problem from publishing it internally. The symbol index never leaves, because it embeds the entire source code of the system being analysed. What travels is a standalone copy of each of the two documents, with every internal link removed rather than repointed, because a relative link dies the moment the page becomes a wiki page or an email attachment. The copy names its companion in plain text and says why the index is not included, so the reader is never left chasing a third document.
Where It Fits
- Technical due diligence, on either side of an acquisition or investment, where the questions are what is really there, who knows it and what it would cost to fix.
- Handover and onboarding, when a system changes hands and the people who built it are moving on.
- Pre-audit and pre-penetration-test scoping, so the trust boundaries and entry points are mapped before anyone is paid by the day to find them.
- Modernisation planning, where the hotspots, dead code and dependency health say where to start.
Real Runs
Runs against three popular open-source Python projects show how it scales:
| Repository | Files | Symbols | Relationships |
|---|---|---|---|
| Flask | 87 | 2,072 | 3,212 |
| browser-use | 426 | 8,493 | 18,747 |
| CrewAI | 1,499 | 36,322 | 82,265 |
The deterministic stages take seconds even on the largest of these, and the guided stages take well under an hour per document. I have also run it across my own products, including the other projects on this blog, where it has caught real problems such as monitoring left pointing at infrastructure that no longer existed, and service counts in a README that had drifted well away from the code.
Lessons Learnt
Most of the engineering effort went into failures that still look finished. The lesson applies to any LLM-assisted process: the dangerous failures are the plausible ones.
- Don't let a process read its own output. An early version fed its own previous documents back in as if they were source code, and the results still looked plausible.
- A missing answer is not evidence. A check that cannot see something must not report its absence as a finding.
- Silent fallbacks are the worst kind. Several failures completed "successfully" while quietly producing less than they should. Every one now has a check, and a test.
- Never guess. A wrong answer presented confidently is worse than an honest "approximate".
- Skipping a failed step is not fixing it. Restarting after a failure can step over it and come back clean, so the runner checks the phases it is about to skip before it starts.
If you have a codebase you need to understand, assess or hand over, reach out.