Skip to main content

Writing docs

The docs are built, not merely written. Three kinds of drift fail the build; one kind cannot, and that is the one to watch.

Facts are read, never restated

A second copy of a fact is the copy that goes stale — and it goes stale in the flattering direction, still claiming a feature works months after it stopped.

FactRead fromWritten as
Is this done, partial or planned?the status table in API.md<Status of="signal" />
The guard scriptsguards/architecture/data.ts<Guards />
The pipeline stagesguards/architecture/data.ts<Pipeline />
Shared-table writers and readersguards/architecture/data.ts<TableRoles />

Do not hand-write any of those. A <Status of="…" /> naming a row that is not in API.md is a build error, and that is the feature: you cannot document a surface the tracking table has never heard of, and renaming a row makes every page pointing at it fail loudly rather than quietly lose its badge.

What the checks catch

bun run docs-check # examples, API coverage, frontmatter
bun run doc-lint # citations across every Markdown file in the tree
bun run docs:build # all of the above, then the real build

Examples compile. Every ```ts and ```tsx block is extracted and typechecked under the repo's own tsconfig — same strictness, same jsxImportSource — so an example is held to exactly what a reader's project would hold it to. Rename an export and the docs fail in the same run as the code.

A fragment that cannot stand alone (one importing a project's own ./state.ts) gets ```tsx no-check. Those are counted and reported, never silently skipped. If that count climbs, the examples are drifting toward decoration.

The public surface is covered. src/index.ts defines the public-versus-internal line, so it defines what the docs owe a reader. The check runs both ways, and the reverse direction fails hard: a page teaching import { foo } from "dziry" when foo is not exported is a lie a reader will act on.

Citations resolve. src/runtime/signal.ts:140 is checked at build time by the same resolver doc-lint uses. Set DZIRY_SOURCE_URL and they become links.

Frontmatter is present. Sidebars are autogenerated, so a page missing sidebar_position sorts arbitrarily and one missing title gets a name guessed from its filename.

What no check can catch

Whether the prose is true.

Every check above is mechanical: the citation resolves, the example compiles, the name is exported. None of them read the sentence.

That is not hypothetical. On 2026-07-31 a cited comment in this repo turned out to state the opposite of what the doc claimed, and an API design was built on it before anyone opened the file. doc-lint was green throughout, because the line number was fine.

So a clean run means "nothing dangling, nothing that fails to compile". It does not mean the docs are right. When you change behaviour, read the page.

House style

  • Document what is done. Check API.md first. A planned surface gets a badge and, if it needs prose at all, an admonition — not present-tense description of behaviour that does not exist.
  • Explain the constraint, not just the rule. Nearly every restriction in dziry follows from one thing: anything the runtime reaches by name must have a name at build time. A reader who has that can derive the rest.
  • Name the failure. "This compiles cleanly and never updates" is more useful than "this is incorrect", because it says what the reader will actually see.
  • Prefer an example that compiles over one that reads well.
  • Do not quote measurements. Point at the script. A percentage in prose is a memory of a measurement.
  • Pages using components must be .mdx. Plain .md is CommonMark and renders <Status/> as literal text.

After a refactor

  1. bun run docs-check — phantom imports and broken examples surface immediately.
  2. bun run doc-lint — citations that moved.
  3. Read the pages the change touched. This is the step that finds the real damage, and the one there is no tool for.

Versioning

Set up but unused — there is no released version yet. bun run docs:version 0.1 snapshots the current pages when there is something to freeze. Running it early doubles every future edit.