Skip to content

docs

mytool docs <list | show <PATH> | browse | serve | ask <QUESTION...>> [OPTIONS]

Feature: Docs, registered by the rtb-docs crate. Passthrough subtree with no default subcommand.

docs rejects --output. Its inner parser does not strip the global flag, so mytool docs list --output json fails with unexpected argument '--output' found.

Where the pages come from

Every subcommand loads from the tool's embedded rtb_assets::Assets overlay, under a root directory that defaults to docs. --root changes it on list, show, browse and serve; ask has no --root flag at all, so mytool docs ask --root mydocs "question" fails with unexpected argument '--root' found.

Loading walks the root for *.md files (case-insensitive on the extension) and looks for <root>/_index.yaml:

  • _index.yaml present — it defines the navigation, and only pages it lists are navigable, searchable or servable by title.
  • Absent — an index is synthesised: each page's first # Heading becomes its title (falling back to the filename with - and _ turned into spaces), and pages are grouped into sections by their top-level directory. Pages directly under the root land in a section called Overview.
  • Neither pages nor _index.yaml — the command fails with docs root not found in assets: <root>.

A page listed in _index.yaml whose path contains .. or is absolute is rejected at load time with an index-malformed error.

Pages not listed in _index.yaml are invisible

Once you supply an _index.yaml, it is the whole navigation. A markdown file that exists in the tree but is not listed is still loaded into memory — docs show can render it and the HTTP server will serve it by path — but it does not appear in docs list, in the TUI index, or in search results. Search is built from index entries, not from the file set.

docs list

Prints the index title, then each section and its pages.

$ mytool docs list
My Tool Documentation

# Getting started
  intro.md — Introduction
  install.md — Install
Flag Default Meaning
--root <ROOT> docs Doc-tree root inside the asset overlay

docs show <PATH>

Renders one page to stdout. PATH is relative to the root and includes the extension — intro.md, guide/setup.md.

Flag Default Values
--format <FORMAT> plain plain, html
--root <ROOT> docs

plain strips markdown to text. html emits a complete HTML document. An unknown path fails with page not found in docs tree: <PATH>.

docs browse

Opens the two-pane terminal browser: the index on the left, the rendered page on the right. Takes over the terminal (raw mode, alternate screen) and restores it on exit.

Key Action
j / Down Move the selection down
k / Up Move the selection up
Enter Open the selected page in the right pane
Tab Move focus between the panes
/ Enter search mode
q Quit

In search mode, typing builds a query, Backspace deletes, Esc cancels, and Enter jumps to the best fuzzy title match and returns to normal mode.

What the browser does not do

  • Search does not filter the list. The left pane keeps showing every page while you type; the query is only applied when you press Enter, which moves the selection to the top-scoring title. There is no visible result list.
  • The content pane does not scroll. Text is wrapped to the pane, and a page longer than the pane is cut off at the bottom. Tab moves focus for the border highlight, but the content pane has no key bindings of its own.
  • Search is title-only here. / runs a fuzzy match against page titles. Full-text search over page bodies exists, but only the HTTP server exposes it.
Flag Default Meaning
--root <ROOT> docs

docs serve

Starts an HTTP server rendering the same tree as HTML, prints the bound address, and runs until the process is interrupted.

$ mytool docs serve
docs server listening on http://127.0.0.1:34177
press Ctrl+C to stop
Flag Default Meaning
--bind <ADDR> 127.0.0.1:0 Socket address; port 0 picks a free port
--root <ROOT> docs

Shutdown is wired to a child of App::shutdown, so Ctrl-C or SIGTERM drains in-flight responses and returns.

Routes

Request Response
GET / Index page listing every entry, grouped by section
GET /<path>.html The page at <path>.md, rendered as HTML
GET /<path> Falls back to a page stored under exactly that key
GET /search?q=<text>&limit=<n> {"results":[{path,title,snippet,score}]}, limit defaults to 10

Unknown paths and paths containing .. return 404 with a JSON {"error": ...} body. A search failure returns 500 with the same shape.

The server is not access-controlled

--bind is not restricted to loopback. Passing --bind 0.0.0.0:8080 binds to every interface, and there is no authentication and no TLS on any route. The default is loopback with an ephemeral port; anything else exposes your embedded documentation to whoever can reach the address.

Images and other non-markdown assets are not served

Only *.md files are loaded. Any other file under the doc root is skipped at load time, and there is no route that serves raw asset bytes — an <img> tag in a page will 404. Reference images by absolute URL, or accept that the embedded copy is text-only.

docs ask <QUESTION...>

Streams an answer to a question about the doc tree.

Without the ai Cargo feature this command exists but always fails, with the DocsError::AiDisabled diagnostic. The subcommand is deliberately present in both builds so the failure explains itself rather than looking like a typo.

With the ai feature it concatenates the plain-text projection of every indexed page into one prompt context, sends the question, and streams tokens to stdout.

Requirement Value
Cargo feature ai on rtb-docs
Provider Anthropic — not configurable
Model claude-opus-4-7 — not configurable
API key ANTHROPIC_API_KEY environment variable
Root docs, regardless of --root

An empty question fails with docs ask: question is required. A missing key fails with a message naming ANTHROPIC_API_KEY.

The built-in ask is single-provider

The default implementation hard-codes the provider, the model and the credential source. Setting an OPENAI_API_KEY, choosing a different model, or pointing at a self-hosted endpoint does nothing. rtb-docs exposes the AiAnswerStream trait precisely so a tool that needs any of that supplies its own implementation instead of using this one.

The whole doc tree is sent as context on every question. There is no retrieval or ranking step, so a large corpus will exhaust the model's context window rather than degrade gracefully.