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.

4artefacts per repository
30required sections across two documents
40+automated checks
0servers or build steps to view the output

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.

ArtefactWhat it gives you
Symbol indexEvery file, class and function, with callers, callees and the exact source of each, searchable and sortable. Generated without an LLM.
Architecture documentHow 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 assessmentHow 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 passCorrections 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 head of a generated architecture document for the browser-use open-source project: headline counts, then links to the companion documents.
The head of a generated architecture document for the browser-use open-source project: headline counts, then links to the companion documents.
The symbol index: thousands of symbols and their relationships for browser-use, each opening to its exact source.
The symbol index: thousands of symbols and their relationships for browser-use, each opening to its exact source.

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 business process for browser-use: the domain flow a user would recognise, which appears nowhere in the source and so is the one diagram the code cannot replace.
The business process for browser-use: the domain flow a user would recognise, which appears nowhere in the source and so is the one diagram the code cannot replace.
A layered call graph from the Flask analysis. Every edge drawn was checked against the code, and anything the analysis cannot see is named rather than drawn on trust.
A layered call graph from the Flask analysis. Every edge drawn was checked against the code, and anything the analysis cannot see is named rather than drawn on trust.
A sequence diagram for a flow that crosses process and network boundaries, with every step tied to a file and line.
A sequence diagram for a flow that crosses process and network boundaries, with every step tied to a file and line.
A state machine, drawn only because the states are real: browser-use's connection reconnect cycle, with every transition tied to the code that causes it.
A state machine, drawn only because the states are real: browser-use's connection reconnect cycle, with every transition tied to the code that causes it.
Deployment topology: what is built where, how it is distributed and what runs on each user's machine, with the build steps cited to the line.
Deployment topology: what is built where, how it is distributed and what runs on each user's machine, with the build steps cited to the line.

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.

The two documents are a pair. The architecture document states each fact and each gap; the assessment rates them. A gap that appears in one and not the other means a document was written without reading its pair, and a check catches it.
The two documents are a pair. The architecture document states each fact and each gap; the assessment rates them. A gap that appears in one and not the other means a document was written without reading its pair, and a check catches it.
SectionWhat it answers
Executive summaryAn 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 betThe one or two decisions hardest to replicate and hardest to reverse, and what they cost.
Security postureEvery finding and its real status, open ones included, assessed against the trust boundaries the architecture document drew.
Quality evidenceTest counts, coverage and the scope limits stated plainly, not buried.
Ownership and key-person riskCommits, authors, the top author's share and the bus factor for each part of the codebase, from the repository history.
Change hotspotsWhere change is frequent and expensive, and what makes each hotspot hard to change.
Dependency health and licencesOne row per runtime dependency: pinning, lockfile, licence and known vulnerabilities from an audit that was actually run.
OperationsHow a deploy happens, its prerequisites, and honestly whether it only runs from someone's workstation.
Cost driversWhat makes the bill grow and where it is called. Drivers and their scaling unit only, never a price it cannot cite.
Risk registerEvery risk rated High, Medium or Low, key-person risk and every gap from the architecture document included.
Remediation roadmapEach 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 youReal usage, actual spend, incident history, the SLA, the team: what someone still has to ask a maintainer.
Part of a generated risk register for browser-use: each risk rated on real exploitability or operational cost, with the reasoning and evidence behind it.
Part of a generated risk register for browser-use: each risk rated on real exploitability or operational cost, with the reasoning and evidence behind it.
The risk register is the credibility test. It has to be willing to say High. A temporary firewall rule left open after a penetration test, a production database change that is not in source control, a single author with no backup: none of it is flattering, and any competent reviewer would find all of it within a day. Finding it first is what makes everything else in the document believable.

How It Works

Facts are extracted deterministically, the LLM authors within a structured process, and automated checks gate every stage.
Facts are extracted deterministically, the LLM authors within a structured process, and automated checks gate every stage.
The eight phases. The deterministic ones take seconds; each guided phase runs in a fresh session, and a gate after every phase stops the run before bad output is handed on.
The eight phases. The deterministic ones take seconds; each guided phase runs in a fresh session, and a gate after every phase stops the run before bad output is handed on.
  • 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.
LanguageSource ranges
JavaScript, TypeScript, Python, PHPExact, from each language's own parser. A missing range is treated as a defect.
KotlinExact for around 96% of a real codebase; the rest are labelled approximate by design.
Anything elseA 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:

RepositoryFilesSymbolsRelationships
Flask872,0723,212
browser-use4268,49318,747
CrewAI1,49936,32282,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.