Skip to content

Contributing to the docs

The docs are docs-as-code: they live in docs/, build with MkDocs Material, deploy on every push to master via Cloudflare Pages, and CI gates broken refs with mkdocs build --strict.

If you're writing your first docs PR, this page is the convention sheet.

Pick the right artifact type

The directory you write into determines what's expected. Don't put a runbook in architecture/ or vice versa.

Type Live where When to use
Architecture architecture/ Living description of how the system works today
ADR adr/ Why we chose X over Y, frozen at decision time
RFC rfc/ Proposal for a major feature, debated before build
Spec specs/ Frozen feature design at build time
Plan plans/ Implementation plan for multi-session work
Runbook runbooks/ Operational how-to for repeated procedures
Reference reference/ API, models, env vars — lookup material
Guide guides/ Tutorials and walkthroughs (read once)
Postmortem postmortems/ What went wrong + what changed

When in doubt, write an ADR. They're the smallest, cheapest, most useful artifact.

File naming

Pattern Used by
slug.md Architecture, runbooks, reference, guides, principles, contributing
NNNN-slug.md (4-digit padded) ADR, RFC
YYYY-MM-DD-slug.md Specs, plans, postmortems
index.md Section landing page (one per directory)
_template.md Template (excluded from build via exclude_docs in mkdocs.yml)

Numbers are append-only — never reuse an ADR or RFC number. Dates are ISO (2026-04-26).

Frontmatter

Every published page starts with:

---
title: Short, specific title
description: One-line summary (used in nav tooltips and search)
status: active   # one of: new | stub | active | frozen | deprecated
tags:
  - architecture
  - data-model
---

Status values mean:

  • new — recently added, may still change
  • stub — placeholder, fill before relying on
  • active — currently maintained
  • frozen — historical record, not updated (specs, plans, postmortems are usually frozen at write time)
  • deprecated — kept for reference only

Writing rules

  • Lead with the answer. First paragraph says what this page is for and what question it answers.
  • Tables for structured data, prose for narrative. Don't force a table when prose flows better.
  • Concrete over generic. Reference specific files, line numbers, issue numbers. Avoid "this might be useful for various scenarios."
  • Link generously. ADR mentions architecture? Link the architecture page. Architecture mentions a decision? Link the ADR. Cross-linking compounds.
  • Mermaid by default for diagrams. Renders in MkDocs and on GitHub. drawio only when mermaid can't express what you need.
  • Don't paste code dumps. A 200-line code block in a doc dates instantly. Link to GitHub instead, with a permalink (specific commit) if you need the line to be stable.
  • Strunk it. Cut "in order to" → "to". Cut "make use of" → "use". Cut filler paragraphs that say nothing.

What needs updating when making a change

This is the cross-doc consequence checklist. Walk it for every meaningful change so nothing gets stranded. Tick or write n/a.

If you changed... Also update...
src/ code Tests in tests/ mirroring the path
Module structure / package boundaries Architecture → Packages
Request/response shape, route paths Architecture → Build flow or relevant flow page; Reference for the contract
Prisma schema Architecture → Data model, Reference → Prisma models, and an ADR if the change isn't trivial
Scraper for an existing retailer Architecture → Ingest pipeline if behaviour shifted
New retailer docs/reference/retailers.md (when it exists), seed in prisma/seed.ts
Compat rule added/changed Architecture → Build lifecycle (the rules section)
Auth, session, security behaviour New ADR; docs/architecture/threat-model.md (when it exists)
New env var Reference → Env vars, .env.example
New domain term Glossary
New visual / brand token Design system, and a brand voice doc once #42 lands
New page or significant page redesign A spec under docs/specs/, then page implementation issue
Decision that closes off other reasonable alternatives A new ADR
Cross-session-worthy fact (e.g., a tool path, a one-off Windows quirk) ~/claude-os/ (brain repo) or ~/.claude/projects/.../memory/ (per-machine)
Issue scope evolved during implementation The issue body — keep it accurate

If a row applies and you haven't updated it, the PR isn't done.

Reviewing

When you (or future Claude) reviews a docs PR, check:

  • Right artifact type for the content
  • Frontmatter complete and accurate (especially status)
  • Internal links resolve (CI catches broken refs)
  • No stale path references (e.g., docs/superpowers/ paths from before the migration)
  • If it's an ADR, the alternatives section is filled out
  • If it's a runbook, Last verified date is set
  • Mermaid diagrams render (preview locally with mkdocs serve)
  • No content that should have been an ADR or RFC inlined into architecture
  • The "what needs updating" checklist above was applied

Local preview

pip install -r docs/requirements.txt
mkdocs serve

Hot-reloads on every save. http://localhost:8000.

Strict build

Before pushing anything that touches docs/:

mkdocs build --strict

Fails on broken internal links, missing nav references, unrecognised page targets. CI runs the same check on every PR.

What does NOT belong in docs

  • Code comments that should stay with the code. "Why this regex" belongs above the regex, not in a doc.
  • PR descriptions. Use the PR description for the PR; if the decision matters, write an ADR.
  • Personal notes / scratchpads. Use a brain repo (MASTER's ~/claude-os/) or local files.
  • Secrets. Obviously.

Templates

Each directory with templated artifacts has a _template.md. Copy it, rename, fill. Templates are excluded from the build (configured in mkdocs.yml exclude_docs).

cp docs/adr/_template.md docs/adr/0004-your-decision.md

Fill in the placeholders, set status: Proposed, push for review.

Templates evolution

If you find a template missing a field you needed, add it to the template (in the same PR as your filled-in artifact). Template improvements compound.

Project board status updates from the CLI

The project board has a Status field (Todo / In Progress / Done) that the workflow expects to be kept current. Two ways to update it:

  • Quick way: bash scripts/set-issue-status.sh <issue-number> "<status>" — wraps the gh GraphQL plumbing
  • Manual way: the underlying calls are in scripts/set-issue-status.sh — read it once to understand what's happening

Status values: Todo, In Progress, Done.

Auto-close + auto-move-to-Done already work via the project's "Item closed" workflow when an issue closes (via Closes #N in a PR or commit). You only need to manually flip status when you start work (Todo → In Progress) or when an issue is paused/blocked.

Memory updates

961tech docs are the canonical source of truth. Two supplementary memory layers exist for cross-session continuity:

  • ~/claude-os/ (brain repo) — synced across MASTER's machines via git. Use for facts that span all of MASTER's projects (preferences, identity, cross-cutting infra).
  • ~/.claude/projects/<project>/memory/ — per-machine, per-project, auto-loaded into Claude sessions on this machine. Use for one-off Windows quirks, local-tool paths, transient session reminders.

When you discover something cross-session-worthy that doesn't naturally fit a docs page (e.g., "the gh CLI is at ~/bin/gh.exe because winget is broken on this Windows box"), update the appropriate memory layer rather than inventing a new docs section.