← all posts
// workflow · code-graph

I stopped grepping my own codebase

Watch an agent review a pull request the naive way and you can see the money burn in real time. It greps for a symbol, gets forty hits, reads nine files end to end, and by the time it forms an opinion it has pulled sixty-something thousand tokens of context to evaluate a 200-line diff. Most of those tokens were neighborhoods, not evidence.

The fix that stuck for me was structural: stop giving the agent a filesystem and give it a graph. A local MCP server parses the repo with tree-sitter into functions, classes, imports, calls, and test relationships, keeps it updated by hooks on file changes, and lets the agent query structure instead of rediscovering it every session. I'd been circling the idea since writing about knowledge graphs versus RAG; it took watching my own review bills to actually deploy it.

Review as four queries

My review flow now opens the same way every time. Change detection first: the graph diffs its model of the branch and returns the touched nodes, risk-scored by how central they are. Then impact radius: who calls what I changed, transitively, which is the question I actually care about and the one grep answers worst. Then targeted context. Source snippets for exactly the affected nodes, not the files they happen to live in. Last, test mapping: which tests exercise the changed paths, and more importantly, which changed paths no test exercises.

That last query has caught real problems twice. Once a utility function whose behavior change rippled into three execution flows, only one of which I'd thought about. The impact query listed all three before I'd read a single file. I'd have found it eventually — probably in staging, possibly in production.

Grep answers "where does this string appear." Review needs "what depends on this decision." Those are different questions, and the second one was never going to come out of a text search.

The token math is blunt. A typical mid-size review in my logs used to run 50–70k tokens of pulled context. The graph-first version of the same review runs 5–8k, because snippets arrive pre-scoped to the blast radius. Cheaper, yes. But also better: the agent's context holds only load-bearing code, and models reason noticeably harder about ten relevant functions than about nine mostly-irrelevant files. Same lesson as the context budget post, arriving from the other direction.

The two ways the graph lies

First lie: staleness. After a violent rebase in early June, the hooks missed a window and the graph confidently described functions that no longer existed. The agent built a perfectly reasoned review of a phantom codebase. It only takes one of those to make you paranoid; now a graph rebuild is part of my post-rebase muscle memory, thirty seconds that buy back trust.

Second lie: homonyms. Semantic search for "auth" in a codebase with an auth service, an author module, and an OAuth shim returns a cheerful mix of all three. The graph is structurally precise but semantically literal. I've learned to query by relationship (callers of this function, imports of this module) and keep name-based search for orientation, not evidence.

Neither failure is disqualifying. Both are the kind of thing you want to know before you route real reviews through it.

Where this leaves grep

Still installed, still used: for the unstructured edges, comments, configs, that one YAML file. But it's demoted from primary instrument to fallback, and the demotion took about a week to feel normal.

The graph earned the top spot for a simple reason: review is a structural activity, and for the first time the agent's context is structured like the activity. It's also the newest layer in my full token stack, and the one that surprised me most: I installed it to save tokens and kept it because the reviews got sharper. That's the trade you hope for and rarely get.

#code-graph#code-review#context