Code graph
Four queries over the workshop's own index — precise for Go, heuristic elsewhere, with a confidence on every edge.
What it is#
Four questions the index can answer, each with an agent tool and a human command.
| Question | MCP tool | Human command | Answers with |
|---|---|---|---|
| Show me this function's body | code_snippet |
orch symbols snippet <name> |
{symbol, start_line, end_line, body, file_bytes} |
| Who calls it, and what does it call? | trace_path |
orch symbols trace <name> |
{root, nodes, edges}, a confidence per edge |
| What does this change break? | impact |
orch symbols impact [path...] |
{paths, touched, callers, edges} |
| What does this repo look like? | architecture |
orch symbols arch |
{dirs, edges} by directory |
trace_path takes an optional direction (callers, callees or both) and a depth from 1 to 5, defaulting to 2. impact with no arguments reads your own checkout's changes; give it paths[], a symbol, or a git_range to ask about something else. code_snippet returns at most max_lines lines, 120 by default.
Your own code is always readable#
The caller's project comes from its session — a dispatched worker's seat names both its project and its worktree — or, for a Chair, from the project argument or cwd. The index stores a path relative to the root that indexed it plus the project it belongs to, never an absolute path, so one index answers the Chair from the project checkout and a worker from its worktree. All four tools return local (untagged) symbols there.
"Shared symbols only" is a rule about crossing a boundary, not about reading your own checkout: only project: naming a different project is limited to orch:export symbols, and an unpublished one is refused in as many words.
Every reply has a ceiling#
A reply is tokens paid for on the turn it arrives and on every turn it stays in context, so each tool has a hard byte budget and degrades into it instead of overflowing:
| Tool | Ceiling | Gives up, in order |
|---|---|---|
trace_path |
2,000 B | edges, then all but the five best-ranked nodes, then a hint |
impact |
3,000 B | edges, then hop-2 callers, then a hint |
architecture |
4,000 B | edges, then the top-symbol list, then a hint |
code_snippet |
body + 200 B | the body itself is capped at 6 KB above max_lines |
Rows are ranked by how many references point at them and capped at limit (20 by default); a capped list carries has_more: true and a cursor to resume from. verbose: true returns the full uncapped shape. A name that misses answers {found: false, hint, did_you_mean} — never a raw error, because a raw error is what sends an agent back to grep.
Why it exists#
Reading a whole file to find one function is the most expensive habit an agent has. A snippet by line range costs a fraction of it, and a call graph answers "who else uses this?" in one round-trip instead of a dozen greps. Orchemax already parses every file it indexes, so the graph is a by-product rather than a second tool to install and keep in sync.
Precise for Go, heuristic elsewhere#
Every edge carries a confidence, and the number is the honest part:
| Confidence | How the edge was resolved |
|---|---|
1.0 |
The Go resolver matched an import, or the file itself |
0.7 |
The Go resolver matched a receiver type |
0.4 |
The generic tokenizer matched a bare Name( against the symbol table of the same language |
So Go is precise and the other twenty-eight langspec languages are heuristic — a 0.4 edge is a plausible call, not a proven one. A name that resolves to no indexed symbol is dropped rather than stored, so a traversal never walks into a dangling edge.
Go source ---> go/ast resolver ---> edges at 1.0 / 0.7
other langs -> langspec regex ---> symbols, then tokenizer edges at 0.4
|
v
symbol_refs table --> trace_path / impact / architecture
What it does not see#
The index sees symbols with a signature — functions, types, methods, classes. It is blind to constants, table names, schema flags and any name that lives inside a string. For those, grep is still the right tool. An empty result is a real answer, not a failure: it means no match, so you may create the thing locally — but do not invent a duplicate of a name you already know is shared.
How it relates to the rest#
- The index is the same one the shared code law populates:
sharedscope for tagged symbols,localfor everything else. Search answerssharedonly; the graph reads both. code_snippetandtrace_pathrecord the bytes they returned against the size of the file they stood in for. Those totals surface as agraphblock inorch usage, content-free.
Nothing to run here#
The graph is queried, not built: registering and indexing a folder fills it. orch index re-scans the whole workspace — every registered project and shared path, and orch inventory checks those folders against what the index actually holds.