Skip to content

docs: replace MkDocs with Zensical#3073

Open
Kludex wants to merge 2 commits into
mainfrom
claude/replace-mkdocs-zensical-5m0ltl
Open

docs: replace MkDocs with Zensical#3073
Kludex wants to merge 2 commits into
mainfrom
claude/replace-mkdocs-zensical-5m0ltl

Conversation

@Kludex

@Kludex Kludex commented Jul 7, 2026

Copy link
Copy Markdown
Member

Migrates the v2 docs build from MkDocs Material to Zensical, the Material team's successor — the same move Starlette and uvicorn made.

Why this isn't a drop-in swap

Starlette and uvicorn could just swap the dependency because their docs only use search + mkdocstrings, both of which Zensical re-implements natively. This SDK's docs are heavier. Verified against Zensical 0.0.47 (source + real builds):

Feature this repo uses Zensical
mkdocstrings, search, glightbox, emoji, social ✅ native
mkdocs-gen-files (the whole api/ tree) ❌ not run
mkdocs-literate-nav (the api/ nav) ❌ not run
hooks: (llms_txt.py) ❌ no MkDocs-hook runtime
YAML tags !relative, !ENV, !!python/name: ❌ parse error

Zensical deliberately runs no arbitrary MkDocs plugins or hooks — it natively re-implements a fixed set. Its public module/extension API is not shipped yet. So the three plugin/hook-based pieces are reimplemented as standalone build steps around zensical build (the "sidecar" pattern Zensical itself recommends).

What changed

  • API referencemkdocs-gen-files + mkdocs-literate-nav become scripts/docs/gen_ref_pages.py (writes the 109 docs/api/*.md mkdocstrings stubs) and scripts/docs/build_config.py (splices the nested API nav into a generated mkdocs.gen.yml, since Zensical has no literate-nav). Zensical renders the stubs via its native mkdocstrings support.
  • llms.txt — the former MkDocs hook becomes scripts/docs/llms_txt.py, a post-build step over the source tree (mkdocs.yml + docs/) with no dependency on build internals, so it survives Zensical upgrades.
  • mkdocs.yml stays the source config, with the MkDocs-only YAML tags translated to the string forms Zensical understands and the emoji functions pointed at zensical.extensions.emoji. The generators moved out of docs/ (Zensical publishes everything under docs_dir) into scripts/docs/.
  • scripts/build-docs.sh now auto-detects the toolchain per worktree so the combined v1 (MkDocs) + v2 (Zensical) build stays correct; adds scripts/serve-docs.sh for local preview.
  • pyproject.toml drops mkdocs, mkdocs-material[imaging] and the gen-files/glightbox/literate-nav plugins for zensical. mkdocstrings is floored at 1.0.4 / mkdocstrings-python at 2.0.5: Zensical's compatibility layer targets that API, and the older line renders API pages with an unregistered-autorefs error.
  • CIshared.yml, deploy-docs.yml and docs-preview.yml updated to the new flow.

Verification

Clean zensical build --strict: no issues, 159 pages, 109 API pages fully rendered, nested API nav, --8<-- snippet includes, tabs, admonitions, emoji, the mcp logo, and both llms.txt / llms-full.txt produced correctly (no build scripts leak into the site). ruff clean; 799 docs tests pass.

Follow-up (out of scope for this branch)

The combined build serves v1 (MkDocs) + v2 (Zensical). This branch's build-docs.sh auto-detects the tool per worktree, so main-triggered deploys are correct. A v1.x-triggered deploy still runs v1.x's old build-docs.sh, which would try to build main with MkDocs and fail — that needs the auto-detecting build-docs.sh backported to v1.x.

🤖 Generated with Claude Code

https://claude.ai/code/session_01CTkPwxyKkLTnqZdeiCMCzK


Generated by Claude Code

Migrate the v2 docs build from MkDocs Material to Zensical, the Material
team's successor (as Starlette and uvicorn have done). Zensical natively
re-implements search, glightbox and mkdocstrings, but — unlike MkDocs — runs
no arbitrary plugins or hooks. This SDK's docs relied on three of those, so
they are reimplemented as standalone build steps around `zensical build`:

- API reference: `mkdocs-gen-files` + `mkdocs-literate-nav` become
  `scripts/docs/gen_ref_pages.py` (writes the `docs/api/` mkdocstrings stubs)
  and `scripts/docs/build_config.py` (splices the nested API nav into a
  generated `mkdocs.gen.yml`, since Zensical has no literate-nav).
- llms.txt: the former MkDocs hook becomes `scripts/docs/llms_txt.py`, a
  post-build step over the source tree, with no dependency on build internals.

`mkdocs.yml` stays the source config, with the MkDocs-only YAML tags
(`!relative`, `!ENV`, `!!python/name:`) translated to the string forms
Zensical understands and the emoji functions pointed at
`zensical.extensions.emoji`. The generators moved out of `docs/` (Zensical
publishes everything under docs_dir) into `scripts/docs/`, and
`scripts/build-docs.sh` now picks the toolchain per worktree so the combined
v1 (MkDocs) + v2 (Zensical) build stays correct. Adds `scripts/serve-docs.sh`
for local preview.

The docs dependency group drops mkdocs, mkdocs-material[imaging] and the
gen-files/glightbox/literate-nav plugins for `zensical`. mkdocstrings is
floored at 1.0.4 / mkdocstrings-python 2.0.5: Zensical's compatibility layer
targets that API, and the older line renders API pages with an
unregistered-autorefs error.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CTkPwxyKkLTnqZdeiCMCzK
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

📚 Documentation preview

❌ Preview build failed for 7c7b6f6workflow logs.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 15 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread scripts/serve-docs.sh Outdated

Kludex commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

Note for reviewers: the red "Docs Preview" check is expected on this PR

The Docs Preview / build check fails here, but it's a pull_request_target artifact, not a problem with the migration:

  • docs-preview.yml runs on pull_request_target, so GitHub executes the workflow file from main, not from this branch. main's version still runs uv run mkdocs build, which aborts with Unrecognised theme name: 'material' because this PR removes mkdocs-material.
  • The updated docs-preview.yml (Zensical flow) lives on this branch but won't take effect until it's merged into main. So this check can only go green after merge — there's nothing fixable on the branch.
  • The auto-posted "❌ Preview build failed" comment above is the same artifact and can be ignored.

The authoritative signal is checks / docs, which runs on pull_request (this branch's workflow) and builds the site with the new flow — build_config.pyzensical build --strictllms_txt.py. That check is ✅ green, alongside the full test matrix, pre-commit, readme-snippets, CodeQL and zizmor.

One follow-up called out in the PR description: the combined build serves v1 (MkDocs) + v2 (Zensical), and this branch's scripts/build-docs.sh auto-detects the toolchain per worktree — but a v1.x-triggered deploy still uses v1.x's old build-docs.sh, so that script should be backported to v1.x.


Generated by Claude Code

The wrapper forwards `"$@"` straight to `zensical serve`, so extra args are
passed directly; the `--` in the usage example would be forwarded literally.
Show args as direct forwarding instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CTkPwxyKkLTnqZdeiCMCzK
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants