Building & testing the docs#
The documentation is built with Sphinx. The build needs none of the compiled
stack (NEML2, MOOSE/PUMA, NEPER, CUBIT); docs/conf.py mocks those imports,
so it runs from a plain checkout.
System prerequisite: pandoc#
The tutorials are Jupyter notebooks, and nbsphinx converts them by shelling
out to the pandoc binary. pandoc is a system program, not a Python package,
so pip install -e ".[docs]" does not install it. Without it the build
stops at the first notebook with:
nbsphinx.PandocMissing: Pandoc wasn't found.
Install it with your system package manager, or into the build environment:
sudo apt-get install pandoc # Debian/Ubuntu (what CI uses)
brew install pandoc # macOS
conda install -c conda-forge pandoc # conda environments
Other platforms and the official installers are at https://pandoc.org/installing.html.
Install the docs toolchain#
pip install -e ".[docs]"
Build the HTML#
cd docs
make html
# open docs/_build/html/index.html
For a strict build that treats warnings (broken cross-references, import failures) as errors, the same check CI runs:
sphinx-build -W --keep-going -b html docs docs/_build/html
Doc tests#
Runnable snippets marked with the doctest directive are executed by the
doctest builder, and external links are checked by the linkcheck builder:
make -C docs doctest
make -C docs linkcheck
A minimal doctest, verifying the package imports and exposes a version string:
>>> import graintrace
>>> isinstance(graintrace.__version__, str)
True
Continuous integration#
.github/workflows/build_docs.yml runs the strict HTML build plus doctest
and linkcheck on every push and pull request to main and
documentation. linkcheck is informational and does not fail the job;
the strict build and doctest do.
Every run — any branch, any pull request — uploads the built HTML as a
downloadable docs-html artifact, so a change can be reviewed without
deploying. Only a push to main deploys, via GitHub’s own
actions/deploy-pages (OIDC, pages: write + id-token: write). There is
no gh-pages branch and pull requests get no live preview URL; download the
artifact instead.
Writing new pages#
API pages under
docs/api/are thinautomodulestubs; add one per new public module and list it indocs/api/api.rst.Tutorial pages under
docs/tutorials/are Jupyter notebooks, listed indocs/tutorials/tutorials.rst. They carry their code inline rather than including the matchingexamples/script; keep the two in step by hand.New prose pages must be reStructuredText.
myst_parseris not installed andsource_suffixis not set, so a.mdfile dropped intodocs/is silently ignored rather than reported as an error.Keep the prose plain and factual; let the code examples carry the detail.
Define every symbol you introduce, or point at Notation and conventions. Equations that a later paragraph refers to get a
:label:and are cited with:eq:.
Definition of done (adding or changing code)#
A new feature or code change is not complete until all five of these are done in the same change:
Tests pass. Add or extend tests under
tests/and keep the suite green:pytest,black --check graintrace tests, andpylint --rcfile=.pylintrc graintrace. Tests that need the external stack self-skip viapytest.importorskip/skipif.Docstrings updated. Every new or changed public class, method, and function has a docstring (Google or NumPy style). Document new constructor keyword arguments; they surface directly in the API reference.
Docs updated. Update the relevant tutorial under
docs/tutorials/, Configuration reference for new options, and add anautomodulepage underdocs/api/for a new public module. The strict build anddoctestmust pass (see above).CLAUDE.md updated. Update
.claude/CLAUDE.md(the working reference for the codebase) so it stays the source of truth.MCP updated. If the change is a workflow segment or adds/changes user-facing parameters, update the MCP tool in
graintrace/mcp/tools/, its recipe ingraintrace/mcp/recipes/, and the tool table ingraintrace/mcp/README.md. New external-tool dependencies must be reported bydependency_status.