Contributing to Docs
This page explains how the beef monorepo keeps documentation honest. Every gate below runs in CI and can be run locally before pushing.
Philosophy
Section titled “Philosophy”Docs are a single source of truth, not a courtesy. If a behaviour, contract, or operational procedure exists only in code, future-you (and on-call) cannot find it. The CI gates make “the docs lie” a build failure rather than a tribal-knowledge problem.
File layout
Section titled “File layout”docs/src/content/docs/overview/— high-level orientation.docs/src/content/docs/architecture/— cross-service architecture.docs/src/content/docs/services/— per-service deep dives. Mirrorsapps/*.docs/src/content/docs/standards/— coding, testing, and review conventions.docs/src/content/docs/operations/— runbooks, on-call, deploys.docs/src/content/docs/flows/— end-to-end user/data flows that span services.docs/src/content/docs/decisions/— Architectural Decision Records (ADRs).docs/src/content/docs/generated/— machine-generated content. Do not hand-edit.
Write an ADR whenever you make a non-trivial, hard-to-reverse decision: choice of library, protocol, data model, sync vs async boundary, vendor, etc. If you would explain it in a design review, write it down.
- Copy
docs/src/content/docs/decisions/_template.md. - Filename:
YYYY-MM-DD-kebab-slug.md. - Required frontmatter:
title,status(Proposed|Accepted|Superseded|Deprecated),date. - Required sections:
## Context,## Decision,## Consequences. Optional:## Alternatives Considered.
The adr-template-check CI gate enforces the above.
CI gates
Section titled “CI gates”The Docs Quality workflow (.github/workflows/docs-quality.yml) runs on every PR, on each merge-queue group, and on push to main:
| Gate | What it checks |
|---|---|
markdown-lint |
Markdown style across docs/**/*.md and root *.md per .markdownlint.jsonc. |
link-check |
Scheduled external URL health via Lychee. |
astro-build |
Locked Starlight production build. |
source-checks |
ADR shape, proto/KB sync, frontmatter, citations, and internal routes/anchors. |
docs-required-check |
A PR touching apps/* or proto/* must also touch docs/ (or carry a bypass marker). PR runs only; it reports skipped, which passes, in the merge queue and on push. |
Run the gates locally
Section titled “Run the gates locally”From the repo root:
# Astro buildpnpm --dir docs install --frozen-lockfilepnpm --dir docs buildnode scripts/docs-check-mermaid.mjs --built
# Markdown lintpnpm dlx markdownlint-cli2 "docs/**/*.md" "*.md"
# ADR templatebash scripts/docs-check-adr-template.sh
# Proto syncbash scripts/docs-check-proto-sync.sh
# KB, frontmatter, citations, and internal linksbash scripts/docs-check-kb-sync.shnode scripts/docs-check-frontmatter.mjsnode scripts/docs-check-citations.mjsgo run scripts/check-doc-links.go
# Docs-required (simulates the PR check against main)GITHUB_BASE_REF=main PR_TITLE="$(git log -1 --pretty=%s)" bash scripts/docs-check-required.shBypassing the docs-required check
Section titled “Bypassing the docs-required check”The docs-required-check gate fails when a PR changes code under apps/* or proto/* but does not change anything under docs/. Bypass it only when a docs update is genuinely not needed.
Add one of the following to the PR title:
[skip-docs]: <short reason>— e.g.[skip-docs]: internal log-format tweak.- A conventional-commit prefix that implies no behavioural change:
chore:,ci:,test:,style:.
Use sparingly. If reviewers cannot tell from the diff that no doc was needed, write the doc.
Regenerating the proto API doc
Section titled “Regenerating the proto API doc”Proto reference output lives at docs/src/content/docs/generated/proto-api.md and ends with a <!-- proto-checksum: <hex> --> marker. After editing any proto/**/*.proto file:
bash scripts/gen-proto-docs.shThe generator and sync checker must change together if their checksum algorithm changes.