How we document
This page is the contract for the docs. Read it before you add or change a page — it exists so the documentation stays coherent as more people write it.
The framework: Diátaxis
Section titled “The framework: Diátaxis”We organise every page with Diátaxis. It splits documentation into four kinds, each serving a different need. The single most important rule: a page belongs to exactly one kind. Mixing kinds on one page is the most common way docs rot — a tutorial that stops to explain theory loses the beginner; a reference that editorialises can’t be trusted as a lookup.
| Kind | Directory | Serves | Answers | Voice |
|---|---|---|---|---|
| Tutorial | tutorials/ |
Learning | “Teach me by doing” | “We will…” — a guided lesson, guaranteed to work |
| How-to guide | how-to/ |
A task | “How do I X?” | “To do X, do this” — a recipe for someone who already knows the goal |
| Reference | reference/ |
Looking something up | “What are the exact parameters?” | Dry, complete, accurate. Describes, never persuades |
| Explanation | explanation/ |
Understanding | “Why is it built this way?” | Discursive. Background, trade-offs, alternatives |
The quick test when you’re unsure which kind you’re writing:
- Is it a lesson for a newcomer, correct start to finish? → Tutorial
- Is it steps to accomplish one real-world task? → How-to guide
- Is it a dry description of what exists (endpoints, flags, fields)? → Reference
- Is it discussion of why, or how pieces fit? → Explanation
If a page wants to be two things, split it and link the halves.
Where things live
Section titled “Where things live”docs-site/src/content/docs/├── index.mdx # landing page (the four quadrants)├── contributing/│ └── how-we-document.md # this page├── tutorials/ # learning-oriented, start-to-finish lessons├── how-to/ # task-oriented recipes (deploy, teardown, …)├── reference/ # configuration, repo layout, and…│ └── api/ # ← GENERATED from the OpenAPI spec, do not edit└── explanation/ # architecture, protocol, roadmapThe sidebar groups in astro.config.mjs mirror these four directories. New
files in tutorials/, how-to/, and explanation/ appear in the sidebar
automatically (those groups use autogenerate); reference/ is a curated
list, so a new top-level reference page needs a line added to the sidebar
config.
Adding a page
Section titled “Adding a page”-
Decide the kind (table above) — that picks the directory.
-
Create a Markdown (
.md) or MDX (.mdx) file there. Use MDX only when you need components (cards, tabs, asides); prefer plain Markdown otherwise. -
Give it frontmatter —
titleis required,descriptionis strongly encouraged (it’s the search snippet and social preview):---title: Roll back a deploydescription: Revert the cluster to the previously released image tag.--- -
If it’s a new reference top-level page, add it to the
Referencesidebar group inastro.config.mjs. -
Run
npm run devand check it renders and lands in the right sidebar group.
Frontmatter you’ll actually use
Section titled “Frontmatter you’ll actually use”| Field | Purpose |
|---|---|
title |
Required. Page <h1> and sidebar label. |
description |
Search result + social card text. Write it. |
sidebar.order |
Force ordering within a group (lower = higher). |
sidebar.label |
Override the sidebar text when it should differ from the title. |
tableOfContents: false |
Drop the right-hand on-page nav for short pages. |
Starlight components (asides, cards, tabs, steps, code groups) are documented at https://starlight.astro.build/components/. Use them sparingly and only where they aid comprehension.
The API reference is generated — never hand-written
Section titled “The API reference is generated — never hand-written”The pages under Reference → API Reference are rendered from
src/openapi.json, which is generated from the FastAPI app, not authored
here. This is deliberate: the published reference can then never drift from the
code.
The flow:
server/src/vouch ──► server/scripts/dump_openapi.py ──► src/openapi.json ──► starlight-openapi ──► Reference/API-
src/openapi.jsonis committed so the site builds anywhere Node runs, but treat it as a build artefact — do not edit it by hand. -
Regenerate it whenever you change a route or a Pydantic schema:
Terminal window cd docs-site && npm run sync:api -
CI runs the same step before every build:
.github/workflows/docs.ymlas a PR/push check, andscripts/build_push.shwhen the Deploy workflow bakes the docs image, so the published reference always reflects the deployed code.
To improve the API docs, change the code, not the JSON — add FastAPI
summary=/description=/tags= and Pydantic field docs/examples, then
npm run sync:api. Good annotations in the routers are what make the reference
readable.
Local workflow
Section titled “Local workflow”cd docs-sitenpm installnpm run sync:api # refresh the API spec from the server (needs uv)npm run dev # live-reloading site at http://localhost:4321npm run build # production build into dist/ (what CI publishes)Style conventions
Section titled “Style conventions”- One kind per page — the rule worth repeating.
- Prefer plain Markdown; reach for MDX only when a component earns its keep.
- Wrap prose near ~80 columns to keep diffs reviewable.
- Link generously between the four quadrants: a how-to can link to the explanation of why; an explanation can link to the reference for exact values. Cross-links are how the quadrants stay separate without stranding the reader.
- Keep runbook commands copy-pasteable and in the same order an operator runs them.