Skip to content

Mise

Mise ⧉ (pronounced "meez") is a tool that can pin dev tool versions via a single mise.toml config file. Every developer then has the correct version of each tool installed. We do not have to manage them through pyproject.toml.

Installation

On your own machine, install it however you like. The installer script is fine here:

curl https://mise.run | sh

Not in a build path

An installer script is an unpinned input with a live network dependency (BUILD-11). CI installs Mise with the pinned jdx/mise-action, through .github/actions/set-up-mise. The builder image installs it from the release binary at a pinned version, with a mirrorable URL. Neither pipes mise.run.

Then activate it in your shell. Add one of these to your shell config:

# bash (~/.bashrc)
eval "$(~/.local/bin/mise activate bash)"

# zsh (~/.zshrc)
eval "$(~/.local/bin/mise activate zsh)"

Restart your shell or source the config file.

Activation is required, not optional: without it mise installs the pinned tools but never places them on PATH, and shell completion reports usage CLI not found.

Upgrade Mise to latest version

mise self-update upgrades your local binary. The version the repository targets is min_version in the root mise.toml. The version that regenerates mise.lock is the github:jdx/mise pin in [tools]. Your local one is neither.

Installing tools

Inside the root of the monorepo, simply run:

mise trust mise.toml
mise install

During CI runs, MISE_YES=1 is set which allows is to skip the trust step

Running tasks

Tasks are defined per project and run with mise run. Run a bare task from inside a project directory, or address any project from anywhere with the //<project>:<task> syntax:

mise run //croesus:install     # one project
mise run '//...:lint'          # every project that defines 'lint'
mise tasks --all               # list every task

Shared task definitions live in mise/includes/ (the task bodies) and mise/scripts/ (the bash they call), not in mise/tasks/. See below. Every task is catalogued in Mise tasks. The rules governing them are build rules.

Adding tools

Add the pin to [tools] in the root mise.toml and commit the mise.lock change with it.

The mise-lock pre-commit hook regenerates the lockfile, not you. mise lock output is version-dependent, so regeneration runs through the github:jdx/mise pin in [tools], not whatever Mise is on your PATH. A lockfile written by a different Mise is a diff nobody can review. CI must allowlist the full github:jdx/mise spec in MISE_ENABLE_TOOLS, or the pin silently does nothing.

A tool the build needs MUST be pinned here, not assumed from the ambient shell. The Makefiles made that assumption, which is why the builder image had to bootstrap protoc separately.

The empty mise/tasks/ directory

mise/tasks/ is one of mise's file-task directories: any file placed under it becomes a task of the config root it sits in. At the repository root that would define phantom root tasks such as //:build and //:lint. Those match wildcards, so mise '//...:lint' would try to lint the repository root, where there is no go.mod. It then fails in a task nobody wrote. The directory MUST therefore stay empty. Shared task definitions live in mise/includes/ and mise/scripts/ instead.

The directory is kept in git by a hidden .tombstone.md, not a .gitkeep. A visible file makes mise warn on every mise tasks. Marking it executable would create exactly the phantom root task described above. A dotfile is ignored outright, and .tombstone.md additionally documents the trap. Do not add visible files there and do not chmod +x anything in it.

Config roots

A project is visible to Mise only if it is listed in [monorepo].config_roots in the root mise.toml and has a mise.toml of its own. The list is explicit, never globbed: iris/ and others hold directories that are not task projects, and a listed root with no config file warns on every invocation. Everyone learns to ignore that warning.

A project missing from config_roots is matched by no wildcard. Not linted, not tested, not built by any sweep, and nothing says so. See BUILD-6.