Skip to content
Back to all field notes knowledge · 11 min

Code knowledge graphs: what they are and why agents need them

An agent can read any file in your repo on demand. What it can't do is see how the files relate. That map is a code knowledge graph, and it's the difference between a change that fits and one that breaks three files away.

field note 11 min

An agent opens your repo, greps for a function, reads the file it lives in, and changes it. The change is locally reasonable. It also breaks a caller two directories away that nobody mentioned, because nothing told the agent that caller existed. You find out in the afternoon, when the thing that used to work stops working.

That failure has a name once you go looking for it. The agent can read any single file on demand, but it has no map of how the files relate. It works from text search, and text search does not know that this function is called from there, that this type flows through those three modules, or that one config decides which branch runs in production. It sees the tree it is standing next to. It does not see the forest.

A code knowledge graph is that forest, drawn out so it can be read and walked. This piece is the reference for what one is, what it answers that a search can’t, and why agents in particular come apart without one. The category is young and most of what gets written about “AI understanding your codebase” is vague. This is the concrete version.

What a code knowledge graph actually is

Take your codebase and stop thinking of it as a folder of text files. Think of it as nodes and relations.

The nodes are the things that exist: files, modules, functions, classes, types, endpoints, database tables, tests, config keys, and the decisions that asked for any of them. The relations are the edges that connect those things, and they are typed, which is the whole point. This function calls that one. This module imports that package. This class implements that interface. This test covers that function. This service depends on that table. This decision supersedes an earlier one.

A folder cannot tell you any of that. A folder knows names and paths. It has no idea that chargeCard on line 40 of one file is the thing that breaks when you rename a field in a struct three directories over. The relationship is real in the running system, but it lives nowhere you can query. You reconstruct it every time by reading, jumping, grepping, and holding the pieces in your head.

A graph makes the relationship a first-class fact. “What calls this function” stops being a full-text guess and becomes one hop across an edge. “What does this endpoint eventually write to the database” becomes a path you can trace node by node. The structure that was implicit in the code, and only ever fully assembled inside an experienced engineer’s memory, becomes something a machine can hold and answer from.

That is the definition worth keeping. A code knowledge graph is your codebase represented as a system of typed relations, so that structure is queryable instead of re-derived on every read.

What it answers that a search can’t

Search is not useless. Grep and vector retrieval are excellent at one job — the split GraphRAG formalized: finding where a string, or something semantically near it, appears. When you know roughly what you are looking for and want the locations, reach for search. Most of what agents do today runs on exactly this, and it is why they feel capable right up until they aren’t.

The questions that break search are the ones about connection, not location.

search

  • finds where mentioned
  • matches strings
  • misses hidden callers
  • no boundaries

graph

  • finds how connected
  • walks typed edges
  • full blast radius
  • reads the seam
Search finds where something is mentioned; a graph finds how it connects, which is the question you need answered before an agent changes anything load-bearing.
  • Blast radius. Change this function’s signature and what breaks? Search finds the definition. It does not reliably find every caller, every test that exercises it, every place the return value gets unpacked. The graph walks the calls and covers edges and hands you the actual set.
  • Provenance. Why does this code exist? Search finds the code. It cannot tell you which decision, story, or acceptance criterion asked for it, because that link is not text near the function, it is a relation to another artifact entirely.
  • Reachability. Is this even used? Dead code reads exactly like live code to a text search. The graph knows whether anything reaches this node, or whether it is an island nobody calls.
  • The path. How does a request get from this HTTP endpoint to that database write? That is a route through many nodes. Search shows you the endpoint and, separately, the write. It does not show you the seven hops between them, or that one of those hops passes through a queue you forgot about.
  • The seam between two worlds. Which functions are the only bridge between the payments module and the accounts module? A graph reads that as a small set of edges crossing a boundary. Search has no concept of a boundary at all.

Retrieval finds where something is mentioned. A graph tells you how it connects. Those are different questions, and the second one is the one you actually need answered before you let an agent change anything load-bearing.

Why agents need this more than humans ever did

Here is the part that makes this urgent rather than academic.

Humans always had a code knowledge graph. It lived in their heads. Tenure on a team is, in large part, the slow construction of a private map: you learn that touching the auth middleware means checking four downstream services, that the billing code has a landmine in the retry logic, that a whole directory is legacy nobody dares delete. Nobody wrote it down. You earned it by breaking things and remembering.

An agent starts every session with none of that. It has no tenure. It has no memory of yesterday’s map. It has a context window and whatever it can pull into that window right now, which is a keyhole view of a house it has never lived in. The reason a competent agent still breaks a caller it never saw is not that the model is weak. It is that the map an engineer carries for free simply does not exist for the agent, so it works blind past the edge of the file in front of it.

The instinct is to fix this by throwing more at the model. Bigger context. A longer, more detailed prompt describing the architecture. A better model next quarter. None of it reconstructs the map, because the problem is not that the agent is under-informed inside a file, it is that the relations between files were never handed to it in a form it can traverse. A longer prompt is more text to search. It is not a graph. This is the reasoning behind the phrase I keep coming back to: codebase maps, not bigger prompts. The leverage is in giving the agent the structure, not in feeding it more prose and hoping it infers the structure each time. It sits right next to context engineering for coding agents: the job is not a smarter model, it is putting the right structure in front of the one you have.

Once the agent can query the graph, the failure mode at the top of this article closes. Before it renames the field, it asks the graph what depends on that field, gets the callers and the tests, and either updates them or tells you it can’t. The change fits because the agent finally has what you have when you make the same change safely: a view of everything it touches.

Code graph, product graph: two layers of the same idea

A code knowledge graph reads the code. It answers structural, engineering questions: what calls what, what breaks, what is reachable.

There is a layer above it that reads the product. That one answers a different family of questions, about shape and provenance and validation debt, and I wrote it up separately in the product knowledge graph. The short version of the difference: the code graph tells you the pull request will break three callers, and the product graph tells you which product decision those callers were serving and whether that decision was ever validated. You want both. They are the same technique, a graph of typed relations, pointed at two different questions. The code graph keeps agents from breaking the system. The product graph keeps you from building the wrong thing quickly.

If you only build one first, build the code graph, because it is the one that stops the immediate bleeding when agents write most of your code.

The graph has to stay true, or it is worse than nothing

A map that lies is more dangerous than no map, because you trust it. This is the trap every documentation effort falls into, and a code graph is not automatically immune.

The only version that survives contact with a moving codebase is one derived from the code, not maintained beside it. If the graph is generated by reading the actual source, the actual call structure, the actual tests, then when the code changes the graph changes, because they are the same fact expressed once. If the graph is a diagram someone drew in a wiki, it starts rotting the moment the next commit lands, and it rots silently. That is the entire argument for living documentation: the artifact stops going stale only when nobody has to remember to update it, because it is a projection of the system rather than a second copy of it.

So the test for whether a code knowledge graph is worth trusting is not how pretty it renders. It is whether it is downstream of the code. A graph you edit by hand is a graph that will lie to your agents on a Tuesday, confidently, about a structure that changed on Monday.

Where PaellaDoc fits

This is the layer I build in PaellaDoc, because operating agents without it is what burned me. The system reads your repo on your machine and builds the graph: the nodes, the typed relations, the links from code back up to the decisions that asked for it. Agents query the structure before they change it, instead of grepping and hoping. The graph is derived from the source, so it moves when the code moves. No cloud, no account, and your code never leaves the machine.

That is the whole bet of this cluster. When the models can write any file you ask for, the constraint is no longer generation. It is whether the thing writing the code can see how the code connects. A code knowledge graph is how you hand it that sight.

FAQ

Is a code knowledge graph just a call graph?

A call graph is part of it. A call graph captures which function calls which, and that is one of the most useful relation types. A full code knowledge graph carries more: types, data flow, tests, configs, endpoints, and the links out to product artifacts and decisions. The call graph tells you the code’s control structure. The knowledge graph adds why the code exists and what it is supposed to satisfy.

Do I need a graph if my codebase is small?

Probably not yet. A small codebase fits in a head and often in a context window, and the map is cheap to rebuild by reading. The graph earns its keep when the code outgrows what one person can hold, when several agents work in parallel across it, or when the people who carried the map in their heads leave. That is also, not coincidentally, exactly when agents start breaking things they never saw.

Can I generate a code knowledge graph automatically?

Yes, and you should, because a hand-maintained one rots. The graph should be built by reading the source, the call structure, and the tests, so it stays a projection of the real system. The parts that cannot be read off the code, chiefly the provenance link from code to the decision that asked for it, are the parts worth attaching deliberately as work completes, so the why is captured while it is still known.

↓ Download PaellaDoc · macOS

What breaks in your codebase that a search would never have warned you about? Tell me on the forum.