docs¶
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.yamlpresent — 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
# Headingbecomes 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 calledOverview. - Neither pages nor
_index.yaml— the command fails withdocs 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.
Tabmoves 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.
| 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.