Editing and building this documentation
This documentation is written using markdown, with special extensions that are supported by zensical. Zensical is the successor to mkdocs and mkdocs-material. We use zensical rather than mkdocs/mkdocs2 as mkdocs is deprecated and mkdocs2 breaks a lot of backwards-compatibility.
Installing zensical
You need zensical to build the documentation and use all its features. Without zensical, mhttpd can still show most of it, with a simpler built-in renderer. See Serve the documentation through mhttpd.
As well as regular zensical, we have custom code for generating API documentation from the C++/python/web source code. This code is the mkdocstrings-midas package in $MIDASSYS/doc/mkdocs/mkdocstrings-midas. Installing it also installs zensical and the other packages needed to build the documentation.
The package isn't part of the midas Python package, because only people who build the documentation need it. Install it as editable (-e), so that changes to its code are used without reinstalling it.
pip install -e "$MIDASSYS/doc/mkdocs/mkdocstrings-midas"
Install python and uv with Homebrew:
brew install python uv
Then install Zensical as an isolated uv tool, together with mkdocstrings-midas, which brings in the other plugins. The tool has its own environment, so it also needs the midas Python package, which the JSON-RPC API docs use:
uv tool install \
--no-managed-python \
--with-editable "$MIDASSYS/python" \
--with-editable "$MIDASSYS/doc/mkdocs/mkdocstrings-midas" \
zensical
Verify the installation:
zensical --version
Install the system Python and the tools required by the official uv standalone installer, then install uv:
sudo apt update
sudo apt install --yes ca-certificates curl python3
curl -LsSf https://astral.sh/uv/install.sh | sh
Start a new shell so that uv is on PATH, or update the current shell:
export PATH="$HOME/.local/bin:$PATH"
Install Zensical and its plugins using Debian's system Python:
uv tool install \
--python /usr/bin/python3 \
--no-managed-python \
--with-editable "$MIDASSYS/python" \
--with-editable "$MIDASSYS/doc/mkdocs/mkdocstrings-midas" \
zensical
Verify the installation:
zensical --version
zensical version requirements
The required versions of zensical and the other packages are specified in $MIDASSYS/doc/mkdocs/mkdocstrings-midas/pyproject.toml.
If you update midas, the required versions may change. You can automatically upgrade the required packages by re-running the same install command. It only upgrades the packages whose installed version is too old.
If you want to forcefully upgrade zensical and the other packages to their latest versions, run:
pip install -U --upgrade-strategy eager -e "$MIDASSYS/doc/mkdocs/mkdocstrings-midas"
uv tool upgrade zensical
If you get errors when trying to generate the documentation, make sure to run the install again first. An example error that may be encountered if you have bad dependencies is: Highlight.__init__() missing 1 required positional argument: 'md'.
Building the documentation
You can choose to build a version that is served via a webserver (written to $MIDASSYS/doc/mkdocs/html_web), or one that is completely static (written to $MIDASSYS/doc/mkdocs/html_local).
Serve via a web server
To build docs and serve via a webserver:
cd $MIDASSYS/doc/mkdocs
zensical build -c -f web.yml && zensical serve -f web.yml
Navigate to http://localhost:8000/zensical/
Note - build then serve
You must do the build -c step (not just the serve step) for autorefs to be found correctly.
Build a static site
The static site does not require a web server to be running, but misses a couple of features (notably instant previews and links to edit the page).
To build docs and generate a completely static site:
cd $MIDASSYS/doc/mkdocs
zensical build -c -f local.yml
Open $MIDASSYS/doc/mkdocs/html_local/index.html in your browser
Build with CMake
You can also build the static site as part of the normal MIDAS build. First
install Zensical and its plugins, then enable the
MIDAS_BUILD_DOCS option, which is off by default:
cd "$MIDASSYS"
cmake -S . -B build -DMIDAS_BUILD_DOCS=ON
cmake --build build
The documentation step runs after the other default build targets finish,
including during parallel builds. To build only the documentation, use
cmake --build build --target docs.
Alternatively, build the documentation independently of the MIDAS programs:
cd "$MIDASSYS"
cmake -S doc/mkdocs -B build-docs
cmake --build build-docs
Both methods generate $MIDASSYS/doc/mkdocs/html_local/index.html and set
MIDASSYS to the checkout being built for the API documentation handlers.
If Zensical is missing from PATH, the documentation step prints a short notice
and skips building the HTML. You can select another installation by adding
-DZENSICAL_EXECUTABLE=/path/to/zensical to the CMake configuration command.
Every build calculates a SHA-256 fingerprint of all .md filenames and contents
under doc/mkdocs/md/. Zensical runs on the first build, when that fingerprint
changes, or when the saved fingerprint or html_local/index.html is missing.
The fingerprint is saved in html_local/.midas-docs-state only after a
successful build; failed builds are retried on the next build.
Local Markdown edits, additions, deletions and renames trigger a rebuild without
requiring a commit. Git revisions and file timestamps are not checked, so a
git pull that leaves the Markdown unchanged does not trigger a rebuild.
Changes to other inputs, such as configuration, images, API source code or
installed tools, require a forced rebuild:
cmake --build build-docs --target docs-force
For the main MIDAS build, replace build-docs with build. The manual Zensical
commands above remain available, but do not update the saved CMake fingerprint.
Serve the documentation through mhttpd
The Documentation page of the web interface shows this documentation inside mhttpd, so that it matches the installed version of midas. Open it at ?cmd=Documentation (or /docs), or with the Documentation menu entry, which is hidden by default. To open a given page, add its path, e.g. ?cmd=Documentation&path=reference/reference/odb_keys.md.
mhttpd looks for the documentation in doc/mkdocs below three places, in this order: its current directory, the experiment directory and $MIDASSYS. How the pages are shown depends on whether the static site has been built:
- Static site built (
html_local/index.htmlexists): mhttpd serves the pages fromhtml_local, and the Documentation page shows them in a frame. They look and work the same as when you open the static site from disk. Build it as described in Build a static site - No static site: mhttpd uses a custom Markdown-to-HTML renderer. This works without zensical, but has limitations (see below). mhttpd serves the Markdown files from
md, and the Documentation page renders them in the browser withresources/markdown.js. The navigation is read from thenavincommon.yml
Limitations of the built-in renderer
- Only some of the Markdown extensions are supported. Tables, admonitions, content tabs and syntax highlighting work, but most icons, tooltips and image placement don't
- Pages that are generated from the source code (with
:::directives) are only shown if a built site (html_weborhtml_local) exists - Search (
resources/docs_features.js) only works if a built site'ssearch.jsonexists
So the Documentation page always works, but it looks best if you build the static site after updating midas:
cd $MIDASSYS/doc/mkdocs
zensical build -c -f local.yml
The files mhttpd serves for the documentation are:
| URL | File |
|---|---|
?cmd=Documentation, /docs, /docs.html |
The viewer page, resources/docs.html |
/docs/<page>.md |
html_local/<page>.html if the static site is built, otherwise md/<page>.md |
/docs/navigation.yml |
common.yml |
/docs/search.json |
search.json from html_local, or else html_web |
/docs/generated/<page>.md |
html_web/<page>/index.html, or else html_local/<page>.html |
Versioned documentation on midas.triumf.ca
https://midas.triumf.ca/docs/ has the documentation for the develop branch and for each release of midas (but only releases since the new documentation was created). A version menu at the top of each page switches between them. Only the docs server needs to build this. Everyone else builds a single version, as described above.
The versioned site is built with mike (a fork of mike for zensical), using two files in doc/mkdocs:
| File | Purpose |
|---|---|
versioned.yml |
Settings for the versioned site. It inherits web.yml, and adds the version menu |
build_versioned_docs.sh |
Builds one version, and copies the whole site to the web server's directory |
build_versioned_docs.sh develop # update the develop docs
build_versioned_docs.sh midas-2026-08-a # add a release, and make it the latest
On the docs server, cron updates the develop docs every night. Releases are added by hand.
How it works
- Its own clone of midas: the script checks out each version in a separate clone (
~/midas-docs/midasby default), so it doesn't touch your working copy. It also compiles midas there, because the JSON-RPC API docs read the schema from the midas library. - Package versions: each version is built in a temporary uv environment, with the package versions that its own
mkdocstrings-midasrequires. The server only needs git, cmake, uv and rsync. - Storage: mike keeps all the built versions in the
built-docsbranch of the clone. The script pushes this branch to the midas-versioned-docs repository as a backup, and copies it to the web server's directory (~/midas-docs/htmlby default). A new clone gets the branch back from the backup, so the old releases don't need rebuilding. - Version names: a release is named without
midas-(e.g.2026-08-a), so that mike sorts it as a release. The newest release also has the aliaslatest, which the menu shows as "(latest release)". The site root goes todevelop. - Older releases: a release can only be built if it includes
versioned.yml, so releases from before it was added aren't on the site.
The settings (such as the directories and the backup repository) are described in the comments at the top of build_versioned_docs.sh.
How this documentation is organised
The documentation is organised by feature, not by audience. The audience of each page is shown by its tags (Operator, Admin, Developer, Reference, API, Internals).
Top-level sections
| Section | Contents |
|---|---|
| Getting started | An introduction to midas, a tour for operators, installation, and setting up a first experiment |
| Features | One folder (or page) per midas subsystem |
| Reference | Facts you look up: programs and options, ODB keys, web pages, data types, limits and drivers. Also holds Internals: how midas works inside, and how to work on midas itself |
| API | The complete C++, Python, JavaScript and JSON-RPC APIs, much of it generated from the source code |
| About | Release notes, history and community links |
Features, Reference, API and each feature folder start with an index.md, which the section header in the navigation links to. Getting started has no index.md: its first page is What is midas.
Pages within a feature
Each feature uses only the pages it needs from this list, in this order:
| File | Title | Contains |
|---|---|---|
index.md |
<Feature>: overview |
Concepts plus day-to-day use through the web pages, odbedit and command-line tools |
configuring.md |
<Feature>: configuring |
ODB settings, setup, deployment, and troubleshooting or recovery |
programming.md |
<Feature>: programming |
C++, Python and JavaScript code, using content tabs for the languages |
<topic>.md |
<Feature>: <topic> |
Optional pages for large features, e.g. a sub-system (MSCB) or a framework (manalyzer) |
Small features are a single page. Page titles always include the feature name, so that search results are easy to tell apart. The page's H1 matches its title. In the nav of common.yml, the label is the title without its <Feature>: prefix (e.g. Overview for "ODB: overview"), because the feature's name is already shown above it.
Where does this go?
- A fact that someone looks up (an ODB key, a command-line option, a function signature, a status code, a limit) goes in Reference (or API, for function signatures), and only there. Other pages link to it.
- Anything that needs code to be compiled or run goes on the feature's programming page.
- Changing settings, deploying, and fixing or recovering things go on the feature's configuring page.
- Everything else an operator needs (concepts and day-to-day operation) goes on the feature's overview page.
- How midas works inside, when the reader doesn't need it to use the feature, goes in Internals.
Documentation of ODB keys
Avoid tables/lists of ODB keys in the feature guide! Those pages should explain the main tasks in English, with references to the relevant ODB keys. The ODB keys reference page contains the full tables/lists:
- Feature guide: English ODB key
- Reference: ODB key English
The same concept applies for programs and their command-line options.
Reading order
Features are ordered so that the documentation can be read from start to finish: a feature comes after the features it depends on. If a page needs a concept from a later feature, give a one-line explanation and a link at the first mention.
Related pages
End each feature overview that has configuring or programming pages with a "Related pages" abstract admonition with the extra related class, containing links separated by single spaces, each starting with an icon. The spacing between links comes from the .admonition.related rule in extra.css. Group the links as Configuring, then Programming, then Reference. A group may have several links, and groups with nothing relevant are left out. Other pages can use the same block where it helps.
Example 'Related pages' end-matter
!!! abstract related "Related pages"
[:lucide-settings: Configuring](configuring.md) [:lucide-code: Programming](programming.md) [:lucide-book-marked: ODB keys](../../reference/reference/odb_keys.md) [:lucide-book-marked: odbedit](../../reference/reference/programs.md#odbedit)