Imagine joining a software team and being asked to fix a checkout bug in a codebase containing 400 files and tens of thousands of lines of code.
You wouldn’t start by reading every file from beginning to end. First, you’d want to understand what the product does, how its code is organised, how the relevant components work, and what infrastructure and external services the application depends on.
AI coding agents face the same challenge, but without the benefit of conversations with experienced engineers or informal knowledge shared across a team. Without prepared context, an agent often has to rediscover the codebase for every task. It reads files, tries to infer how components connect, and can misunderstand the architecture before it even starts making changes.
Tools such as GitHub Copilot can help developers explore an unfamiliar repository, understand its structure and functionality, and identify relevant code before making changes
The solution is to prepare codebase context before an agent receives a task.
We built a system that analyses a software repository and produces plain-English documentation at four levels of detail. These documents give AI agents and human developers a structured way to understand the codebase, from its overall purpose to its internal components and underlying infrastructure.
A codebase understanding system analyses a software repository and converts its structure, functionality, dependencies and infrastructure into layered documentation. This gives AI coding agents and developers the context they need to understand a codebase before working on it.
Think of a software project as an office building. Each level of documentation gives you a different view of that building, helping you move from a broad understanding to the details you need to do the work.
The system organises codebase knowledge into four documentation levels: L1, L2, L3 and L0. Each level answers a different question, moving from the software’s overall purpose to its architecture, internal implementation and infrastructure.
The four levels of codebase understanding are L1 (software overview), L2 (module structure and dependencies), L3 (internal module implementation) and L0 (infrastructure, configuration and external services). Together, they provide a structured view of a software system, from its overall purpose to its underlying technical environment.
The first level answers the question a visitor asks at the front door: What does this building do, and who is it for?
L1 describes what the software is for, what it can do, how the outside world interacts with it, what technology it’s built with, how to get it running, and what changed recently. It also includes a section for open questions, where the system records what it isn’t sure about.
That uncertainty section matters. An AI agent that knows where the gaps are can investigate before making assumptions.
The second level is like the directory board in a building’s lobby: it shows which departments exist, what each one does, and how they depend on one another.
L2 divides the codebase into modules, which are coherent groups of related code, and maps the relationships between them. For example, the payment module might call the user module to check an account, while the reporting module reads data produced by the ingestion module.
One important lesson is that module size matters. If one module is a single small file and another contains half the codebase, deeper analysis becomes uneven. To avoid this, the system aims to create modules of roughly comparable size. Large folders may be divided into multiple modules, while several smaller files may be grouped together.
The third level examines each module in greater detail and produces a dedicated document explaining its internal structure.
Each L3 document describes the module’s purpose, important functions, inputs and outputs, and how its internal components interact.
It also includes a coverage ledger, which records what was examined and what was not. If a module is too large to analyse completely, the documentation identifies the areas that were skipped.
A coverage ledger records which parts of a code module were analysed and which were not. It makes documentation gaps visible, helping AI agents identify where they need further investigation instead of assuming they have a complete understanding.
The last level covers the technical foundations that are easy to overlook until something breaks.
L0 documents where application data is stored, which configurations are required, how the software is deployed, which external services it calls, and which services call it.
It is numbered L0 because it describes the underlying foundation on which the other levels depend. Although it sits underneath the other levels conceptually, the system generates it last because it needs the broader understanding of the codebase to describe these dependencies accurately.
Infrastructure context describes the environment a software application depends on, including its data storage, configuration, deployment setup and connections to external services.
The four documentation levels are not generated independently. Each level builds on the context established by the previous ones, allowing the system to develop a progressively deeper understanding of the codebase.
When generating L2, the system already has the L1 overview. When generating L3, it uses both L1 and L2. By the time it generates L0, it has all three earlier levels available.
This means L0 is numbered lowest because it describes the underlying foundation, but it is generated last because it benefits from the complete picture.
The four levels build on one another sequentially. L2 uses the context established by L1, L3 builds on L1 and L2, and L0 uses the understanding developed across all three earlier levels. This allows each stage to add detail without repeatedly starting from scratch.
This is also how an experienced engineer learns a codebase. You first understand what the product does, then how its components are organised, and finally how individual functions work within that structure.
For example, by the time the system documents a function inside the payment module, it may already know that the module handles retries when a payment provider times out. It can describe the function in that context instead of having to rediscover the module’s purpose.
When an AI agent receives a task, it can access the level of detail it needs:
The agent can therefore start with the relevant documentation rather than reconstructing the entire codebase for every task.

Consider a small, fictional link-shortening application. It converts long web addresses into short links, such as sho.rt/x7Kp2, and counts how many times each link is clicked.
The following examples show what the four documentation levels might produce for this application.
What it is: A link shortener. Users submit a long web address and receive a short link. When someone clicks that link, they are redirected to the original page, and the click is counted.
Who uses it: A marketing team that shares links through emails and social media and wants to measure engagement.
Open question: There is no indication that old links expire. Is this intentional?
L2 identifies three modules and documents their dependencies. More importantly, it distinguishes between essential connections and those that are useful but not critical.
| Module connection | What it does | Dependency importance |
| mod.web → mod.links | Every visitor request goes through the links module to find the destination URL. | Essential: If this fails, the short link cannot work. |
| mod.web → mod.analytics | Records a click after the visitor has been redirected. | Best-effort: If tracking fails, the visitor should still reach the destination. |
This distinction matters because not all dependencies have the same impact on the application. A failure in one connection can break the core product, while a failure in another may only affect analytics.

L3 examines the internal implementation of individual modules. For the mod.links module, its documentation might include:
Function: make_code()
Why it is designed this way: Codes are random rather than sequential (1, 2, 3…), making it harder for someone to guess other users’ links by simply counting.
Coverage ledger: All three files in the module were examined. The old import script in tools/ was not reviewed.
L0 documents the infrastructure and configuration required to run the application.
| Area | What the documentation identifies |
| Data storage | Link records are stored in PostgreSQL using DATABASE_URL. |
| Click counts | Stored in Redis using REDIS_URL. |
| Runtime environment | A single container listening on port 8080. |
| Required configuration | BASE_URL. Without it, generated short links point to an incorrect or unusable destination. |

An Abstract Syntax Tree (AST) scan examines the structure of source code. It can identify functions, imports, calls and relationships between code elements. However, structural information alone does not necessarily explain the purpose or importance of those relationships.
The difference becomes clearer when comparing a raw structural scan with the layered documentation produced for the same link-shortening application.
| What you need to understand | Raw AST scan | Layered documentation |
| Module relationships | Identifies connections between modules. | Explains what each connection does and why it matters. |
| Dependency importance | Shows that one component calls another. | Distinguishes essential dependencies from best-effort ones. |
| Function behaviour | Identifies functions and their code relationships. | Explains what functions do and why they are designed that way. |
| Infrastructure | May expose configuration references and technical structures. | Explains required settings, storage systems and runtime dependencies in context. |
| Analysis coverage | Shows the structures discovered by the scan. | Records what was examined and what was not. |
An AST scan shows the structural relationships in a codebase. Layered documentation adds the purpose, importance and operational context behind those relationships, helping an AI agent understand not just how the code connects, but what those connections mean.
Both views can be technically accurate, but they serve different purposes.
For example, if count_click() fails, the application should still redirect the visitor. If find_link() fails, the short link cannot work. The layered documentation makes this distinction explicit. It also explains why codes are random and which configuration setting is essential to generating usable links.
An AST scan can show the connections. The four documentation levels explain the system behind them.
An Abstract Syntax Tree (AST) is a structured representation of source code that shows how code elements relate to one another. It can identify function calls, imports and other structural relationships with precision, much like a compiler analysing a program.
So if an AST can map a codebase’s structure, why involve AI?
Because an AST shows what is connected, but it does not explain why those connections exist.
Think of an AST as an X-ray of a building. It can show every pipe and wire precisely, but it cannot explain that a particular room is the server room, that one pipe is the backup water supply, or that a department has moved while its old signs remain in place.
There are four important areas where structural analysis alone falls short.
An AST can identify that process_batch() calls retry_upload(). However, it cannot independently explain that this function exists to help the system recover when a network connection becomes unreliable.
Understanding the purpose behind a function requires interpreting its behaviour and the surrounding application context.
An AST can produce thousands of individual structural relationships. But deciding which files collectively form a meaningful component, such as an authentication system or payment module, requires understanding what those files do together.
In our testing on the same repository, automatically grouping the AST’s connections produced 87 clusters. The more meaningful module breakdown contained just eight modules.
The difference is between grouping code based on structural relationships and grouping it based on functional purpose.
Not every dependency is explicitly visible in source code. Some applications decide which component to load at runtime based on a configuration setting, lookup table or other dynamic condition.
An AST can only identify relationships represented in the code it analyses. It may miss dependencies selected dynamically.
In our testing, AI identified this type of runtime dependency even though it was not visible to the AST.
A codebase also depends on things outside its source files, including deployment settings, environment variables, configuration files and external services.
These details are often distributed across scripts, configuration files and project conventions. Identifying them is not simply a matter of mapping function calls; it requires interpreting how the application is configured and operated.
Although AST analysis has limitations, removing it would introduce another problem: AI-generated explanations are not always complete.
AI can interpret code and explain relationships in context, but it may overlook individual dependencies, particularly when they are buried inside functions in a large repository.
We tested both approaches on one real repository and compared the connections they identified.
| Measurement | Result |
| Connections identified by AST | 22 |
| Connections identified by AI | 22 |
| AI connections matching AST connections | 21 |
| Additional runtime dependency identified by AI | 1 |
| AST connection initially missed by AI | 1 |
| AST connections missed by AST analysis | 0 |
| Time taken by the AST analysis | 2.7 seconds |
The AI identified 22 connections: 21 matched the AST, while the additional connection was a genuine runtime dependency that the AST could not detect.
However, the AI also missed one of the 22 connections identified by the AST. That dependency was a function call buried inside another function.
This illustrates why neither approach should be relied on independently.
The system combines the two approaches so each compensates for the other’s limitations.
After combining both approaches, the AI’s list accounted for all 22 AST-identified connections while retaining the additional runtime dependency it had discovered.
The AST analysis itself took 2.7 seconds on that repository and required no AI calls.
AST analysis provides a verified foundation of structural code relationships, while AI adds functional grouping, explanations, purpose and dynamically discovered dependencies. Combining the two produces codebase documentation that is both structurally grounded and easier for humans and AI agents to understand.
Neither approach is sufficient on its own. AST analysis is precise about code structure but does not explain its meaning. AI can interpret that meaning but may miss individual connections. Together, they provide a more complete and readable understanding of a codebase.
Building a system that uses AI to understand large codebases revealed four important lessons. These apply beyond code analysis to almost any workflow where AI is given a complex task involving large amounts of information.
Don’t rely on AI to calculate or report facts that can be obtained directly from the source.
Information such as lines of code, commit history and the author of the latest change should be calculated using deterministic code. AI should focus on tasks that require interpretation, such as explaining functionality, identifying relationships and describing purpose.
We learned this early on when we allowed AI to generate a simple label. It confidently produced an incorrect label for six of the first 12 repositories we analysed.
The lesson: Use deterministic code for verifiable facts and AI for tasks that require judgment.
AI-generated documentation should distinguish between what was examined, what was established and what remains uncertain.
Every documentation level in our system includes an uncertainty section, while detailed module reports include a coverage ledger. These make it clear when the system has incomplete information or has not examined part of the codebase.
An honest statement such as “I didn’t check this” is more useful than a confident but unsupported assumption.
The lesson: Make uncertainty and analysis gaps visible instead of allowing AI to fill them with guesses.
The order in which AI receives information matters.
We once asked the L1 brochure to refer to modules that would only be defined later in the L2 floor map. Instead of acknowledging that those modules had not yet been identified, the AI invented plausible-sounding names.
Across 12 repositories, between 85% and 100% of those invented names did not exist in the corresponding L2 documentation.
We changed the process so each documentation level can only refer to information established in earlier levels, never information that will be generated later.
The lesson: Give AI information in a logical sequence and prevent it from depending on context that does not exist yet.
AI models can revert to unwanted patterns even when explicitly instructed not to.
For example, we instructed the model not to copy certain boilerplate content into its reports. It continued doing so. In one run, an unwanted title appeared in all 284 module reports and in every L0, L1 and L2 report.
Instructions helped reduce the problem, but they did not eliminate it. We needed an automatic cleanup step after generation to prevent the unwanted content from appearing in the final documents.
The lesson: Use instructions to guide AI behaviour, but use automated validation and cleanup to enforce requirements consistently.
Reliable AI workflows combine deterministic checks, explicit uncertainty reporting, sequential context and automated validation. Instructions alone are not enough to guarantee accurate and consistent outputs.
These lessons changed how we approached the system. Rather than expecting the model to get everything right, we designed the workflow around what AI does well, where it can fail and how those failures can be detected before the output reaches an agent or developer.
As AI agents take on more engineering work, from fixing bugs and adding features to reviewing code changes, the challenge is no longer just how capable the model is. It is also how well the agent understands the system it is working on.
Even a highly capable engineer can make mistakes when working without context. An engineer with a clear architectural map, an explanation of how each component works and an honest record of what remains unknown has a much stronger starting point.
That is what the four documentation levels are designed to provide: not just an inventory of files and functions, but a structured understanding of the codebase that can be prepared once and reused by multiple AI agents and developers.
AI coding agents need more than access to source code. They need structured context about a software system’s purpose, architecture, implementation, dependencies and known gaps to work on it reliably.
The goal is to move away from making every agent rediscover the same codebase for every task and towards giving each agent a shared foundation of reusable engineering knowledge.
By transforming codebases into structured, multi-layered knowledge representations, Synapt Context Substrate enables AI agents and engineering teams to start with a shared understanding of the system rather than repeatedly reconstructing it from source code. The result is faster onboarding, better code quality, more reliable agent execution, and greater confidence in AI-assisted development.
If you’re exploring how to improve codebase understanding for AI agents, reduce context gaps, or build a stronger foundation for AI-driven software engineering, connect with Synapt’s experts to see how structured code intelligence can accelerate your AI development initiatives.
AI agents can understand a codebase more effectively when its context is analysed and documented in layers. A four-level approach covers the software’s overall purpose, module architecture, implementation details and infrastructure dependencies. This gives agents reusable context before they begin tasks such as debugging, feature development or code review.
The four levels are L1 (software overview), L2 (module architecture), L3 (implementation details) and L0 (infrastructure and operational dependencies). Together, they provide a structured understanding of what the software does, how it is organised, how its components work and what external systems it relies on.
An Abstract Syntax Tree (AST) identifies structural relationships in source code, such as function calls and imports. However, it does not independently explain the purpose behind those relationships, the responsibilities of modules or dependencies selected dynamically at runtime. Combining AST analysis with AI helps add functional explanations, meaningful groupings and operational context.
AST analysis provides a structural foundation by identifying code relationships, while AI interprets those relationships, groups related files into meaningful modules and explains their purpose. A verification step can then compare AI-generated findings with AST results, helping identify missed connections and additional runtime dependencies.
Layered codebase documentation gives AI coding agents reusable information about software purpose, architecture, implementation, infrastructure and known gaps. Instead of repeatedly analysing the repository from scratch, agents can retrieve the level of context relevant to a task, helping them make better-informed changes and avoid unsupported assumptions.
Insights on making enterprise AI actually work - straight to your inbox.
Insights on making enterprise AI actually work - straight to your inbox.
Synapt AI connects your AI agents to live, governed enterprise context — so they reason on what's true right now, not what was true at training time.