Maintaining the docs¶
This site is the project's documentation: its architecture, API contracts and examples. There are no separate design documents; when a design decision changes, the relevant page here changes with it.
Build and review¶
pixi run docs-serve
pixi run docs-build
pixi run -e docs docs-check
pixi run docs-test --output .cache/docs-examples-001
The docs environment pins MkDocs 1.6.1 and Pygments 2.19.2; the default
environment keeps the pinned compiler. docs-build writes the static site to
.cache/docs-site. docs-check builds in strict mode and then checks every
rendered local link, anchor and asset, duplicate HTML ids, and that every API
chapter is in the search index. docs-test compiles and runs every example the
site includes. After visual changes, review desktop and mobile layouts, search,
keyboard focus, theme switching and printing in a browser.
For an example with expensive generic specialization, run it alone with
pixi run docs-test --only <path> --compile-timeout 1800 --jobs 1 --output <dir>;
the timeout and worker count are recorded in the report.
Writing style¶
Use the home page opening as a model. Write as you would explain the library to another programmer: introduce a task or concept, show how it works, then explain the choices and limits that matter.
- Use established functional programming terms: composition, partial
application, folds, algebraic data types, inductive data types, exhaustive
pattern matching and monad transformers. Explain a term through its use;
for example,
Resultis a sum type withOkandErrconstructors, andflat_mapis monadic bind that skips the callback onErr. - Keep terminology precise. A non-raising callback can still mutate state; call it pure only when purity is the property being discussed. Explain an inductive type through its finite constructor-built values and structural recursion.
- Prefer direct verbs and familiar words. Replace promotional claims with an example or a precise contract. Leave out "please", "simply" and bold warnings; state a limit once, plainly.
- Walk through an example with its own values:
positive(-1)returnsErr, sotwicenever runs. - Say what an operation borrows, copies, moves or destroys, when its callbacks run, and how often.
- Keep the failure channels apart: a stored
Err, a raised error, a match with no applicable clause, and iterator exhaustion. State whether a rule applies to a callback, an operation, or a whole pipeline or match. - Give limits where they affect a reader's choice: callback forms, arities, ownership conventions, compilers and targets. Keep planned features separate from implemented ones.
- Use tables for comparisons and lists for steps or parallel choices. Use paragraphs for explanations that build on one another.
- Vary sentences to fit their subject. Avoid repeating a stock opening on every page or turning every explanation into a list of bold claims. Keep an example's walkthrough focused on what its values and callbacks actually do.
- Keep proofs, compiler workarounds and benchmark evidence in the architecture pages. Preserve assumptions, measurement conditions and the meaning of each ratio.
Organize a page around what its reader needs:
| Page | Shape |
|---|---|
| Tutorial chapter | Introduce the concept, show a maintained example, and explain its results. Link to the next chapter and put compiler implementation details in the architecture pages. |
| Reference page | Help the reader choose an operation, then include the api directive and relevant examples. Keep the introduction distinct from the generated package docstring. |
| Architecture chapter | The contract, then how the implementation meets it and why; limits and their sources |
| Guide | Explain a task or decision. Use a table when the reader needs to compare choices or look up a symptom. |
Address the reader as "you", and avoid "we". Name headings after a task or a claim, such as "Transform only the active branch", rather than "Example" or "Discussion".
Where decisions go¶
- A package's contract and the reasons for its design go in its architecture chapter.
- Compiler limitations go in native Mojo boundaries.
- Measurements go in performance; the workflows that produce them go in development or benchmarks.
- What is supported today and what is planned goes in support and limitations.
- Describe current behavior, and label any historical measurement with its setup.
Where things live¶
| Path | Contents |
|---|---|
mkdocs.yml |
Site configuration and navigation |
docs/content/ |
The pages, in Markdown |
docs/examples/ |
Every program the site includes |
docs/examples.json |
The expected standard output of each included program |
docs/public-exports.json |
The reviewed inventory of public names and their source modules |
docs/api.json |
The public API's docstrings, extracted by python scripts/api_docs.py |
docs/hooks.py |
MkDocs hooks: reads the version from pixi.toml, runs the documentation audit, expands directives and publishes source downloads |
docs/theme/ |
The theme: main.html and 404.html templates, assets/ with styles, scripts, favicon and bundled fonts with their licenses |
scripts/docs_contract.py |
The audit and directive rendering, shared by the hooks and the tooling tests |
Directives¶
Pages include generated material with HTML-comment directives:
<!-- api: functions -->
<!-- example: docs/examples/quickstart.mojo -->
<!-- source: docs/examples/<file>.mojo -->
apiwith a package name renders the package's reference from its docstrings, extracted intodocs/api.jsonbypython scripts/api_docs.py: the package docstring, a summary table, then every public name with its signature, description, limitations, parameters, arguments, result and error.examplerenders a complete program as one frame: its file name and download link, the code, the run command and the expected output. The program must be listed indocs/examples.json. The output has no copy button: it is read, not pasted.sourcerenders a file fromdocs/examples/without a run command or output. Use it for a module, or when a page supplies its own run instructions, as in the installed-package quickstart. Runnable programs still belong in the example manifest and need anexampleinclusion elsewhere on the site.
Directives inside fenced code blocks are left alone. Directives never run library code while the site builds.
Rules the audit enforces¶
The build fails unless:
- every page starts with a
#title; - no page contains a hand-written
```mojoblock: include maintained files so readers see exactly what was tested (usetextfences for signatures and sketches); - the
apidirectives name every public package exactly once, so every public name is documented once; docs/api.jsoncovers exactly the reviewed public names, and every public name has a summary, and its documented overloads describe every parameter, argument, result and error;- the set of
exampledirectives equals the set of programs indocs/examples.json, and each expected output ends with a newline; - every
sourcedirective names a.mojofile indocs/examples/.
In docstrings, put code in backticks: an unbackticked name[X](args) renders
as a broken Markdown link.
Documenting an API¶
The docstrings are the API documentation. A package docstring opens its page
with the package's shared contracts; each public name's docstring starts with a
one-line summary, then the description, an optional Limitations: block, and
the Parameters:, Args:, Returns: and Raises: sections. Fully document
at least one overload of each function; the others need a summary line and are
listed collapsed. Together they state, as it applies:
- purpose and exact signature;
- its relationship to Mojo's native capabilities (what it reuses, what gap it fills);
- type constraints;
- ownership: what is borrowed, copied, moved and destroyed;
- evaluation order, laziness and short-circuiting;
- errors, and the empty-input and no-match behavior;
- complexity, allocation and stack behavior;
- target support;
- the laws it satisfies and their assumptions.
When an API changes, review the new inventory from
export_contract.export_inventory() (in scripts/) and write it to
docs/public-exports.json; the build rejects any unreviewed difference. Then
update the docstrings, run python scripts/api_docs.py to refresh
docs/api.json, and add or update examples. Never regenerate expected outputs
from a failing implementation: review them independently.
Adding an example¶
- Write a complete program in
docs/examples/with amainthat asserts its results withstd.testing, and a one-line docstring. - Add its path and exact expected output to
docs/examples.json. - Include it on the page it illustrates with an
exampledirective, and list it in the example gallery. - Run
docs-testfor it anddocs-check.
Every file in docs/examples/ is also part of the test suite.
Theme¶
The theme is a small custom MkDocs theme: Jinja templates for the page shell,
navigation and search page, one stylesheet (assets/site.css), and scripts for
theme switching, mobile navigation, copy buttons and search. Fonts are bundled,
so the site makes no external requests; search uses MkDocs' generated index with
its bundled Lunr. Keep URLs relative so the site works under any path.
The header shows the version from pixi.toml and links to its GitHub release;
the sidebar and footer name the Mojo series from the mojo dependency. Both are
read at build time, so bumping the version at a release updates the site.
site.css defines every color as a token on :root.light and :root.dark; the
rest of the stylesheet uses only the tokens. Syntax colors follow Catppuccin:
Latte hues, deepened for contrast, in the light theme and Mocha in the dark.
Keywords are purple, types amber, functions blue, modules teal, strings green,
numbers and constants orange, decorators pink, self red, operators sky and
comments grey italic. Prose is limited to about 74 characters a line; code and
tables use the full column. See MkDocs' theme guide and
configuration reference.
The minimal program used on the home page is also the smallest example of the directive format:
"""The smallest complete FP Mojo program."""
from fp.functions import identity, pipe
from std.testing import assert_equal
def twice(var value: Int) -> Int:
return value * 2
def main() raises:
var answer = pipe(21, twice)
assert_equal(answer, 42)
print(answer)
Run from the repository root pixi run mojo run -I src docs/examples/quickstart.mojo
Output
42