Skip to main content
Kodelyth ECC
performance

Ask the Graph, Not grep: Structural Code Queries Without the Token Bill

Who calls this function? What breaks if I change it? grep answers by reading files into context — hundreds of thousands of tokens. An AST knowledge graph answers in one MCP call. ECC integrates DeusData's codebase-memory-mcp across 158 languages; here is when to use it instead of grep.

By Kodelyth · · 7 min read

Two ways to answer who calls processPayment: grep reading many files for roughly 412,000 tokens on the left, versus one MCP graph query for roughly 3,400 tokens on the right — 99 percent fewer.

"Who calls processPayment?" is a structural question. grep answers it lexically — it finds the string processPayment wherever it appears, drags the surrounding files into the model's context so it can tell a call from a definition from a comment, and bills you for every token of all of them. On a real repository that is hundreds of thousands of tokens to answer one question whose answer is a short list of names.

An AST knowledge graph answers the same question directly: it already knows which nodes have a CALLS edge into processPayment, and returns them as structured data. ECC integrates one to do exactly this.

What it is, and whose it is

ECC wires in DeusData/codebase-memory-mcp: a single static binary that indexes a codebase into a tree-sitter AST graph across 158 languages, with Hybrid LSP semantic type resolution for the major ones (Python, TypeScript/JavaScript/JSX/TSX, Go, Rust, Java, Kotlin, C, C++, C#, PHP). Their binary, their curl script, their MIT license. ECC installs, wires, and surfaces it — no fork, no code copy, no npm dependency.

(If you've seen graphify in an ECC-adjacent repo, that's a different, standalone graph CLI. The tool ECC integrates for in-session structural queries is codebase-memory-mcp, exposed through MCP tools your AI calls directly.)

The token math

The project's own comparison puts a structural query like "who calls X" at roughly 3,400 tokens through the graph versus roughly 412,000 tokens via file-by-file grep — about a 99% reduction. That figure is theirs, and it's a property of the approach: the graph returns the answer, while grep returns the material from which the answer must be re-derived, every time, into a context you pay for.

The saving isn't only money. The grep approach also burns context-window space you then don't have for the actual task, and it degrades as the repo grows. The graph query is flat — a Cypher query over the index is sub-millisecond regardless of repo size.

When to use the graph, and when grep is still right

The discriminator is simple: is the question about edges between symbols, or about a string?

Use the graphUse grep
Who calls AuthMiddleware?Find every TODO: comment
What's the impact of changing this type?Find a literal config key
Show the architecture / entry pointsFind a log message's exact text
Find dead code (functions with zero callers)Find a typo'd variable name
Which HTTP routes touch the users table?One-off string occurrence count

grep is excellent at lexical questions and you should keep using it for them. The moment the question is "who / what / how do these connect," grep has to reconstruct structure the graph already holds.

The three queries that cover most of it

Your AI translates natural language into these MCP calls, but it helps to know what they are. All run locally, at zero LLM cost, and return structured JSON:

  • search_graph — find nodes by name or pattern. "Every handler":
    kodelythecc codebase query search_graph '{"name_pattern": ".*Handler.*"}'
  • trace_path — follow CALLS edges in a direction. Outbound from an entry point is "what does this reach"; inbound to a function is "who calls it" and, by extension, the blast radius of changing it:
    kodelythecc codebase query trace_path '{"function_name": "main", "direction": "outbound"}'
  • query_graph — a Cypher query for everything the first two don't cover: arbitrary patterns over CALLS, IMPORTS, IMPLEMENTS, INHERITS, HTTP_CALLS, and the rest of the edge types.

So "find dead code" is a query_graph for functions with zero inbound CALLS edges; "what breaks if I change AuthMiddleware" is trace_path inbound. You rarely write these by hand — you ask the AI in plain words and it dispatches the right one — but knowing the shape tells you why the answer was cheap.

Install and first index

npm i -g kodelyth-ecc
kodelythecc --target claude-code --codebase-graph

Then open a project and say "Index this project" — the AI calls index_repository and builds the graph. It's fast: a Django-scale repo indexes in about 6 seconds; the Linux kernel (28M LOC, 75K files) in about 3 minutes, all in memory with the working set released afterward. Verify the binary and what's indexed:

kodelythecc codebase status
codebase-memory-mcp: codebase-memory-mcp 0.8.1
  indexed projects: 18
  cache dir:        /Users/you/.cache/codebase-memory-mcp
  next: open a project in your AI tool and say "Index this project"

Honest limits

It's an index, which means it can go stale — after a large change, run detect_changes or re-index so the graph matches the tree, or trace_path will answer confidently about code that moved. Hybrid LSP semantic types (parameter binding, return-type inference, generic substitution) cover the major languages listed above, not all 158 — the rest get the AST structure without the deep type resolution. And it's a separate binary you install; it persists to a local cache and your code never leaves the machine, but it is one more thing on your PATH to keep current.

None of that changes the core trade: for structural questions, one graph query beats reading a repository into the context window, by about two orders of magnitude.


codebase-memory-mcp is MIT by DeusData, with a research paper behind it. ECC's wrapper — install, auto-register, and the codebase query passthrough — is thin Node in scripts/codebase. Full reference in Codebase Graph.

npm i -g kodelyth-ecc && kodelythecc --target claude-code --codebase-graph