← Back to Blog

Stop Grepping, Ask the Compiler

April 20263 min read

When you change a function, the compiler already knows everything about it. Where it lives, what calls it, what types flow through it, what breaks if you touch its signature. It built this map the last time it ran. It's sitting right there.

But agents don't use it. Instead they grep.

They grep for the function name, read some files, grep again with a different pattern, read more files, and repeat. Each round costs tokens and latency. k rounds of search to answer a question the compiler could answer in one.

Click any dot to search for it.

With n files in a codebase, grepping is O(n) per query. You scan everything for string matches when what you want is a graph traversal. Like reading every page in a library to find a phone number when there's a phone book on the front desk.

Why do agents grep? Because that's the tool they were given. Most agent frameworks hand you a file system and a text search. That's it.

What agents actually need is structural. Not which files contain the string validateToken, but what calls validateToken and what breaks if it changes. Graph questions, not text questions.

Compilers know the answers. But compilers are hard to use for this. Full toolchain per language, internals aren't exposed in useful ways, and they choke on broken code. LSIF and SCIP tried to standardize this. Cross-language support never materialized.

Tree-sitter turns out to be a surprisingly good middle path. It parses many languages with the same interface, works on broken code, and gives you the structural skeleton: functions, classes, imports, call relationships. Enough to build a dependency graph.

A dependency graph can answer the questions agents actually ask. What depends on this function? What's the blast radius of this change? Which tests cover this code? All graph traversals. None require grepping.

Grepping returns text matches. A dependency graph returns relationships. Grep for validateToken and you get every file that mentions it: tests, comments, string literals, unrelated functions with similar names. The graph gives you exactly the callers. No noise.

Agents pay for noise with tokens. For a human, scanning grep results and skipping junk takes seconds. For an agent, every line of junk is real cost against a hard context limit.

The natural unit here is the function. Not the file, that's too coarse. Not the line, that's too fine. Functions, classes, methods. That's how people think about code and how agents should too.

If an agent has the dependency graph, it can answer what breaks if I change this in one call. Deterministic. No hallucination. Computed once, cached, free after that.

Click any function to see its blast radius.

The compiler already did the hard work. It parsed every file, resolved every symbol, traced every dependency. All that information exists. The question is why we make agents rediscover it from scratch, one grep at a time, burning through tokens to reconstruct a map that was already built.