Composites & the _meta envelope
The graph tools from Stop 2 are atomic — one question each. Composites
bundle a whole investigation behind one call. And every response, atomic
or composite, carries a _meta envelope the agent reads to
decide what to do next.
Why composites exist
Picking up a bug normally costs a 5–10 call loop: search for suspects, read each one, trace callers, check what changed. Each round trip is latency the user watches as a "thinking…" spinner. A composite runs that sequence inside one tool call — against the same store, with no nested round trips — and returns the assembled result.
context_for_task — pick up an investigation
Give it a free-form task or a seed ID. It resolves the top matching
symbols, pulls each one's source and direct dependencies, traces callers
and callees, and folds in any uncommitted-change overlap — one envelope
of {seeds, neighbors, callers, callees, recent_changes}.
context_for_task task="fix the login retry bug"
plan_change — preview a blast radius
Before editing a function or file, plan_change composes
changes + inbound trace + relevant ADRs into a
blast-radius report: depth-1 (CRITICAL) and depth-2 (HIGH) callers,
cross-package boundary crossings, and the test files that exercise the
target.
plan_change target="internal/auth/login.go::auth.Login#Function"
investigate_failure — triage a stack trace
Paste a panic or exception. It parses the frame tokens, ranks suspect symbols by frame-match + recent-change + caller fan-in, and returns each with the evidence that fired — so the agent can trust a suspect or pivot.
audit_unused & onboard_module
audit_unused— dead-code candidates, each confirmed by a deeper inbound trace and classified high / medium / low confidence, so "safe to delete" is actually safe.onboard_module— point it at a directory and it returns the module's entry points, exported surface, language mix, and the CALLS edges that cross its boundary in and out.
The _meta envelope
Every tool response carries a _meta block. It is not
decoration — it is the planning-loop input the agent branches on:
tokens_used/tokens_saved— the real BPE cost of this call vs. the file-read it replaced.complexity_tier—lite/standard/heavy, a hint at how expensive the call was.empty_reason— when a result is empty, why:stale_index,no_results_in_corpus,query_too_narrow, and more.next_steps— concrete follow-up tool calls, with arguments filled in.warnings— clamped arguments, drift, anything the caller should know.
_meta.empty_reason value to the
why_empty tool — it returns the catalog entry for that reason
with concrete recovery steps. An empty result in pincher is a signpost,
not a dead end.
For the full field-by-field contract, see the reference and empty-reasons catalog.