Koragraph

GraphRAG for code

GraphRAG for code is retrieval that walks a graph of the codebase to assemble context, following real edges out from a node instead of returning the chunks that scored highest for similarity.

GraphRAG for code is retrieval that walks a graph of the codebase to assemble context, following the real edges out from a starting point instead of returning the chunks of text that happened to score highest for similarity, so the material the model reads is the material the answer actually depends on.

Starting from what plain retrieval does

Before a language model answers a question about your code, something has to decide which parts of the code to put in front of it. The model cannot read a whole repository at once, so a small, well-chosen slice has to be selected. That selection step is retrieval, and it is where the quality of the answer is largely won or lost. This is the same pattern as retrieval-augmented generation in general: fetch relevant material, place it in the context window, then let the model generate.

The usual way to do that fetch is vector search. Every chunk of code is turned into a list of numbers standing for its meaning, the question is turned into the same kind of numbers, and the chunks nearest the question are returned. For prose this works well, because passages that answer a question tend to use words like the question. The trouble, examined in the ideas on vector search and similarity, is that code does not obey that rule. The function that will break when you change something often shares no words with it, and the functions that share words often have nothing to do with it. Similarity and dependency come apart.

So plain retrieval, applied to code, tends to return lookalikes. Ask about a function and you get other functions that read like it, while the ones that truly call it, the ones the answer depends on, are missing because they do not resemble it. The model then reasons over a slice of code that looks relevant and is not. GraphRAG for code exists to fix exactly this: to change what gets fetched, from what resembles the question to what is actually connected to it.

The codebase as a graph

To retrieve by connection, you first need the connections written down as facts you can follow. That structure is a graph: a set of nodes joined by edges. In a code knowledge graph, the nodes are the real things in a codebase, a function, a file, a class, a service, and the edges are the real relationships between them, each one a link you can travel along.

The relationships are not guessed from resemblance. They are the actual wiring of the program, recovered from the code itself.

  • Calls: this function calls that function.
  • Imports: this file pulls in that module.
  • Inheritance: this class is built on that one.
  • Cross-service links: this service reaches that one, over the network or through a shared channel, so the connection crosses the boundary between separate programs.

Each edge has a direction, which turns out to be the whole point. From a function you can look along its calls edges to see what it depends on, the things it uses. You can also look backward along the same kind of edge to see who calls it, the things that depend on it. That second direction, the callers, is the one plain similarity search can almost never recover, because callers so rarely share words with what they call. In a graph it is a simple matter of following the edges the other way. The full account of this structure, how the nodes and edges are built and what they mean, is the subject of the code knowledge graph. Here it is the substrate: the thing retrieval walks.

Walking edges instead of measuring distance

With the graph in hand, retrieval changes shape completely. Instead of embedding the question and measuring nearness on a map of meanings, you find the node the question is about and walk outward along its edges, collecting the nodes you reach. The context you hand to the model is that walked neighborhood: the real dependencies and dependents of the thing in question, not a set of lookalikes.

  1. Identify the starting node. The question is about a particular function, file, or service, so begin there.
  2. Decide which edges to follow. To understand what a function does, follow its calls outward to what it uses. To judge the risk of changing it, follow calls backward to everything that uses it.
  3. Walk those edges, one hop at a time, gathering the nodes you land on. Stop after a sensible number of hops so the neighborhood stays focused rather than swallowing the whole codebase.
  4. Assemble the gathered nodes into the context and hand it to the model, which now reads the pieces that are genuinely connected to the starting point.

The difference from plain retrieval is not a tuning detail. It is a difference in what the returned context means. Similarity search returns the code most like the question. A graph walk returns the code the question is actually about: the callers that will break, the callees it relies on, the imports it needs, the service on the other end of a request. One answers what looks similar. The other answers what is connected. For code, connected is almost always the thing you needed.

Plain retrieval returns what resembles the question. Graph retrieval returns what the answer depends on. For code, those are rarely the same set.

A worked example

Take the question a developer asks constantly before making a change: if I modify this function, what else might break? Say the function is normalize, a small helper used all over the codebase, called by parseInvoice, by importUsers, and by a request handler in a completely different service.

Run this through vector search. It embeds normalize and returns code that looks like it: other small utilities with tidy bodies and short names, a sanitizehere, a trim there, none of which call normalize. The three functions that will actually break do not resemble normalize in words, so they may not appear at all. The developer reads a plausible list, changes normalize, and is surprised in production by the caller nobody surfaced.

Now run it through a graph walk. Find the normalize node. Follow its called-by edges backward. You arrive directly at parseInvoice, importUsers, and the request handler in the other service, because each of those has a real edge pointing at normalize. Follow one more hop and you find what calls them in turn, the wider ring of code that could feel the change indirectly. The returned context is the true blast radius: the set of things that depend on normalize, defined by actual links, with no lookalikes and no silent omissions. The developer sees the risk before making the change rather than after.

Notice that the cross-service caller is the sharpest win. It lives in a separate program, in a different file, probably written by a different team, sharing no words with normalize. Word similarity had no chance of finding it. A directed edge finds it in one hop, because the connection was recorded as a fact rather than left to be inferred from vocabulary.

Why the context is the right context

It is worth being precise about why this produces better answers, because the reason is not that the model got smarter. The model is the same. What changed is the material it reads. A language model reasons over what is in its context window and nothing else. If the context holds lookalikes, the model reasons about lookalikes and gives you a confident answer about the wrong code. If the context holds the true dependents and dependencies, the model reasons about those and its answer rests on the actual structure of the program.

This is grounding, the same idea that runs through all retrieval-augmented generation, but grounded in relationships rather than resemblance. The answer to what breaks if I change this is, by its nature, a fact about edges: it is the set of nodes reachable backward along the calls edges. Retrieval that walks those edges returns that set directly. Retrieval that measures similarity can only approximate it by accident, and for code the accident rarely happens. Matching the retrieval method to the shape of the question is the whole gain.

The graph has to be real

A graph walk is only as good as the graph. If an edge is missing, the walk misses a dependent and the answer is quietly incomplete, which is the very failure GraphRAG was meant to avoid. So the substrate has to be built carefully from the code itself, and building it accurately is real work: reading each file against the grammar of its language to recover the true calls, imports, and inheritance, and resolving the harder links that cross the boundary between separate programs.

Koragraph is a system that builds exactly this substrate and serves it to AI coding agents. It is a local server that gives coding agents a persistent, offline, multi-repo code knowledge graph, and it runs entirely on the developer’s machine with no cloud dependency, so no source code leaves the machine. It reads repositories with a parsing library called tree-sitter across twelve languages, including C, C++, C#, Go, Java, JavaScript, PHP, Python, Ruby, Rust, Swift, and TypeScript. From those files it resolves the edges a graph walk needs: calls, imports, inheritance, and cross-service links such as HTTP and gRPC connections, package imports, message topics, Docker Compose relationships, and framework routes. It also mines the project’s git history for how files have changed together over time.

Because the graph is meant to be walked repeatedly, the facts are stored so they persist. They live in a local database on the developer’s machine, at a fixed location under the home folder, and they survive across sessions and follow files when they are renamed, so the graph does not have to be rebuilt from scratch each time. An agent reaches into this graph through a small set of tools. To take one by name, a tool called blast_radiusanswers the very question from the worked example above, what could be affected by a change, by walking the edges rather than guessing from resemblance.

The tools are exposed through the Model Context Protocol, an open standard that lets an AI model reach external tools and data through one common interface. That is the plumbing by which a coding agent can ask the graph a question in the middle of its work. The graph is the substrate; the protocol is how the agent gets to it.

Where it fits, and where similarity still helps

Graph retrieval is not a replacement for every other kind of search. There are honest questions where you do not have a starting node, only a fuzzy description of what you are looking for: where is the code that handles retries, roughly. For that, matching by meaning is genuinely useful, and it can be the way you find the node you then start walking from. The two methods are complementary. Similarity is good at find me something like this description. A graph walk is good at now show me everything connected to this exact thing.

The point of GraphRAG for code is to stop using similarity for the job it is bad at. When the question is about the structure of a program, what depends on what, the answer is defined by edges, and it should be retrieved by following edges. That reframes retrieval as a walk over a real map of the code rather than a guess based on word overlap. The map itself, how a codebase is turned into nodes and edges in the first place, is the subject of the code knowledge graph, and the broader comparison of when to reach for a graph, a plain text search, or embeddings is the subject of graph versus grep versus embeddings.

Connected concepts

Retrieval-augmented generationRetrieval-augmented generation is the pattern of looking up relevant information and putting it in the context window before the model answers, so the answer rests on fetched facts.Vector search and similarityVector search finds text by nearness in embedding space rather than by matching words, which is powerful for prose and quietly wrong for code, where the caller and the callee rarely share vocabulary.The code knowledge graphA code knowledge graph is a structured map of a codebase where every declaration is a node and every real relationship, calls, imports, inheritance, cross-service links, is an edge.Graph vs grep vs embeddingsText search finds strings that look alike and vector search finds text that means something similar, but only a resolved graph can answer what is actually connected to what, which is the question code work turns on.The context layerA context layer sits between your codebase and your agent and decides what the agent sees for a given question, which is the job Koragraph exists to do and the point every other concept here builds toward.

Where this sits

Back to the full graphThe short glossary