Contributing to the docs¶
This page covers the conventions for editing prose docs, adding API
reference pages, and regenerating the auto-generated bits. It is the
counterpart to docs/gen_ref_pages.py — read both if you are touching
the reference surface.
Quick reference¶
# Install docs dependencies
uv sync --extra bedrock --group docs
# Build the site locally and serve at http://127.0.0.1:8000
uv run mkdocs serve
# Strict build (used by CI; must be green before merging)
uv run mkdocs build --strict
# Regenerate docs/reference/*.md after editing __all__
uv run python docs/gen_ref_pages.py
# Check for reference drift (CI-style)
uv run python docs/gen_ref_pages.py --check
Prose docs (docs/*.md)¶
The hand-authored pages under docs/ populate six tabs:
| Tab | What lives here |
|---|---|
| Home | docs/README.md — project intro, key features, quick start. |
| Guide | Procedural how-to docs — setup.md, the per-TUI guides (home.md, board.md, settings.md, memory-browser.md, review.md, observations.md, graph.md, logs.md), bridge.md, and sync.md. |
| Concepts | Conceptual prose (philosophy.md, memory.md). |
| Architecture | System design (architecture.md). |
| Reference | docs/reference/skills.md (hand-authored) plus the Python API pages under docs/reference/{tools,hooks}/ (auto-generated — see below). |
| Contributing | Developer-facing docs (development.md, this file). |
When deciding where a new page belongs, think about why the reader is opening it: stepping through a procedure → Guide, building a mental model → Concepts, looking up specifics → Reference.
Conventions:
- Markdown, GitHub-style. The full set of pymdown extensions is
enabled in
mkdocs.yml— admonitions, tabbed code blocks, mermaid fences, footnotes, etc. - British English spelling and grammar (behaviour, organise, centred).
- Imperative mood in step-by-step guides ("Run the migration", not "You should run the migration").
- Headings start at H2 within a page; the H1 is the page title declared in the nav.
- Internal links use relative Markdown paths (
./memory.md,../architecture.md); strict mode catches broken targets. - Code blocks declare their language for syntax highlighting:
```python,```bash,```toml, etc.
To add a new prose page:
- Create the file under
docs/(or a subdirectory if a section grows that warrants nesting). - Add it to the
nav:block inmkdocs.ymlunder the appropriate tab —strict: truewill fail the build if a doc exists but is not in the nav. - Run
uv run mkdocs build --strictto verify.
API reference (docs/reference/)¶
The Python API pages — docs/reference/{context,cli,config,llm,logging,ssl,bridge}.md plus the nested docs/reference/tools/*.md and docs/reference/hooks/*.md — are regenerated from each module's __all__ by docs/gen_ref_pages.py. Editing those files by hand is futile — the next regeneration run overwrites them, and CI's --check invocation will flag the drift.
docs/reference/skills.md and docs/reference/mait-code.md (the mait-code CLI command reference) are the only hand-authored files under docs/reference/. Edit them directly — skills.md when adding or renaming a slash command, mait-code.md when changing a CLI command. (Note the deliberate split: reference/cli.md is the generated mait_code.cli Python API, while reference/mait-code.md is the hand-authored command reference.)
The nested layout mirrors the dotted module hierarchy: mait_code.tools.memory lives at docs/reference/tools/memory.md and renders at /reference/tools/memory/.
The __all__ contract¶
For a module to surface in the reference, it must:
- Be listed under one of the groups in
REFERENCE_MODULESinsidedocs/gen_ref_pages.py(Core, Bridge, Tools, or Hooks). - Declare
__all__as a list (or tuple) of string literals. - Live at
src/mait_code/<name>.pyorsrc/mait_code/<dotted>/<name>/__init__.py(the generator resolves either layout).
The generator parses __all__ via ast, then re-scans the source
text for # Section comments interleaved inside the list. Those
comments become H2 headings on the rendered page, grouping the
symbols below them.
Example from src/mait_code/tools/memory/__init__.py:
__all__ = [
# CLI
"main",
# Storage
"connection",
"get_connection",
# Embeddings
"EmbeddingProvider",
"embed_text",
...
]
becomes a page with ## CLI, ## Storage, ## Embeddings, …
headings, each followed by a ::: mkdocstrings directive per symbol.
If a module has fewer than ~3 symbols, the section comments are usually noise — leave them out and let the symbols render as a flat list.
Adding a module to the reference¶
- Add
__all__to the module's__init__.py(or the single-file module). Re-export the public symbols you want documented; keep internals out. - Optionally group with
# Sectioncomments. - Append a
(dotted_name, display)tuple to the relevant group inREFERENCE_MODULES("Core","Bridge","Tools", or"Hooks") insidedocs/gen_ref_pages.py. The display is the leaf name only —"Memory", not"Tools — Memory"— since the group is conveyed by the surrounding nav section. - Add the page to the corresponding nested sub-section of
Reference → Python APIinmkdocs.yml. The file path mirrors the dotted name:tools.memory→reference/tools/memory.md. - Regenerate:
uv run python docs/gen_ref_pages.py. - Verify drift-free:
uv run python docs/gen_ref_pages.py --check. - Verify strict build:
uv run mkdocs build --strict.
Removing a symbol from the reference¶
Remove it from __all__. The next regeneration drops it from the
page. Do not edit the generated Markdown directly.
Google docstring style¶
mait-code uses Google-style docstrings throughout src/mait_code/
because mkdocstrings (configured for docstring_style: google)
renders them into the reference pages.
The shape:
def store_memory(content: str, *, importance: int = 5) -> int:
"""Persist an observation to the memory store.
Longer prose paragraph that explains the *why*, the side
effects, or any subtle behaviour. Omit if the summary line is
self-explanatory.
Args:
content: The observation text to store.
importance: 1-10 weight feeding the recency/importance
composite score.
Returns:
The new entry's primary-key ID.
Raises:
ValueError: If ``content`` is empty.
"""
Conventions:
- Imperative summary line: "Persist X", not "Persists X" / "This function persists X".
- Skip
Args:if there are no parameters worth documenting beyond what the signature already conveys. - Skip
Returns:if the function returnsNoneobviously. - Use double back-ticks for inline code (mkdocstrings renders them cleanly in either Markdown or HTML contexts).
If mkdocs build --strict complains about a symbol's docstring
mentioning an annotation that isn't on the signature (griffe: No
type or annotation for parameter X), add the missing type
annotation rather than removing the documentation.
What CI runs¶
.github/workflows/docs.yml runs these on every push to main, every PR, every v* tag, and on release: published:
uv sync --locked --group docs
uv run python docs/gen_ref_pages.py --check
uv run mkdocs build --strict
Pushes to main and tag pushes additionally deploy to GitHub Pages via mike — the dev alias from main, version + latest aliases from tags. PRs build but do not deploy.
Run the same three commands locally before pushing to catch failures early.