feat: add experimental tree command with agent index - #3005
Conversation
Dynamic imports inside the test body made vitest transform the whole untransformed dependency subtree within the test, exceeding the 5000ms per-test budget when istanbul coverage is enabled. Static top-level imports move that cost to the file-load phase, which has no timeout.
Add the `treeview` language to the example code fences in tree.md (matching eject.md / translate.md house style) to satisfy markdownlint MD040. Stop tracking the internal agentic planning/spec docs under docs/superpowers/: they were accidentally committed into the published documentation and caused all vale and linkcheck failures plus most markdownlint errors. Nothing references them; they remain available locally but are no longer published.
The absolute-ref to node-id rule, the codepoint sort comparator, and the operation-method set each had duplicate copies across build-graph.ts and build-structure.ts. Move them to node-id.ts as the single source so the two graph builders cannot drift. Also fix build-graph's edge-refs sort to use the codepoint comparator (was the default .sort()), matching the determinism the module documents, and drop a redundant narrating comment in build-structure. No behavior change: 58 tree unit tests and 11 e2e snapshots pass unchanged.
…iants, duplicate e2e snapshot)
|
📦 A new experimental 🧪 version v0.0.0-snapshot.1786808983 of Redocly CLI has been published for testing. Install with NPM: npm install @redocly/cli@0.0.0-snapshot.1786808983 |
|
📦 A new experimental 🧪 version v0.0.0-snapshot.1786811652 of Redocly CLI has been published for testing. Install with NPM: npm install @redocly/cli@0.0.0-snapshot.1786811652 |
|
📦 A new experimental 🧪 version v0.0.0-snapshot.1786868116 of Redocly CLI has been published for testing. Install with NPM: npm install @redocly/cli@0.0.0-snapshot.1786868116 |
|
📦 A new experimental 🧪 version v0.0.0-snapshot.1786981559 of Redocly CLI has been published for testing. Install with NPM: npm install @redocly/cli@0.0.0-snapshot.1786981559 |
What/Why/How?
Adds the experimental
treecommand — one command that shows an API description's structure to humans and serves it as a navigable index to LLM agents.Humans get orientation and impact analysis in multi-file descriptions ("what breaks if I change this schema?"); agents get a way to work with descriptions far larger than a context window, borrowing the retrieval loop from PageIndex — build a small index, let the model reason over it, fetch only what it needs — fully deterministic here, because an API description already carries its structure and summaries (no AI calls, no keys).
The engine is a new
api-graphmodule in@redocly/openapi-core: one walk of the original resolved files (the lint pattern, no bundling) builds a dependency graph plus index metadata, and the CLI renders views over it.Selection is typed —
--tag,--path,--webhook,--operation,--component+--name,--file, plus the two standalone selectors--findand--pointer— so there is no id syntax to learn.Every result carries the defining file and
start_line/end_line, so any answer can be checked against its source, or read directly with plain file tools.--with-depsreturns a self-contained slice (64 KB cap with an explicittruncatedmarker);--used-byreturns transitively affected operations and components, each with the shortestviachain.Three output formats:
stylishfor a terminal,jsonfor tooling, andai— plain text built for agents, where a card's body is one line of minified JSON, a--with-depsclosure collapses to one-line schema signatures, and every view ends with anext:line naming the flags that continue from it, so an agent runs the whole chain from the output alone without reading any documentation.v1 scope: OpenAPI 2.0–3.2. AsyncAPI and Arazzo descriptions render their
$refdependency graph; the typed selectors are OpenAPI-only for now.Architecture note for review: the engine lives in core on purpose — the CLI is one of several planned surfaces, and an MCP server or portal-side index generation would consume the same module.
Measured
Same multi-step task (three chained requests with a trap in each), fresh isolated agent sessions, three descriptions × three models × two conditions: the agent gets the file and nothing else, or the file plus the
treerun line and one sentence aboutnext:.The number is the context each run added to its own session — a session opens with a fixed 26–43k of system prompt and task, identical in both conditions, which is subtracted out. Tool calls in parentheses.
All 18 answers were correct on both sides, including the operation-level
uploads.github.comserver override and ananyOfwithout a discriminator: an agent that never opens the file answers as well as one that reads it.The size of the win tracks how much of the description the baseline has to pull in — half of it on the 41 KB Cafe API, which it reads whole, and 1–18% on the large ones, which it can search instead.
Tool calls halve almost everywhere: 13 against 26, 10 against 17, 6 against 11.
Billed cost for the same runs moves the same way in eight of nine cells — $0.87 → $0.38 on the billing API with Sonnet 5, $0.70 → $0.59 on GitHub with Fable 5 — but it is the least reproducible number of the set, since a warm prompt cache can halve it for identical work, so the guide prints it for shape rather than precision.
Two findings shaped the command itself and are worth flagging for review:
next:lines exist so the prompt can stay one line long.stderron every call, spending agent context on every invocation. It is now suppressed when--format=ai.Method, prompts, per-model command chains and the caveats are in the benchmark guide.
Docs
Reference
treedraft (feat(cli): addtreecommand #2869)Testing
api-graphunit tests — graph building, selection lookups, views (overview, listings, cards), used-by reports withviachains, deps closure, pointer resolution, webhook classification, outside-cwd path normalization, callback exclusion, split-alias canonical ids.Screenshots (optional)
Check yourself
Security