Skip to content

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.py imports the FastAPI app and writes docs/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.html is 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.toml configures the mkdocstrings Python handler with paths = ["backend/src", "sdk-python/src"]; requirements-docs.txt installs both packages editable so they import cleanly. Add new modules by dropping dotted.path into 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 in preview.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 in planning/, outside docs_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.