Skip to content

Documentation Style Guide

Applies tov1.4.0DifficultyBeginner

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.

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.

Task pages follow this order without exception. Readers rely on it.

  1. Frontmattertitle and description. The description is what search results show.
  2. <PageMeta> — version, hardware, requirements, difficulty, restart impact.
  3. One-paragraph statement of what the page does and why someone would want it.
  4. “What this changes” — a diagram or before/after, for anything structural.
  5. <Prerequisites> — exact versions, ports, permissions, plus a pre-flight command.
  6. Numbered steps — with <Tabs syncKey="interface"> for Python / TypeScript / CLI / Helm / cURL.
  7. <Verify> — the command, the expected output, and what a failure means.
  8. Edge cases and known limitations — what quietly bites.
  9. 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.

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.

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.

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.

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.

  • 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 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:

  1. Append an entry with a unique code prefixed ERR_OCULIS_.
  2. Write logSignature as a real, grep-able fragment of the log line. This is what someone pastes into search.
  3. Point guide at the section that resolves it.
  4. 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.
  • 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.

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.

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.

  • npm run build passes — this includes astro 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, or easy.
  • Links resolve — the build fails on a broken <ErrorCode>, but not yet on a broken URL.