Documentación
Code graph
Structural code exploration with `tde graph`.
En esta 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.
tde graph stats
tde graph callers run_session_cli
tde graph impact SessionPaths 2
tde graph tests parse_task_createEvery 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
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>| Command | What it answers |
|---|---|
index, stats | Report the index: files seen, indexed now, unchanged, symbols, resolved and unresolved edges, elapsed ms. The two are the same command. |
q QUERY, search QUERY | Prefix-routed query, or substring search over symbol names when no prefix is given. |
callers NAME | Which symbols call this one, with call counts. |
callees NAME | Which 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 NAME | A budgeted, ready-to-read context bundle for the symbol. |
expand ID | Recover the lines a bundle truncated. |
bench-ab A B | Compare 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.
| Prefix | Returns |
|---|---|
defs:NAME | Definitions whose name or qualified name matches exactly. |
callers:NAME | Callers of the symbol, plus possible candidates. |
callees:NAME | Callees of the symbol. |
tests:NAME | Affected tests. |
imports:NAME | Import relationships. |
tde graph q "defs:parse_request"
tde graph q "callers:agent_request"
tde graph q "tests:SessionPaths"
tde graph search parse_taskAn 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.
tde_session::SessionPaths::new fn crates/tde-session/src/lib.rs:3730 tde-sessionSearch 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:
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:
… 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:
| Language | Extensions |
|---|---|
| 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.
tde graph bench-ab 118 119The 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.