Menu da documentação

Documentação

Code graph

Structural code exploration with `tde graph`.

Nesta página

Overview

tde graph answers structural questions about a codebase without reading it: who calls this function, what breaks if I change it, which tests should I run. It builds a symbol-and-edge graph from the repository you are standing in and queries that graph, so answers come back in milliseconds and stay the same size whether the repo has ten files or ten thousand.

bash
tde graph stats
tde graph callers run_session_cli
tde graph impact SessionPaths 2
tde graph tests parse_task_create

Every invocation resolves the repository from your current working directory and re-indexes it incrementally before answering. Freshness is part of the contract: you never have to remember to rebuild, and you never get an answer based on the file as it was before your last edit.

Commands

text
tde graph <index|stats|q|search|callers|callees|impact|tests|bundle|expand|bench-ab> [symbol] [depth]
tde graph q "<defs:|callers:|callees:|tests:|imports:><name>"
tde graph expand <id>
tde graph bench-ab <task_id_a> <task_id_b>
CommandWhat it answers
index, statsReport the index: files seen, indexed now, unchanged, symbols, resolved and unresolved edges, elapsed ms. The two are the same command.
q QUERY, search QUERYPrefix-routed query, or substring search over symbol names when no prefix is given.
callers NAMEWhich symbols call this one, with call counts.
callees NAMEWhich symbols this one calls.
impact NAME [DEPTH]Everything reachable from this symbol, annotated by distance.
tests NAME [DEPTH]Tests affected by changing this symbol, tiered by confidence.
bundle NAMEA budgeted, ready-to-read context bundle for the symbol.
expand IDRecover the lines a bundle truncated.
bench-ab A BCompare two board task runs from the usage ledger.

The optional DEPTH is the third positional argument and defaults to 3. For tests it is raised to at least 4, because a test usually sits further from the symbol than a caller does.

Search prefixes

q routes on a prefix; search accepts the same prefixes for convenience. An unprefixed query on either falls back to a plain substring search over symbol names.

PrefixReturns
defs:NAMEDefinitions whose name or qualified name matches exactly.
callers:NAMECallers of the symbol, plus possible candidates.
callees:NAMECallees of the symbol.
tests:NAMEAffected tests.
imports:NAMEImport relationships.
bash
tde graph q "defs:parse_request"
tde graph q "callers:agent_request"
tde graph q "tests:SessionPaths"
tde graph search parse_task

An empty argument after the colon is not treated as a prefixed query, so tde graph q "callers:" falls through to substring search instead of failing in a confusing way.

Output shape

Everything is tab-separated, so it pipes into cut, awk and sort without parsing.

text
tde_session::SessionPaths::new    fn    crates/tde-session/src/lib.rs:3730    tde-session

Search and defs: lines are qualified name, kind, path:line, crate. Caller and callee lines add a call count in the second field. impact lines are prefixed with d<distance>. tests lines are prefixed with their tier.

Defensible, or it refuses

The graph does not guess. When you name a symbol it cannot resolve to exactly one definition, it says so and tells you how to disambiguate:

text
Error: parse is ambiguous (7 definitions — use a qualified name like tde_cli::parser::parse)

The same discipline shows up in caller results. Edges the extractor resolved with certainty are printed as facts; candidates it could not prove are printed on separate lines prefixed possible, so a name-based guess is never silently presented as a call-graph edge. The index report exposes the same honesty at the corpus level, counting resolved and unresolved edges separately.

Bundles and expansion

bundle renders a single, budgeted block of context for a symbol: its definition, its neighbours and the code around them, sized to fit a model's context window rather than dumping whole files.

When a section exceeds its budget, the bundle prints a marker instead of truncating silently:

text
… 34 more [expand:a1b2c3]

tde graph expand a1b2c3 prints exactly those dropped lines. Overflows are kept for seven days; after that — or for an id that never existed — expand says so and tells you to re-run the bundle for a fresh id, rather than returning an empty result you might mistake for "nothing there".

What gets indexed

The walker skips .git, target, node_modules and other build and cache directories, and indexes files by extension:

LanguageExtensions
Rust.rs
TypeScript and JavaScript.ts, .tsx, .js, .jsx
Python.py
Go.go

Anything else is skipped. Indexing is incremental — the report distinguishes files indexed on this run from files that were unchanged — so the per-command refresh is cheap after the first build. The database lives under ~/.tde/code-graph, keyed by repository root, so different checkouts never share a graph.

A/B benchmarking structural context

bench-ab is the odd one out: it reads the usage ledger at ~/.tde/usage.db rather than the graph, and needs no repository at all.

bash
tde graph bench-ab 118 119

The protocol is deliberate. Duplicate a board task, run one copy with the scheduler started under TDE_GRAPH_CONTEXT=0 — structural brief off — and the other with the variable unset or =1, then pass both board task ids. It prints per-stage input, output and cache tokens plus billable cost for each side, then the signed delta between them.

It reports only what the ledger actually records. Output length and true per-stage duration are not stored for board runs, so they are not reported; the stage-span figure is the spread between the first and last stage completion, not wall-clock cost. A task id with no ledger rows is an explicit error telling you to run it through the pipeline first.

From an agent

The same graph is exposed to agents as an MCP server, tde graph-mcp. You do not normally run it by hand — it is registered for you. See System commands for the other MCP stdio entry points.