Installation and CLI
|
This content was generated with the assistance of AI and should be verified against the official documentation of each tool before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
This page was written against Zensical 0.0.72 (published on 2026-10-23, still the latest release on PyPI) and checked on
2026-10-26. Zensical is a static site generator for Markdown documentation that is distributed as a Python package with a
Rust core inside the wheel, so installing it is a normal Python package installation. It needs Python 3.11 or newer. The
command line has only three commands: new creates a starter project, serve previews it and build writes the static
site. The examples were run in a scratch project on macOS with Python 3.13 and the official Docker image, using the
documentation of Pocket Units, the small units-conversion library with a C# and a Python implementation, as the subject.
Zensical is in alpha (the PyPI classifier is Development Status :: 3 - Alpha), and the project has announced a 0.1.0
release for 2026-11-05. Output formats and messages quoted below belong to 0.0.72 and may change.
Choosing an installation method
All four methods install the same program. The project documents pip and uv as the normal choices, conda-forge as a third-party channel, and Docker for previews and builds only.
| Method | Use it when | Caveat |
|---|---|---|
pip |
You want the simplest route and already have Python 3.11 or newer. |
Install inside a virtual environment so the version is well defined. |
uv |
The project is already managed with uv and you want Zensical recorded as a development dependency in |
Run it with |
conda-forge |
Your environment is managed with conda or Mamba. |
The package is built by the community, not by the Zensical team, and is not officially supported. Report problems to the conda-forge feedstock. |
Docker |
You do not want Python on the machine, or you build in a container. |
The image is for previews and builds, not for hosting the site. |
pip
Create a virtual environment first, then install the package into it.
python3 -m venv .venv
source .venv/bin/activate
pip install zensical==0.0.72
zensical --version
On Windows the activation command is .venv\Scripts\activate, and the interpreter may be called python or py -3
instead of python3.
Source: Zensical docs: Get started
Output of the last command in the scratch environment:
0.0.72
The pin is optional. Without it, pip install zensical installs the latest release, which is what the generated GitHub
workflow does. Upgrade an existing environment with pip install --upgrade zensical, and after an upgrade run
zensical build --clean once (see below).
uv
uv keeps the dependency in pyproject.toml and runs commands in the project environment.
uv init
uv add --dev zensical
uv run zensical --version
Source: Zensical docs: Get started
Always start Zensical through uv run (or activate the project’s .venv), otherwise another installed version may be
picked up. The scratch environment of this page was created with uv, but the exact uv init run was not repeated for
this page, so its output is not shown.
conda-forge
conda create -n zensical python=3.14
conda activate zensical
conda install -c conda-forge zensical
Source: Zensical docs: Get started
This example was not executed here, because no conda installation was available. Check zensical --version after installing to see which release you got.
Docker
The project publishes the image zensical/zensical. The image’s entry point is the zensical command, its working
directory is /docs, and its default arguments are serve --dev-addr=0.0.0.0:8000. Mount the project directory at
/docs and pass a command to override the default.
docker pull zensical/zensical
docker run --rm zensical/zensical --version
docker run --rm -v "$PWD":/docs zensical/zensical build --clean
Source: Zensical docs: Get started
Output of the three commands (the image pull messages are omitted):
0.0.72
Build started
No issues found
Build finished in 0.27s
The official page only names the image and refers to Docker Hub for usage; the mount and the command above are the
standard Docker way of using an image with this entry point, and they produced the site directory in the project. To
preview, run the image with its default command and publish the port, for example
docker run --rm -p 8000:8000 -v "$PWD":/docs zensical/zensical. The preview command was not run in the container here,
only the build.
The three commands
The figure shows the usual order: create the project once, preview while writing, build for publishing.
zensical --help lists the commands, and zensical <command> --help lists the options of each one.
Usage: zensical [OPTIONS] COMMAND [ARGS]...
Zensical - A modern static site generator.
Options:
--version Show the version and exit.
--help Show this message and exit.
Commands:
build Build a project.
new Create a new template project in the current or given directory.
serve Build and serve a project.
zensical new
zensical new [DIRECTORY] creates a starter project in the given directory, or in the current one. The directory must
exist. Run on an empty directory it generated four files:
.github/workflows/docs.yml
docs/index.md
docs/markdown.md
zensical.toml
| File | Purpose |
|---|---|
|
The project configuration (118 lines in 0.0.72, mostly commented-out options). It sets |
|
A "Get started" page that begins with a front matter |
|
A short Markdown reference page ("Markdown in 5min") that doubles as a feature demonstration. |
|
A GitHub Actions workflow that builds the site and deploys it to GitHub Pages. |
The generated zensical.toml starts like this (comments removed):
[project]
site_url = "https://www.example.com/"
site_name = "Documentation"
nav = [
{ "Get started" = "index.md" },
{ "Markdown in 5min" = "markdown.md" },
]
[project.theme]
language = "en"
Replace the placeholder site_url with the real address of the published site before publishing.
The command is safe to repeat. If zensical.toml already exists it stops with an error and exit code 1, and if the target
is not a directory it fails with a usage error and exit code 2. Other template files that already exist are not
overwritten, and the command still succeeds.
Error: /path/to/demo/zensical.toml already exists.
Error: Invalid value for '[DIRECTORY]': Directory 'afile' is a file.
The generated GitHub workflow
.github/workflows/docs.yml is the template that the publishing page of the official documentation describes. It runs
on every push to master or main.
name: Documentation
on:
push:
branches:
- master
- main
permissions:
contents: read
pages: write
id-token: write
jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- uses: actions/configure-pages@v6
- uses: actions/checkout@v7
- uses: actions/setup-python@v6
with:
python-version: 3.x
- run: pip install zensical
- run: zensical build --clean
- uses: actions/upload-pages-artifact@v5
with:
path: site
- uses: actions/deploy-pages@v5
id: deployment
Source: Zensical docs: Publish your site
This is the file written by zensical new 0.0.72, verbatim. The permissions allow the workflow to publish to Pages, the
site path matches the default site_dir, and --clean makes every CI build start without cached state. The workflow
was not run on GitHub here. It requires the repository’s Pages source to be set to GitHub Actions; the
Validation and Publishing page covers publishing in
detail. The official documentation advises against caching in CI.
zensical serve
zensical serve builds the project and starts a local web server that rebuilds and reloads the browser page when source
files change.
| Option | Short | Meaning |
|---|---|---|
|
|
Path to the configuration file. |
|
|
Address and port to listen on. The default is |
|
|
Open the preview in the default browser. |
|
|
Accepted, but the help text says strict mode is currently unsupported for |
Source: Zensical docs: Preview your site
Pages listed in draft_docs are included in the preview with a draft notice, while pages matched by exclude_docs are
not. The server is for previewing only and is not meant for production.
Started with a custom address, the scratch project printed:
zensical serve -a 127.0.0.1:8765
Serving /path/to/demo/site on http://127.0.0.1:8765
Build started
No issues found
A request to the address returned HTTP/1.1 200 OK. Running zensical serve -s in a project with no problems started
the server normally, as expected from the help text; its behaviour with broken links was not tested. The serve process
keeps running until it is interrupted with Ctrl+C.
zensical build
zensical build writes the static site into site_dir, which is site by default.
| Option | Short | Meaning |
|---|---|---|
|
|
Path to the configuration file. |
|
|
Clear the build cache before building. |
|
|
Abort the build when it produces warnings. |
Source: Zensical docs: Build your site
Pages in exclude_docs and draft_docs are left out of the site. A first build of the starter project printed the
following and created site/ with index.html, 404.html, markdown/index.html, search.json, sitemap.xml and an
assets directory; a .cache directory next to zensical.toml holds the build state.
Build started
No issues found
Build finished in 0.29s
Without a configuration file in the current directory the command fails:
Error: No config file found in the current folder.
It looks for zensical.toml and also accepts a mkdocs.yml (a directory containing only mkdocs.yml with
site_name: T built successfully). Use -f to point at a file elsewhere.
--clean
Zensical caches build state between runs so repeated builds are fast. Use --clean when the output looks wrong,
especially right after upgrading Zensical. The official documentation says clean builds should become unnecessary as
stale-state problems get fixed, and asks for an issue report if a problem survives a clean build. CI should always pass it,
as the generated workflow does.
--strict
Warnings are normally printed and the build still finishes with exit code 0. With --strict the build aborts when it
finds any. To try it, a page docs/broken.md with a link to a missing page and a link to a missing anchor was added to the
starter project:
# Broken
[x](missing.md) and [y](index.md#nope)
Without --strict the build reported both problems (the output also contains terminal colour codes) and finished
successfully:
Warning: page does not exist
╭─[ broken.md:3:5 ]
3 │ [x](missing.md) and [y](index.md#nope)
│ ──┬──
│ ╰──── page does not exist
Warning: anchor does not exist
╭─[ broken.md:3:34 ]
3 │ [x](missing.md) and [y](index.md#nope)
│ ──┬─
│ ╰─── anchor does not exist
2 issues found
Build finished in 0.27s
The report above is shortened. With zensical build --strict the same warnings were printed and
the command ended with a Python traceback whose last line is the message below, and exit code 1. CI systems treat that as
a failed job.
RuntimeError: Aborted because --strict flag is set
Which problems count as warnings is configured in the [project.validation] table, described on the
Validation and Publishing page.
Pitfalls
-
The command is
zensical, notmkdocs. There is nogh-deployorget-depscommand; deployment is done by a workflow such as the generated one, and dependencies are declared inpyproject.toml. -
--theme,--use-directory-urlsand--site-dirof MkDocs are not accepted; the equivalents are settings in the configuration file (theme.variant,use_directory_urls,site_dir). -
Running
zensicalthrough a global installation instead of the project environment is the usual reason for "wrong version" surprises; preferuv run zensicalor an activated virtual environment. -
The preview server is bound to
localhostby default. Inside Docker it must listen on0.0.0.0, which the image’s default arguments already do; publish the port with-p. -
The default
.cachedirectory and thesitedirectory are build output. Add both to.gitignore.