Skip to content

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 --strict over the twenty public names of nanopnp.__all__, with docstring_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.py does import it, to render the case-file, CLI and exit-code references, which is why the docs group 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 --strict does not count it.
  • Setting validation.nav.omitted_files, validation.links.not_found, anchors, absolute_links and unrecognized_links to warn makes --strict fail on each of them. The MkDocs 1.6 defaults leave several at info, which strict mode ignores.
  • A page copied from the bundle keeps its YAML header, which MkDocs reads as page metadata (title names the page). not_in_nav takes a directory, so the concept pages of the bundle need no navigation entry beyond its index, and the footnotes extension renders a [^id] source label.
  • An attr_list heading 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 _1 suffix of a repeat.