A Call Graph Is Not a Specification, and CodeGraph Shows Exactly Why
CodeGraph launched on 18 January 2026 and became the largest project in its category within five months, sitting somewhere around 47,000 stars. MIT licensed, a local SQLite symbol and call graph served over MCP, 21 languages, 8 agent integrations, and a file watcher doing incremental sync so the graph stays current while you work.
It deserved every one of those stars. It runs entirely on your machine with no server and no cloud embedding call, the setup is close to trivial, and it makes agents meaningfully better at navigating a repository they have never seen before. If somebody asked for the fastest way to stop an agent flailing around a codebase, this would sit near the top of the list.
The reason we built something different is not that CodeGraph is bad. It is that a call graph answers one class of question completely and another class not at all, and the second class is where production breaks.
What the graph holds
A symbol and call graph is a structural record. There is a node for each function, class, method and module, and an edge wherever one calls, imports or extends another. Query it and you get exact, deterministic, fast answers about structure.
Which functions call this one. What does this module import. If I change this signature, which call sites break. Where is this type defined and who constructs it. Those are real questions with real value, and a parser answers them better than a model ever will, because a parser is reading the compiler’s own view of the program rather than inferring anything about it.
The thing worth noticing is that every one of those questions has a structural answer. Nothing in the graph is about purpose.
The questions that have no node
Try these against a call graph and watch what happens.
Where do we enforce the seven day return policy. There is no function called that, and the rule is spread across a validator, a scheduled job, and a comparison inside a service that names none of it.
Which of these three implementations is live. All three exist as nodes. One sits behind a flag that has been off in every environment since March, one is deprecated and waiting for deletion, and nothing in the repository marks which is which.
Does this pull request violate a rule the rest of the codebase already depends on. The graph knows which files are connected to each other. It holds no representation of what any of them promised.
What is the blast radius of removing this API field. The graph returns every structural reference. It cannot tell you that the mobile client decodes the payload strictly, so an unknown field fails the parse there and nowhere else in the estate.
How many engineering hours will this feature take. That requires knowing the complexity and the intent of every affected component, rather than simply counting them.
There is a general form of all of this. A call graph tells you what is connected, it does not tell you what any of it means, and review is a question about meaning.
The evidence that intent is the missing third
This is not a theoretical objection, and the data is not ours. In the MSR 2026 dataset of agentic pull requests rejected by maintainers, only about 36% reflected a clear failure in the agent’s code. Another 31% were rejected because the contribution violated a workflow constraint or a decision the project had already made, and that context is not in the repository.
A structural index cannot reach that 31%, because the information was never structural in the first place.
What a derived specification stores
ByteBell is a verification layer generated on top of a codebase of any size below 10 million files, and the index is a statement of meaning rather than a map of connections.
Cheap open source models read every file once at indexing time. An agent detects the boundaries of each language element, stores them separately, and then analyses each one in the context of its file, its module, its repository and across every repository. What comes out for a single file is what the module does, why it exists in business terms, what users lose if it fails, the capabilities it provides, its edge cases, its contracts and preconditions, and the specific places where its behaviour is genuinely undecided. Every claim carries the file and the line it came from.
On a real store adapter, the layer records not only the 3 code units and their callers but that identity is used as the default selector, and it separately flags an open question about which equality function applies when neither a per call nor a default one is supplied. A call graph holds both functions as nodes and has no field in which to say the semantics are ambiguous.
That difference is what turns retrieval into verification. Because the layer holds what a file promised, a proposed change can be compared against that promise. We trace what the change touches, generate and run tests for it, then review each modified file against its indexed base rather than against what the diff says it changed. Collateral damage is checked across other repositories that read the same helper before anyone approves.
The cost side
CodeGraph is free and local, which is a real advantage and not one we are going to talk around. Our index costs about $13 per 1,000 files, once, with only changed files re-derived on each commit.
What the paid index buys is that the reasoning never repeats. In a structural flow the agent still has to read the actual code to work out meaning, so the expensive part happens on every question. On a traced run, tracing a change across 32 impacted files in 4 repositories took 4 minutes 9 seconds and cost 30 for the same work by brute force. A full test generation and review pass came to 87,001 tokens at $0.11. Accuracy of code holds above 93% with token spend down by roughly 80%, which is how the layer manages to decrease AI cost and raise correctness together rather than trading one against the other.
Our own MCP server and ingestion engine are open source, and the free tier indexes 1,000 files with no card and nothing held back, so the comparison can be run without a purchase order.
One thing worth knowing about very fast open source projects
Roughly 91% of CodeGraph’s commits come from a single person. That is not a criticism of the work, which is excellent, and it is the normal shape of a project that grew this quickly. It is worth weighing honestly if you are putting the tool in a path your review process depends on, and the same question is worth asking of any tool including ours.
The honest limitation
Deterministic structure is the one place a parser beats us and always will. A call graph will never hallucinate an edge, and a model based index can in principle get a relationship wrong. We handle that by attaching a file and a line to every claim so any statement can be checked in about 10 seconds, and by re-deriving on each commit, though there is a window after a push where a claim can lag the branch.
We also do not cover every language. Mojo is not indexed today.
This is what ByteBell builds
Point both tools at the same repository and ask each one where a business rule is enforced, using the words your product team would use rather than a symbol name. The structural tool will return files containing those words. The gap between the two answers is the reason this layer exists.
ByteBell is the verifiable context layer for code. We run the LLM compiler pattern, a one time pass where a model reads every file and lowers it into a verifiable code IR capturing purpose, business context and cross repository relationships, on your own infrastructure through Docker, with your source never leaving your environment. Every engineer, on any copilot, queries the same representation through a single MCP url, and every agent edit is checked against it before it lands, using per file SHA-256 diffing so only what actually changed gets examined again. Across 46 Kubernetes ecosystem repositories and 150,000 files we measured roughly 10% higher accuracy at 70% lower cost, on about a fifth of the tokens.