Coding agents waste context when they repeatedly read entire files just to answer a narrow question about a change. A code graph context system gives the agent a structural map first: functions, classes, imports, calls, inheritance edges, tests, and change impact. The agent can then retrieve the small set of files and symbols that matter instead of scanning a repository from scratch.
The code-review-graph project demonstrates this pattern with Tree-sitter parsing, a persistent graph stored locally, incremental updates based on changed files, blast-radius analysis, risk-scored review context, and MCP tools that expose the graph to coding assistants. Its README reports large token reductions on multi-file repositories while preserving conservative impact recall. The exact tool is less important than the architecture: parse code into durable structure, update it incrementally, query it at review time, and expose focused results through a protocol boundary.
This topic treats code graphs as agent memory infrastructure. Unlike plain vector retrieval, the graph knows about symbols and dependencies. Unlike a one-shot code search, it persists across tasks and can be updated as the repository changes. The result is a context layer that helps agents reason about blast radius, hidden coupling, test coverage, and architectural hotspots before editing or reviewing code.
A structural graph represents code entities as nodes and relationships as edges. Nodes can be files, functions, classes, methods, imports, test cases, framework entry points, or notebooks. Edges can represent calls, imports, inheritance, ownership, test coverage, data flow, or inferred dependency. This converts a text repository into a queryable map.
Tree-sitter is well suited for this job because it produces concrete syntax trees and can update parses efficiently as source files change. A repository graph does not need to rebuild every node on every save. It can hash file contents, reparse only changed files, invalidate dependent edges, and preserve unaffected graph regions.
When a file or function changes, the graph can walk callers, imports, tests, and dependent flows to estimate what might break. For code review, high recall is usually more important than high precision: reading a few extra affected files is cheaper than missing a subtle dependency.
A code graph is not a replacement for reading source code. It is a routing layer that tells the agent which source code deserves attention, why it is connected, and which tests or flows are likely affected.
The build step walks repository files, selects a language grammar, extracts symbols, and records relationships. A practical extractor stores both exact edges and confidence-rated inferred edges so downstream agents can distinguish parse evidence from heuristics.
def index_file(path, parser, graph):
tree = parser.parse(read_bytes(path))
symbols = extract_symbols(tree, path)
imports = extract_imports(tree, path)
calls = extract_call_sites(tree, path)
for symbol in symbols:
graph.upsert_node(symbol.id, kind=symbol.kind, path=path, span=symbol.span)
for imported in imports:
graph.upsert_edge(path, imported, kind="imports", confidence="extracted")
for call in calls:
target = resolve_call(call, graph)
graph.upsert_edge(call.source_id, target, kind="calls", confidence=target.confidence)
Incremental updates compare file hashes, reparse changed files, remove stale edges for those files, and recompute dependent summaries. This keeps the graph fresh enough for interactive agent work while avoiding full-repository rebuilds after every edit.
def update_graph(repo, graph):
changed = []
for path in repo.source_files():
digest = sha256(read_bytes(path)).hexdigest()
if graph.file_hash(path) != digest:
changed.append((path, digest))
for path, digest in changed:
graph.delete_edges_touching_file(path)
index_file(path, parser_for(path), graph)
graph.set_file_hash(path, digest)
graph.refresh_dependents([path for path, _ in changed])
Through MCP or another tool interface, the agent can ask for impact radius, review context, architectural hotspots, or tests related to a changed symbol. The tool response should include file paths, symbol names, edge reasons, confidence, and a token budget so the agent can decide what to open next.
A review agent can start from a diff, query impacted callers and tests, inspect only the most relevant files, and produce findings tied to dependency evidence. This is more reliable than asking the model to infer repository structure from raw diff text alone.
For a failing test or stack trace, the graph can identify nearby call chains, entry points, and shared dependencies. The agent receives a narrowed investigation path instead of repeatedly running broad grep searches.
Graph metrics such as hub nodes, bridge edges, oversized communities, and cross-language coupling help agents plan safer refactors. A migration can be split by communities and verified by the tests connected to each changed area.
A local SQLite database is a pragmatic default for repository-scale graphs. It supports transactional updates, simple deployment, full-text search extensions, and indexed lookups without requiring a separate graph database. For larger teams, export formats such as GraphML or Cypher can feed visualization and offline analysis tools.
CREATE TABLE node (
id TEXT PRIMARY KEY,
kind TEXT NOT NULL,
path TEXT NOT NULL,
start_line INTEGER,
end_line INTEGER
);
CREATE TABLE edge (
source_id TEXT NOT NULL,
target_id TEXT NOT NULL,
kind TEXT NOT NULL,
confidence TEXT NOT NULL,
PRIMARY KEY (source_id, target_id, kind)
);
Agent-facing graph tools should explain why each result appears: “function A calls function B,” “test T imports module M,” or “file X shares a framework entry point with file Y.” Explanations let the agent prioritize evidence instead of treating graph output as an opaque ranking.
Structural edges are strongest for known relationships. Full-text search and optional embeddings help with names, comments, error strings, and concepts that static analysis cannot resolve. A hybrid interface can retrieve candidates lexically, then expand them through the graph.