AI agents read too much code to do small tasks. An agent asked to modify one function in a 3,000-line file loads the entire file. An agent exploring a new repo reads dozens of files before it understands the structure. Context windows fill up with code the agent never needed.
Every tool in this post attacks the same problem: index the codebase first so the agent can request only the symbols it needs.
The tools
jCodeMunch
jCodeMunch parses source files with tree-sitter, extracts every symbol (function, class, type, constant), and stores them in a JSON index. Agents request individual symbols by ID instead of reading files. Each response includes token accounting.
The numbers from a real benchmark: finding a function drops from ~40,000 tokens to ~200. Understanding a module’s API drops from ~15,000 to ~800. About 80% reduction overall, or 5x efficiency.
It’s a flat symbol index. No relationships between symbols, no call graph, no type information. You get surgical extraction of individual definitions.
SymDex
SymDex does what jCodeMunch does, plus semantic search and call graph analysis. It stores symbols in SQLite with vector embeddings, so agents can search by intent (“validate email”) rather than exact name. It also indexes HTTP routes from Flask, FastAPI, Django, and Express.
Claims 97% token reduction per lookup. Supports 14+ languages, live reindexing via file watching, and cross-repo search from a single instance.
The addition of semantic search matters. An agent that doesn’t know the function name can still find it. That cuts a round trip that would otherwise cost thousands of tokens in exploratory reads.
CodeGraphContext
CodeGraphContext goes further than symbol extraction. It indexes code into a graph database where nodes are symbols and edges are relationships (calls, imports, inheritance). Agents query for callers, callees, class hierarchies, and call chains.
It supports 14 languages, live file watching, and generates interactive knowledge graph visualisations. Available as both a CLI and an MCP server.
The graph structure means an agent can ask “what calls this function?” without reading every file. That’s a qualitative difference from flat symbol indexes.
Prowl
Prowl is a desktop app that builds an interactive knowledge graph of your codebase. It uses tree-sitter for parsing and KuzuDB for graph storage, with local embeddings for semantic search. 19 MCP-exposed query functions cover impact analysis, blast radius tracing, Cypher queries, and change detection.
Measured 90.5% token reduction for full project understanding (84,795 to 8,035 tokens) and 93.2% for multi-step research tasks.
It’s the most feature-rich option. Built-in AI chat, code editor, terminal, GitHub repo comparison. The tradeoff is complexity: it’s an Electron app, not a lightweight MCP server.
CodeBoarding
CodeBoarding takes a different angle. Instead of symbol-level indexing, it generates high-level architectural diagrams. Static analysis plus LLM agents produce Mermaid.js visualisations showing how components, layers, and modules relate.
It’s not a query tool. You don’t ask it for a specific function. You ask it to explain the architecture of PyTorch or FastAPI, and it produces a diagram. Useful for onboarding and documentation, less useful for an agent modifying code.
Memgraph GraphRAG
Memgraph’s approach uses a full graph database (Memgraph) with tree-sitter parsing to build a code graph, then lets agents query it with natural language that gets translated to Cypher. The demo showed it answering “what is the maximum function call chain in this repo?” with a precise answer of 11.
The hybrid search strategy is interesting: simple questions get grep-style search, structural questions get Cypher queries. The graph database handles the routing.
What they have in common
Every tool follows the same pattern:
- Parse source code (usually tree-sitter)
- Index symbols and/or relationships
- Serve targeted queries over MCP
- Measure token savings vs reading raw files
The differences are in what gets indexed (symbols only vs relationships vs architecture) and how queries work (exact lookup vs semantic search vs graph traversal).
Where ilo graph fits
ilo graph is built into the ilo language compiler. It doesn’t index external codebases. It analyses ilo programs specifically, using information that’s only available because the language was designed for it.
# Full program graph: all functions and types, signatures only
ilo graph program.ilo
# One function plus its direct dependencies
ilo graph program.ilo --fn build-order
# Transitive subgraph: everything build-order depends on
ilo graph program.ilo --fn build-order --subgraph
# Budget-constrained: fit within 500 tokens
ilo graph program.ilo --fn build-order --budget 500
# Reverse: who calls subtotal?
ilo graph program.ilo --fn subtotal --reverse
The output is JSON. Every function includes its signature, direct calls, reverse callers, and types used. The --budget flag does token estimation and truncates the subgraph to fit a limit, returning a list of what got cut.
This is possible because ilo’s type system and explicit imports make the call graph derivable from the AST without execution. use "auth.ilo" [vld-email vld-plan] declares exactly what’s imported. Every function signature declares its types. There’s no dynamic dispatch, no implicit imports, no globals to track.
The five principles from the ilo manifesto explain why this matters. Principle 5, “Graph-Reducible,” was designed specifically for this:
Writing code costs the same tokens regardless of program size. But reading code scales with program size. ilo makes the dependency graph explicit and queryable, so the agent loads only what it needs.
An agent modifying one function in a 30-function program loads the target function’s source, its dependencies’ signatures, and the types it references. Benchmark results show 40-70% reduction compared to loading the full file.
Different problems, different tradeoffs
These tools sit on a spectrum:
| Tool | Index type | Query model | Token savings | Scope |
|---|---|---|---|---|
| jCodeMunch | Flat symbols | Exact lookup | ~80% | Any language |
| SymDex | Symbols + embeddings | Semantic search | ~97% | Any language |
| CodeGraphContext | Symbol graph | Graph queries | Not published | Any language |
| Prowl | Full knowledge graph | Cypher + semantic | ~90-93% | Any language |
| CodeBoarding | Architecture | Diagram generation | N/A | Any language |
| Memgraph GraphRAG | Full code graph | NL to Cypher | Not published | Any language |
| ilo graph | Call + type graph | Subgraph extraction | ~40-70% | ilo only |
The external tools (everything except ilo graph) share a constraint: they work with languages that weren’t designed for graph analysis. Python has dynamic imports, monkey patching, getattr. JavaScript has require with computed paths, prototype chains, dynamic this. These tools use tree-sitter to approximate the call graph, but they can’t know everything statically. The graph has holes.
ilo graph has no holes. The call graph it extracts is complete because every dependency is declared and every type is explicit, so nothing is hidden behind dynamic dispatch or implicit imports.
The tradeoff: ilo graph only works with ilo, while the external tools work across many languages.
Which approach wins
For existing codebases in Python, TypeScript, Java, or Go, the external tools are the only option. Among them, the choice depends on what the agent needs. Flat symbol lookup (jCodeMunch, SymDex) is fast and cheap. Graph queries (CodeGraphContext, Prowl, Memgraph) answer structural questions that flat indexes can’t.
For new programs where correctness matters and the agent is generating code, ilo’s approach has an advantage the external tools can’t replicate. The graph isn’t approximate. The budget constraint ensures the agent never overloads its context. The type signatures serve as contracts that let the agent understand a dependency without reading its implementation.
The external tools retrofit graph analysis onto languages that didn’t anticipate it. ilo bakes it in, so the graph extracted at compile time is exact rather than approximate.