13. Documentation tooling: MkDocs, Material and Zensical
13. Documentation tooling: MkDocs, Material and Zensical¶
Read 23 September 2026 from the publishers' own announcements. Not tested here; the WP16 implementation confirms the versions it pins against current releases (Context7) before locking.
- Material for MkDocs has been in maintenance mode since 5 November 2025. Its maintainers fix
critical bugs and security issues for at least twelve months from then, and add no features.
Feature work moved to Zensical, an MIT-licensed successor from the same team, which reads an
existing
mkdocs.yml. → squidfunk.github.io/mkdocs-material/blog - MkDocs 2.0 is not compatible with Material. A Material site therefore pins
mkdocs<2. → What MkDocs 2.0 means for your documentation projects - Zensical renders mkdocstrings API pages (since its 0.0.11 release), but cross-references and backlinks between pages are not yet supported. → zensical/zensical#237, release 0.0.11
What follows from those three facts: a Material site today pins mkdocs<2. It stays portable to
Zensical only if its mkdocs.yml avoids what Zensical does not read, such as MkDocs hooks: and
plugins it has no shim for. A page generated by a separate step before the build is portable, and
one generated by a build hook is not.
What the build actually did, 23 September 2026. Locked by WP16 at MkDocs 1.6.1, mkdocs-material 9.7.7, mkdocstrings 1.0.6 and mkdocstrings-python 2.0.9 (griffe 2.3.0), on Python 3.12:
mkdocs build --strictover the twenty public names ofnanopnp.__all__, withdocstring_style: numpy, emits no warning. The package's NumPy-style docstrings parse as they stand, and their Sphinx roles (:func:`…`,:class:`…`) render as literal text rather than failing the build. So the strict build gates links and navigation, not docstring prose.- mkdocstrings-python reads the source statically through griffe. It never imports
nanopnp, so the API page builds without NGSolve.docs/scripts/generate.pydoes import it, to render the case-file, CLI and exit-code references, which is why thedocsgroup is synced on top of the project and not in place of it. - Material 9.7 prints a boxed "MkDocs 2.0" warning to standard error on every build. It is not a
MkDocs log record, so
--strictdoes not count it. - Setting
validation.nav.omitted_files,validation.links.not_found,anchors,absolute_linksandunrecognized_linkstowarnmakes--strictfail on each of them. The MkDocs 1.6 defaults leave several atinfo, which strict mode ignores. - A page copied from the bundle keeps its YAML header, which MkDocs reads as page metadata (
titlenames the page).not_in_navtakes a directory, so the concept pages of the bundle need no navigation entry beyond its index, and thefootnotesextension renders a[^id]source label. - An
attr_listheading id may begin with a digit, and the table-of-contents slug of all 241 headings of the bundle was checked against the slug the bundle checker computed (since removed, REV-117), including the_1suffix of a repeat.