How the docs work¶
Documentation is derived from source wherever possible so it cannot drift. Each surface has one canonical source.
| Surface | Source of truth | Tool |
|---|---|---|
| HTTP API | FastAPI routes + Pydantic models | OpenAPI → Scalar |
| Python core / SDK | docstrings + type hints | mkdocstrings |
| UI components | the React components themselves | Storybook |
| Guides / concepts | hand-written Markdown | Zensical |
The umbrella site is built with Zensical (the static site generator from the
Material for MkDocs team), configured in zensical.toml.
Storybook is built separately (it is a Vite/React app) and published under
/storybook on the same site.
Build locally¶
# from the repo root
python -m pip install -r requirements-docs.txt
python scripts/gen_openapi.py # regenerate docs/api/openapi.json
python -m zensical serve # live-reload at http://localhost:8000
# component docs
cd frontend && npm install && npm run storybook # http://localhost:6006
The Makefile wraps these: make docs-serve, make docs-build, make
storybook (each docs target regenerates the OpenAPI schema first).
How each piece is wired¶
- OpenAPI -
scripts/gen_openapi.pyimports the FastAPI app and writesdocs/api/openapi.json. It is intentionally SSG-agnostic (no build-plugin dependency), so it works under Zensical, MkDocs, or anything else. Run it before every site build.docs/fxquinox/api/scalar.htmlis a standalone, full-screen Scalar page that renders the schema; the nav links to it directly (like Storybook) rather than embedding it. The generated JSON is git-ignored - it is always rebuilt. - Python autodoc -
zensical.tomlconfigures themkdocstringsPython handler withpaths = ["backend/src", "sdk-python/src"];requirements-docs.txtinstalls both packages editable so they import cleanly. Add new modules by droppingdotted.pathinto a page. - Storybook - config in
frontend/.storybook/. Stories live next to components as*.stories.tsx. It reuses the app's Vite config (so the@alias and Tailwind work) and imports the global stylesheets inpreview.tsx.
Conventions¶
- Python: Google-style docstrings (matches the mkdocstrings config).
- Keep guides task-oriented; let autodoc carry the exhaustive reference.
docs/is the public docs root - only publishable pages live there. Internal specs and milestone plans live inplanning/, outsidedocs_dir, so they are never published.
Excluding files is not yet supported in Zensical
Zensical (v0.0.x) does not yet support exclude_docs / not_in_nav. That
is why internal planning docs live in planning/ rather than inside docs/.
If you generate new planning docs (e.g. via a plan-writing workflow that
defaults to docs/superpowers/), keep them out of docs/ or they will
be published until Zensical adds an exclude mechanism.
Publishing¶
CI (.github/workflows/docs.yml) builds the Zensical site and Storybook on
every PR, and deploys to GitHub Pages on push to main. To go live, enable Pages
with the GitHub Actions source in the repository settings.