Documentation pipeline (docs-as-code)

Overview

How doc automation works and what make docs-check enforces.

What make docs-fix generates, which paths are machine-owned, and how make docs-check catches drift. See also ADR 0001: Adopt Docs as Code.

make docs-fix stages

  1. UMLscripts/regenerate_docs.py renders docs/uml/**/*.puml to SVG under docs/uml/rendered/ (Kroki; requires network).
  2. Marker syncscripts/sync_docs.py refreshes marker blocks in README.md, docs/internal/system-design.html, and docs/internal/developers.html from the Makefile and FastAPI routes (repository tree, Makefile command table where present, HTTP route tables). Environment variables are documented only in env/example, not generated into the README.
  3. Optional Markdown → HTMLscripts/render_docs_html.py rewrites *.html next to any *.md in docs/adr/, docs/developer/, and docs/runbooks/ when those .md files exist.
  4. HTML normalizationscripts/format_docs_html.py normalizes docs/**/*.html except under docs/backlog/ and docs/api/ (pdoc output for make api-docs).
  5. Python API referencemake api-docs runs pdoc on package app and writes HTML under docs/api/ for local browsing and GitHub Pages (linked from docs/index.html).
  6. Docs search indexscripts/build_docs_search_index.py writes docs/assets/search-index.json for client-side search in the docs UI.

Generated and managed paths

Path / pattern Source of truth
docs/uml/rendered/*.svg Generated from sibling docs/uml/**/*.puml (edit PlantUML; commit PNGs after docs-fix).
Marker blocks in README.md, docs/internal/system-design.html, docs/internal/developers.html Human prose outside markers; inside markers overwritten by sync_docs.py.
env/example Authoritative env reference (comments and defaults). Copied to .env via make env-init; not auto-generated into README.
docs/**/*.html (except docs/backlog/ and docs/api/ formatting skips) Hand-edited HTML; normalized by format_docs_html.py. Prose for ADRs, runbooks, and developer guides is maintained as HTML in this repository.
docs/api/ Generated by make api-docs (pdoc) from Python docstrings on package app; also produced as the last step of make docs-fix. Commit the tree after docs-fix so Pages serves api/index.html next to the rest of docs/.
Optional docs/adr/*.md, docs/developer/*.md, docs/runbooks/*.md If added, companions drive generated .html next to them via render_docs_html.py.
docs/openapi/openapi-baseline.json Updated via OpenAPI governance flows (make openapi-accept-changes), not docs-fix.

make docs-check (CI)

docs-check saves git diff HEAD, runs docs-fix, then compares the new diff to the saved one. If they differ, docs-fix changed something — run it, review, and commit. The check covers every path the pipeline can touch.

Files that docs-fix never touches stay as you left them. If generated output already matches HEAD, the two diffs match.

Optional published doc site

Many teams only browse docs/ in git. If you want site search, versions, or a branded site, add a generator (e.g. MkDocs or Docusaurus) and publish to GitHub Pages or CI. That layer is separate from this repo’s Makefile: move content slowly and keep docs-fix for PNGs and marker sync until you replace those steps.

GitHub Pages from the docs/ folder: use Settings → Pages → Deploy from branch → /docs. The site root must have index.html (this repo includes docs/index.html). Add docs/.nojekyll so GitHub does not run Jekyll on static HTML. Project-site URLs look like /{repo}/… without a /docs/ segment; the top nav script supports that layout. Example for repository study_bot: https://iboiarkin96.github.io/study_bot/internal/system-design.html is valid; https://iboiarkin96.github.io/study_bot/docs/internal/system-design.html is not (404), because with Pages rooted at docs/, URLs omit the docs/ prefix — the file lives at docs/internal/system-design.html in git. Python API HTML from pdoc is at /{repo}/api/index.html (same pattern).

Documentation versioning (policy)

Default in this repository: narrative and process docs live in git with the code (docs-as-code). After a feature merges to main, the docs/ tree describes the current repository state. Release discipline uses ADR 0013 and git tags as needed.

When a feature is not yet released but exists on main: readers of the repo see the new docs immediately; operators following only deployed builds should rely on release notes, tags, or internal comms. If external readers must see only released documentation, add a versioned static site (see section 4) and publish snapshots from release tags—for example mike with MkDocs or Docusaurus versioning—so / or stable tracks the last tag and next or branch previews can show unreleased content.

Lightweight alternative: no separate site—documentation “version” is the git tag or release branch; readers open files at that tag in the hosting UI. No extra automation required.

Documentation-only changes on main: pull requests that only update docs/ (and docs/CHANGELOG.md) may merge before implementation lands; follow-up PRs carry code. Notable documentation-facing changes are recorded in docs/CHANGELOG.md. How we mark ADR work (Issue title [ADR], data-adr-weight on the page, Ratification) and the ADR status model are defined in ADR 0018 (roadmap/backlog pills and branch names are separate).

Python API reference (make api-docs)

HTTP API contracts are documented via OpenAPI and developer guides; in-module Python API (packages, classes, functions) is documented from docstrings using pdoc, similar in spirit to Rust’s cargo doc. Use Google-style docstrings; the normative template and agent checklist are in ADR 0016 (see also .cursor/rules/python-docstrings.mdc for editor assistance).

Run make install, then make docs-fix (or make api-docs alone to refresh only API HTML). Output is under docs/api/; commit it with other doc updates so GitHub Pages serves api/index.html. The site home docs/index.html and top nav link to it.

Optional CI: versioned prose sites or extra artifacts

make verify and make docs-check already run docs-fix, which regenerates docs/api/. If you add a separate static-site build (MkDocs, Docusaurus, etc.), run it in CI from the same commit and deploy alongside raw docs/ or replace that layout incrementally.

For a full multi-version prose site (section 4), run the static-site build in CI from the same tag and deploy alongside or instead of raw docs/ browsing; the Makefile pipeline remains the source of committed UML and marker-synced content until you migrate those steps.

In-page “On this page” sidebar (HTML docs)

Long-form pages that load docs/assets/docs-nav.js show a sticky On this page outline beside the article. Keep this mount as the last child of <main>:

<div class="docs-inpage-toc-mount" data-inpage-toc="auto"></div>

The script wraps content after #docs-top-nav into a grid, builds links from h2 / h3 (with generated id where missing), and skips diagram titles inside figure.sys-diagram / .sys-diagram. p.lead is not listed in the sidebar (add an explicit id on a lead only if you need a shareable fragment).

Authoring: cards still help layout. The sidebar lists every in-article h2 / h3 that has an id, except diagram titles inside figure.sys-diagram / .sys-diagram.

Long outlines: many h2/h3 entries produce a tall list; the sidebar scrolls inside a capped height so the block stays usable (see .docs-inpage-toc nav in docs.css). If mount is absent, docs-nav.js adds it automatically.

No duplicate TOC blocks: do not author a manual in-page Contents block on pages that use this script. Keep only the generated On this page sidebar.

The top doc nav must keep the host node <div id="docs-top-nav"> in the DOM (the script injects <nav class="top-nav"> inside it). If the sticky block is missing, see Runbook: In-page “On this page” sidebar missing or empty.

Page history

Date Change Author
Added Page history section (repository baseline). Ivan Boyarkin