Documentation Style Guide
These docs borrow their rigor from Cisco and NetApp — explicit prerequisites, mandatory verification, diagnostic matrices — and their reading experience from modern developer docs. This page is the contract that keeps both halves intact.
The one rule
Section titled “The one rule”Every task-oriented page must end in an observable signal.
A configuration guide that stops at “apply this config” is unfinished. The reader has no way to know whether it worked, and will find out in production. Every procedure terminates in a command to run and the exact output that proves success.
If you write a page and cannot produce a <Verify> block for it, the page is describing something
that is not yet verifiable — fix that first.
Page anatomy
Section titled “Page anatomy”Task pages follow this order without exception. Readers rely on it.
- Frontmatter —
titleanddescription. The description is what search results show. <PageMeta>— version, hardware, requirements, difficulty, restart impact.- One-paragraph statement of what the page does and why someone would want it.
- “What this changes” — a diagram or before/after, for anything structural.
<Prerequisites>— exact versions, ports, permissions, plus a pre-flight command.- Numbered steps — with
<Tabs syncKey="interface">for Python / TypeScript / CLI / Helm / cURL. <Verify>— the command, the expected output, and what a failure means.- Edge cases and known limitations — what quietly bites.
- Next steps — a
<CardGrid>of<LinkCard>s.
Troubleshooting pages substitute a <DiagnosticMatrix> for steps 4–6, then follow the same shape.
Write to an engineer under pressure. They are not reading for pleasure; they are looking for one specific thing. Put the answer first, then the explanation.
Be specific. “Set a reasonable timeout” is useless. “Set timeout_seconds: 60; a cold cloud
fallback can take 10 s before its first byte” is usable.
Say what will go wrong. The most valuable sentences in these docs are the ones that name the
failure a setting causes. “Raising gpu_memory_utilization is almost never the fix” saves more
time than three paragraphs of theory.
State trade-offs plainly. Every optimization costs something. Name it.
Do not hedge. “You may want to consider possibly enabling” — pick one. If there is a right default, say so and explain when to deviate.
Word choices
Section titled “Word choices”| Use | Not |
|---|---|
| “Run this command” | “Simply run this command” |
| “This requires a restart” | “Note that this may require a restart” |
| “Set X to Y” | “You’ll want to set X to Y” |
| “If X fails, do Y” | “In the unlikely event that X fails” |
| “Time to first token (TTFT)” | “TTFT” on first use |
Never write “simply”, “just”, “obviously”, or “easy”. If it were easy the reader would not be here.
Code samples
Section titled “Code samples”Every sample must be runnable. No <your-value-here> placeholders inside otherwise-complete
commands — use a real-looking value and say what to substitute.
Multi-interface tasks use synced tabs. syncKey="interface" means a reader who picks Helm on
one page sees Helm everywhere.
Title every block that is a file.
```yaml title="oculis-config.yaml"Highlight the lines that matter when a sample is long:
```yaml title="oculis-config.yaml" {8-13}Use frame="terminal" for expected output, so it is visually distinct from input.
Never put a real secret in a sample. Use ${env:OPENAI_API_KEY} — which also documents the
right practice.
Components
Section titled “Components”| Component | Use it for |
|---|---|
<PageMeta> |
The compatibility strip. Every task and reference page. |
<Prerequisites> |
Opening every task page. Include checkCommand. |
<Verify> |
Closing every task page. Non-negotiable. |
<ErrorCode> |
Any mention of an error code, inline. |
<DiagnosticMatrix> |
Troubleshooting pages, and failure modes a config produces. |
<VramCalculator> |
Capacity planning only. |
<Aside type="…"> |
note, tip, caution, danger. |
Blank lines inside components
Section titled “Blank lines inside components”Markdown nested in a component needs a blank line after the opening tag and before the closing tag, or MDX parses it as inline text rather than block content. A list without them renders as one run-on paragraph — and it renders, so nothing fails and you only notice by looking.
<Prerequisites checkCommand="oculis status --check-deps">
- **Oculis Collector** `v1.4.0` or later- **Ports:** `8080` inbound
</Prerequisites>For the same reason, src/content/docs/ is excluded from Prettier in .prettierignore. Prettier’s
MDX printer reflows those lists back into a paragraph, re-indents <Tabs> nested in <Steps> until
the JSX no longer closes, and moves inline <ErrorCode> chips onto their own line, turning them
into block elements mid-sentence. Format prose by hand.
Aside severity
Section titled “Aside severity”note— useful context the reader can skip.tip— a better way to do what they are already doing.caution— this will cost you time if ignored.danger— this will cause an outage, data loss, or a security incident.
Do not inflate. A page where everything is danger teaches readers to skip every danger.
Error codes
Section titled “Error codes”Error codes live in one place: src/data/errors.ts. The diagnostic matrix, the error index, and
every inline <ErrorCode> chip read from it.
Adding a code:
- Append an entry with a unique
codeprefixedERR_OCULIS_. - Write
logSignatureas a real, grep-able fragment of the log line. This is what someone pastes into search. - Point
guideat the section that resolves it. - Build.
<ErrorCode>throws on an unknown code, so a typo fails CI rather than shipping a dead link.
Never write an error code as plain text in prose — always <ErrorCode code="…" />, so it links and
stays consistent.
- Internal links are root-relative with a trailing slash, and include the product segment:
/ai/gateway-routing/fallback-failover/. - Deep-link to sections when you mean a specific procedure:
/ai/performance-tuning/#kv-cache-quantization. - Link the first mention of a concept on each page, not every mention.
Headings
Section titled “Headings”- Sentence case: “Reducing time to first token”, not “Reducing Time To First Token”.
##for major sections,###for subsections.####is a signal the page needs splitting.- Heading text becomes the anchor, so renaming a heading breaks inbound links. If you must, search the repo for the old anchor first.
Tables
Section titled “Tables”Use tables for anything a reader will scan rather than read: compatibility, parameters, status codes, trade-offs. Every parameter table should have a “why it matters” column, not just a description — the type is already in the schema reference.
Diagrams
Section titled “Diagrams”ASCII diagrams in a text code block. They render in both themes, need no build step, diff
cleanly in review, and copy into a terminal or a ticket.
Keep them under ~80 columns so they do not force horizontal scrolling on mobile.
Before you open a PR
Section titled “Before you open a PR”npm run buildpasses — this includesastro check.- Every code sample was actually run.
- The
<Verify>block output is real output, not invented. - New error codes are in
src/data/errors.ts. - No
simply,just, oreasy. - Links resolve — the build fails on a broken
<ErrorCode>, but not yet on a broken URL.