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
-
UML —
scripts/regenerate_docs.pyrendersdocs/uml/**/*.pumlto SVG underdocs/uml/rendered/(Kroki; requires network). -
Marker sync —
scripts/sync_docs.pyrefreshes marker blocks inREADME.md,docs/internal/system-design.html, anddocs/internal/developers.htmlfrom the Makefile and FastAPI routes (repository tree, Makefile command table where present, HTTP route tables). Environment variables are documented only inenv/example, not generated into the README. -
Optional Markdown → HTML —
scripts/render_docs_html.pyrewrites*.htmlnext to any*.mdindocs/adr/,docs/developer/, anddocs/runbooks/when those.mdfiles exist. -
HTML normalization —
scripts/format_docs_html.pynormalizesdocs/**/*.htmlexcept underdocs/backlog/anddocs/api/(pdoc output formake api-docs). -
Python API reference —
make api-docsrunspdocon packageappand writes HTML underdocs/api/for local browsing and GitHub Pages (linked fromdocs/index.html). -
Docs search index —
scripts/build_docs_search_index.pywritesdocs/assets/search-index.jsonfor 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 |