Migrate documentation build from MkDocs to Zensical - #8848
Merged
Conversation
The override targeted `{% block disqus %}`, which no longer exists in
mkdocs-material's base.html. Jinja never invokes an undefined block, so
the script tag never reached the rendered pages and no comments widget
has been displayed on megalinter.io for some time.
Verified absent from the served HTML of /latest/, /latest/quick-start/,
/latest/config-file/ and /beta/.
Removing the dead code; a working comment system is added separately.
`theme.font.text` was set to "Satoshi, sans-serif", which the theme emits as `--md-text-font: "Satoshi, sans-serif"` — a single quoted family name that matches nothing. The theme also requests the family from Google Fonts, which does not host Satoshi (it is an Indian Type Foundry face distributed via Fontshare), so the site has been falling back to the browser default rather than rendering in Satoshi. Ship the four weights in use (400/500/700/900) under docs/assets/fonts, declare them with @font-face, and set --md-text-font to a single family name. `font: false` stops the theme requesting a family Google Fonts cannot serve.
Replace mkdocs + mkdocs-material with zensical, which reads the existing mkdocs.yml unchanged. Versioning keeps working through the Zensical-compatible mike fork, pinned to a commit SHA. - Swap mkdocs/mkdocs-material/mkdocs-glightbox for zensical in requirements and in the hatch docs env - Point mike at squidfunk/mike (Zensical-compatible fork), SHA-pinned - Use zensical.extensions.emoji for the pymdownx.emoji namespace - Drop the search_index.json prettify step: Zensical emits site/search.json
- Replace the purple palette with the OX Security colors: navy #061C37 / #07224A, indigo #3F11F7, lime #C6F43C, off-white #F7F7FF - Add a light/dark palette toggle; dark mode uses a navy slate scheme and the lime accent, which stays readable on navy - Scope the color variables per scheme, so the light overrides no longer win over the slate ones by cascade order - Title the home page "Home" again through front matter: the doc engine derives page titles from the file name when the page has no h1 - Drop the h1[content~=Home] rule: h1 has no content attribute, so it never matched
- Rename the workflow to "Check documentation generation" and its file to test-docs.yml (it was not a required status check) - Also trigger it on docs/** and on the docs requirements file, so a broken page is caught before it reaches the deploy workflow - Build with zensical instead of mkdocs - Drop the two dead "mkdocs gh-deploy" comments from the deploy workflows
Add a custom manager that reads "# renovate: datasource=git-refs depName=<url> branch=<branch>" annotations above "pkg @ git+<url>@<sha>" requirements, so the SHA-pinned Zensical-compatible mike fork gets update PRs like any other pin.
Replace the mkdocs-material references in CLAUDE.md, the .claude rules, agents and skills with Zensical, document the docs commands and the mike fork, add zensical and Fontshare to the cspell dictionary, and add the CHANGELOG entries.
Comments are rendered by overriding the theme comments partial, so they appear at the bottom of every page and follow the light/dark palette toggle. Threads are GitHub Discussions of oxsecurity/megalinter, created lazily in the Announcements category and matched on the page path. A page can opt out with "comments: false" in its front matter. Requires the Giscus GitHub App to be installed on oxsecurity/megalinter.
nvuillam
requested review from
Kurt-von-Laven,
bdovaz and
echoix
as code owners
August 31, 2026 16:10
Collaborator
|
Nice work |
Contributor
✅
|
The CHANGELOG entry naming the removed template block was the only blocking cspell error.
markdownlint --fix strips the significant trailing space from the error-format regexes in skills/megalinter-fix/linters/*.md (MD038). That corrupted the documented regex and left the tree dirty, so the auto-fix commit step aborted its checkout on every pull request. Those files are generated and already excluded from cspell and lychee.
The good and bad fixtures were identical except for a basic-auth credential on the-internet.herokuapp.com: trufflehog reported the bad one only after authenticating against that site, so the tests failed whenever the runner could not reach it, as happened on this branch. The fixtures now differ by what is detected rather than by what verifies, and pre_test drops --only-verified, which stays the production default. The .wireit poison gains a private key so the excluded-directories forwarding guard fires instead of being vacuous. Validated offline with trufflehog 3.97.0: good 0 findings, good with .wireit kept 1, bad 4.
3 tasks
nvuillam
added a commit
that referenced
this pull request
Sep 5, 2026
build.sh builds the documentation site with `zensical build` since the MkDocs to Zensical migration (#8848), but entrypoint.sh still installed the MkDocs stack (mike, mkdocs-material, mkdocs-glightbox) before running it. The Auto-Update Linters job has therefore failed with `build.sh: line 20: zensical: command not found` (exit code 127) on every run since 2026-09-04, after the linter versions and the docs had already been regenerated, so no update pull request was ever created. Swap the three unused MkDocs packages for zensical, keeping the list in sync with .config/python/dev/requirements.txt as its header asks.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Migrates the documentation build from
mkdocs+mkdocs-materialto Zensical, squidfunk's Material successor, keeping every capability of the current site — versioning included.mkdocs.ymlstays the configuration file (Zensical reads it indefinitely), so.automation/build.py's marker-comment nav generation is untouched.Commits
fix(docs){% block disqus %}overridefix(docs)feat(docs)build.sh, hatch scripts, mike forkfeat(docs)ci(docs)test-mkdocs.yml→test-docs.yml, broadened trigger,zensical buildchore(deps)docsfeat(docs)Versioning is preserved
Zensical has no native versioning; it documents a Zensical-compatible fork of
mike, installed from GitHub and pinned to a commit SHA, watched by a new Renovate custom manager.mike deploy 9was rehearsed on a throwaway local clone (nothing pushed):versions.jsoncame back intact, all 40 existing versions preserved9/"version":{"default":"latest","provider":"mike"}config the live site uses, andjavascripts/version-mike.jsstill loadsThree pre-existing bugs fixed along the way
All three predate this work and are independent of Zensical:
docs/overrides/main.htmloverrode{% block disqus %}, a block the theme does not define, so Jinja silently never invoked it. Verified absent from the live site.theme.font.text: Satoshi, sans-serifemitted--md-text-font: "Satoshi, sans-serif"— one quoted family name matching nothing — and the theme requested it from Google Fonts, which does not host Satoshi. Now self-hosted fromdocs/assets/fonts/.h1[content~=Home] { display: none; }never matched:h1has nocontentattribute. Rule removed.Regression checks against a 403-page mkdocs baseline
<img>tagsmdx_truly_sane_lists)--8<--)Judgement calls worth reviewing
--strictin CI. It was in the plan, butmainalready emits 10 broken-link warnings (missinglicenses/spectral.md,licenses/tofu-fmt.md,../CLAUDE.md…), so the new check would have been red on day one. Zensical also prints "Strict mode is currently unsupported" for the flag today. Fix the 10 links, then turn it on.comments: falsein its front matter; narrowing this to hand-written pages is a one-line change in the partial.unpkg.com/glightbox@3instead of being self-hosted — that is Zensical's built-in behaviour, and it adds a third-party CDN at runtime.<h1>source changed. Zensical derivespage.titlefrom front matter where mkdocs used the nav entry, so 57 descriptor pages now showspectral configuration in MegaLinterinstead ofspectral. Cosmetic, and consistent with the<title>tag. The home page rendered as "Index" and is fixed withtitle: Homefront matter, generated bybuild.py.Rollback
gh-pagestip before this change:c3dfe2d0aa84f03a42346ae5d3d7f5f101017112Restore with
git push --force-with-lease origin c3dfe2d0aa84f03a42346ae5d3d7f5f101017112:gh-pages.Merging fires the
betadeploy only;latestand the version aliases stay untouched until the next release, which makes that window a natural soak period.Requires
The Giscus GitHub App installed on
oxsecurity/megalinter— already done and verified.