| name | api-docs |
| description | Generate human-readable API reference documentation (Markdown) from an rfc-to-api IR, an existing OpenAPI/GraphQL spec, or (as a fallback) implemented route/handler source code. Use whenever the user asks to document an API or endpoints, generate API reference docs or a README for an API, or write developer-facing docs for a service. |
api-docs
Generates a single Markdown API reference document. This skill's primary
path renders from an already-produced contract, and only falls back to
reading source code when no structured contract exists at all.
Requires: scripts/render_docs.py, design/_shared/rest_path.py, and
design/_shared/naming.py (stdlib-only Python 3) โ the same REST path/verb
derivation rfc-to-api's OpenAPI renderer uses, so the docs never disagree
with the spec on a method/path. install.sh places these automatically.
Step 1 โ Resolve the input, in priority order
rfc-to-api's api.ir.json โ if the user points at one (or it's
the obvious sibling to something else they mentioned), use it. If a
sibling schema.ir.json also exists, use it too (entity field
resolution for response bodies) โ same explicit/sibling convention as
the rest of this repo, not a repo-wide search.
- An existing OpenAPI or GraphQL SDL spec file (not generated by this
repo) โ if given one instead, read it directly; there's no IR to run
render_docs.py against, so build the same document structure by hand
from the spec's own operations/schemas.
- Implemented route/handler source code โ only if neither of the
above exists. In this mode, read the code directly to infer the
contract (methods, paths, request/response shapes, auth checks) the
same way
security-review/performance-review read source โ but the
output is still contract documentation, not a security/performance
finding. Say explicitly in the report's intro that the contract was
reverse-engineered from implementation, not sourced from a spec, since
that's a materially weaker starting point than the first two paths.
If none of the three exist, ask what to document.
Step 2 โ Run the structural pre-pass (IR path only)
python3 <skill_dir>/scripts/render_docs.py --ir-file api.ir.json [--schema-ir-file schema.ir.json]
Produces a Markdown skeleton: one ### heading per operation with its
resolved REST path/verb, an auth/scopes/idempotency/pagination summary
line, request/response field tables, and an error table. Every place the
script can't fill in on its own is left as an explicit placeholder for you
to replace โ never leave one in the final doc:
<DESCRIPTION: ...> โ expand the operation's own IR description (or the
spec's, or your own read of the code) into a fuller explanation: what
it's for, when to use it, any non-obvious behavior (idempotency,
side effects).
<EXAMPLE:description for FIELD> โ a one-line explanation of what this
field actually means in context, not a restatement of its type.
<EXAMPLE:request body> / <EXAMPLE:response body> โ a full synthesized
JSON example.
A path/verb marked best guess, no entity/ref hint on this operation โ verify means the operation IR has no entity field and no ref in its
input/output โ the derived path is a low-confidence fallback. Flag this
plainly in the doc rather than presenting it with the same confidence as
a normally-derived path.
Step 3 โ Write descriptions
Expand every <DESCRIPTION: ...> placeholder. Write for a developer who
has never seen this API โ state what the operation does, any idempotency/
side-effect behavior already declared in the IR (don't just restate
idempotent: true as a checkbox, say what that means practically), and
auth/scope requirements in plain language.
Step 4 โ Synthesize examples
For every <EXAMPLE:...> placeholder, synthesize a realistic-looking
value from the field's declared type and name โ an email field gets
"jane@example.com", a createdAt/*_at datetime field gets a plausible
ISO timestamp, an id/ref field gets a realistic-looking UUID, an
enum field gets one of its declared values. Build full request/response
body examples the same way, matching the field table exactly (same field
names, same nesting for object/array fields).
Mark every synthesized example clearly โ a trailing _(example)_
next to each generated body, consistent with this repo's "never let
inferred details look as certain as stated ones" convention (the same
spirit as the RFC pipeline's assumed: true flag). These are illustrative
values, not captured real traffic โ say so.
Step 5 โ Write the report
Write API_DOCS.md next to the input that was read (the api.ir.json,
the spec file, or โ for the source-code fallback โ the codebase root),
falling back to cwd only if that input has no filesystem location, same
convention as the rest of this repo. Show it inline too.
Structure: a one-paragraph API overview at the top, then one section per
operation in IR/spec order (no reordering by name or category โ match the
source's own order so the doc is easy to cross-reference against it).
No JSON intermediate โ the rendered Markdown skeleton from Step 2 (with
every placeholder filled) is the final artifact directly.
Every invocation is treated as a fresh render โ no staleness/drift check
against a previously-generated doc, and no diff against a prior run of
this same IR, in v1. Implementation-vs-IR drift checks are
security-review's/performance-review's job, not this skill's.
Rules
- Don't leave any
<DESCRIPTION:...>/<EXAMPLE:...> placeholder unfilled
in the final doc.
- Don't present a low-confidence (no-entity-hint) path derivation with the
same certainty as a normally-derived one.
- Don't present a synthesized example as if it were real captured data โ
always mark it
_(example)_.
- Don't reverse-engineer a contract from source code if an IR or spec file
is available โ that's the last-resort path, not a default.
- Don't reorder operations by name/category โ preserve the source's own
ordering.