Back to Blog🇮🇹 Leggi in Italiano

Code Graphs: How AI Can Actually Understand Your Codebase

Why AST-based code graphs beat grep for AI agents, and how ours stays fresh on every edit through hooks while staying callable directly from agents via MCP.

LLMs read code as text. That's the problem.

Ask a coding assistant "who calls validate_token?" Most will grep. Works for literal matches, fails when calls go through decorators, dynamic dispatch, re-exports, or name collisions across modules.

The issue is straightforward. A language model sees code as tokens. It doesn't natively grasp that a function has callers, a class extends another, a module imports a symbol, or that HTTP call talks to a specific service. It can infer. Inference eats debugging time.

AST and tree-sitter, the standard substrate

An Abstract Syntax Tree is the structured view of source code: every node is a real program construct — a function definition, a method call, an import, a type annotation. Walk the tree, extract entities, link them, and you have a code graph.

Tree-sitter is the de facto standard for producing those trees. Fast, incremental, error-tolerant, 40+ languages from one toolchain. GitHub uses it for Semantic. Cursor, Zed, Claude Code, Codex, Gemini CLI all build on it. We do too — that part isn't a differentiator, it's table stakes.

What separates code-graph implementations is everything above the AST: how the graph is kept in sync with edits, how it's exposed to AI agents, and what entity types it captures.

What makes ours different

Three concrete things, none in any cloud or standalone competitor.

1. The graph updates itself as you code. A PostToolUse hook (code-graph-incremental.sh) fires on every agent write to Python, JavaScript, or TypeScript. The file queues, code-graph-updater reanalyzes incrementally, graph is current in seconds. No manual code-graph-analyze runs. No "is the graph stale?" question.

2. AI agents call the graph directly. Two MCP tools: search_code_graph(query, scope, expand_hops) for semantic search with optional expansion, and query_code_structure(type, target) for structural queries. Cody and Augment expose surfaces developers query. Ours is an interface agents query—different integration class. An agent debugging can ask for function callers, follow call edges two hops, pull cross-service interactions in one reasoning step.

3. Five entity types; one no competitor tracks. CodeModule, CodeClass, CodeFunction, CodeAPI are standard. The fifth, CodeInteraction, captures cross-service calls: protocol, endpoint, confidence, direction. Service A calling B over HTTP/gRPC becomes a queryable edge in the graph via query_code_structure("interactions", "module.py"). Cursor, Cody, Augment focus on intra-repo understanding; cross-service boundaries don't model in theirs.

Pre-built query primitives close the loop: callers, dependencies, methods, extends, interactions, path (BFS up to depth 6 between two functions), composes, composed_by, type_users. An agent calls these by name, no scripting.

Embeddings: defaults and lighter options

Default: CodeSage-Large-v2 (2048-dim, Apache 2.0, FastAPI port 11438, GPU-accelerated). We don't claim 2048-dim is universal—denser, more nuance, higher storage/query cost. For CPU-only or smaller projects, Jina v2 code-embed (768-dim) is a drop-in alternative. Both Apache 2.0, local. Pick what your hardware supports.

Joern integration (optional, recommended)

Joern builds a Code Property Graph — AST + Control Flow Graph + Program Dependence Graph fused — for Java, Python, JavaScript, Kotlin, more. It's Apache 2.0 and JVM-based (~600MB).

The installer detects Joern on PATH. If found, the analyzer pulls two extra fields per function: cfg_summary (branch / loop / depth metrics — useful for "find the most complex functions to refactor") and data_flow_vars (variables that flow through the function — useful for "what does this function actually touch"). If you don't have Joern, the installer offers to fetch it via the official script. Decline and the rest of the code graph (Tree-sitter AST + 5 entity types + CodeSage embeddings + cross-service interactions) works exactly as before.

We don't (yet) wrap CPGQL queries or run inter-procedural taint analysis. That's a deeper integration on the roadmap. For now, Joern adds metrics, not new query primitives.

Where each tool actually fits

Each tool in this space optimizes for a different shape of work.

ToolOptimization targetLocal?Auto-fresh on edit?AI-agent-callable?
VibeCoded OrchestratorHook-driven freshness + cross-service graph + MCPYesYes (hook)Yes (MCP)
Augment Code100k+ file monorepo retrievalNo (cloud)Yes (cloud-side)Via UI
Sourcegraph CodyRepo-wide semantic searchNo (cloud)Yes (cloud-side)Via UI
GitHub Copilot workspaceWorkspace indexingNoPartialVia UI
JoernAST + CFG + PDG (CPG)YesNo (manual)Optional metrics integration
SemgrepRule-based pattern matchingYesOn scanNo
TabNineLocal autocomplete modelYesn/aPartial

What we combine: local graph, fresh without manual runs, queryable by AI agents via stable MCP, cross-service edges as first-class data. Four properties, one stack.

Get it

The full code graph stack ships with VibeCoded Orchestrator — free, AGPL-3.0, runs on your machine. Same data, same hooks, same MCP tools whether you're on the free base or on Pro.

Check out the Orchestrator — full code graph included, no tier gating.

Sources