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 pyproject.toml.

Run it with uv run. uv’s symlink link mode is not supported.

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.

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

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

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

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

flowchart LR N["zensical new"] --> F["zensical.toml and docs/"] F --> S["zensical serve: preview with reload"] F --> B["zensical build: write site/"] B --> D["publish site/"]

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

zensical.toml

The project configuration (118 lines in 0.0.72, mostly commented-out options). It sets site_url, site_name, an explicit nav with the two pages, a [project.theme] table with language = "en", a list of enabled theme features, a three-entry [[project.theme.palette]] list and a [project.markdown_extensions] table. See Configuration.

docs/index.md

A "Get started" page that begins with a front matter icon and lists the three commands.

docs/markdown.md

A short Markdown reference page ("Markdown in 5min") that doubles as a feature demonstration.

.github/workflows/docs.yml

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

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

--config-file PATH

-f

Path to the configuration file.

--dev-addr <IP:PORT>

-a

Address and port to listen on. The default is localhost:8000.

--open

-o

Open the preview in the default browser.

--strict

-s

Accepted, but the help text says strict mode is currently unsupported for serve.

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

--config-file PATH

-f

Path to the configuration file.

--clean

-c

Clear the build cache before building.

--strict

-s

Abort the build when it produces warnings.

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, not mkdocs. There is no gh-deploy or get-deps command; deployment is done by a workflow such as the generated one, and dependencies are declared in pyproject.toml.

  • --theme, --use-directory-urls and --site-dir of MkDocs are not accepted; the equivalents are settings in the configuration file (theme.variant, use_directory_urls, site_dir).

  • Running zensical through a global installation instead of the project environment is the usual reason for "wrong version" surprises; prefer uv run zensical or an activated virtual environment.

  • The preview server is bound to localhost by default. Inside Docker it must listen on 0.0.0.0, which the image’s default arguments already do; publish the port with -p.

  • The default .cache directory and the site directory are build output. Add both to .gitignore.