v2026.9.7
jdx/misev2026.9.7Sep 13, 2026by mise-en-dev
Upgrading?
AI Summary
This release introduces lockfile revision 2 to record transitive dependency graphs for npm and Python tools, adds a command to inspect dotfile conflicts, and restricts dotfile templates in OCI builds to prevent credential exposure.
Key Highlights
- Lockfile revision 2 records full transitive dependency graphs for npm (via aube) and Python (via uv) in native sidecar files.
- New `mise bootstrap dotfiles conflicts` command allows read-only inspection of dotfile sync conflicts before resolution.
- Dotfile templates can now reference bootstrap secrets using `{{ secret(name='...') }}`.
- Security updates restrict `history.describe_command` to global configuration and restrict OCI build templates to prevent ambient credentials from being baked into images.
Breaking Changes
- Lockfile revision 2 is not readable by older mise versions; existing files must be upgraded via `mise lock --upgrade`.
- Project-level `history.describe_command` configuration is ignored; move it to global config or environment variable.
- `mise oci build` dotfile templates can no longer call `secret()`, `get_env()`, `exec()`, or `read_file()`.
New Features
- Support for `mise lock --upgrade` to migrate lockfiles to revision 2.
- Support for `mise lock --bump` to refresh transitive graphs without changing top-level versions.
- Support for `mise install --locked` to replay recorded dependency graphs.
- Introduction of `pypi:` as the preferred name for the Python CLI backend, with `pipx:` as a supported alias.
- Secret resolution in dotfile templates and preflight checks for dotfile templates.
Full Release Notes
This release introduces `mise.lock` revision 2, which records complete transitive dependency graphs for npm tools (via embedded aube) and Python tools (via uv) in native sidecar files, and adds `mise bootstrap dotfiles conflicts` for inspecting dotfile sync conflicts before resolving them. It also lets dotfile templates consume bootstrap secrets, stops `minimum_release_age` from rejecting versions already committed to a lockfile, and closes a security gap in `history.describe_command`.
## Added
- **lock:** Lockfile revision 2 records the full dependency graph of npm tools installed by embedded aube and of `pypi:` tools installed by uv, then replays it with a strict frozen install so two projects on the same top-level version can still receive their own reviewed transitive graph. Graphs live in native sidecar files (`uv.lock` / `aube-lock.yaml` plus a manifest) under `.mise/locks/<backend-tool>/<version>/`, referenced from `mise.lock` by relative path and SHA-256 digest, so the lockfile itself stays small. Commit the sidecar directory with `mise.lock`. New lockfiles use revision 2; existing revision 0 and 1 files keep their format until you run `mise lock --upgrade`. `mise lock --bump <tool>` refreshes a tool's transitive graph even when its top-level version is unchanged, ordinary `mise install` validates and accepts hand-edited sidecars, and `mise install --locked` rejects digest mismatches until you run `mise lock`. Python graph locking requires uv 0.12.10 or newer and published wheels for the target platform; Git sources, standalone pipx installs, and free-form `uvx_args`/`pipx_args` stay version-only. ([#13131](https://github.com/jdx/mise/pull/13131), [#13146](https://github.com/jdx/mise/pull/13146) by @jdx)
```sh
mise lock --upgrade # move an existing lockfile to revision 2 and resolve graphs
mise install --locked # replay the recorded graphs
mise lock --bump pypi:black # refresh Black's dependencies without changing its version
```
- **pypi:** `pypi:` is now the preferred name for the Python CLI backend; `pipx:` remains fully supported as an alias with no warnings, and settings accept both `pypi.*` and `pipx.*` names. The two spellings are distinct tool identities (`pypi-black` vs `pipx-black` install directories and lock entries), so switching spelling creates a new installation. ([#13146](https://github.com/jdx/mise/pull/13146) by @jdx)
- **bootstrap:** `mise bootstrap dotfiles conflicts [PATH...]` shows a read-only comparison of the saved local and fetched remote versions of a conflicted dotfile so you can decide between `--take-remote` and `--keep-local` with full context. The default output is a unified diff including file-mode changes; `--difftool` opens the configured Git `diff.tool` (falling back to `merge.tool`) and `--tool <name>` picks one explicitly. Encrypted contents are decrypted only into private temporary files, and inspection never modifies either side or marks the conflict resolved. Bootstrap secrets are also now resolved from the same composed config maps as dotfile discovery, so root-scoped dotfile templates can use secrets declared by their bootstrap root. ([#13144](https://github.com/jdx/mise/pull/13144) by @jdx)
```sh
mise bootstrap dotfiles conflicts ~/.config/mise/config.toml
mise bootstrap dotfiles conflicts --difftool ~/.config/mise/config.toml
```
- **dotfiles:** Dotfile templates (`mode = "template"`) can reference `[bootstrap.secrets]` values with `{{ secret(name="...") }}`, matching managed bootstrap file templates. Dotfiles commands that render templates (`add`, `apply`, `diff`, `edit`, `status`, `unapply`) accept `--prompt-secrets`; without an available value, rendering fails closed. A full `mise bootstrap` run preflights dotfile templates before making changes, `mise bootstrap status` reports secrets used only by dotfiles, and textual diffs redact resolved secret values. ([#13140](https://github.com/jdx/mise/pull/13140) by @jdx)
```toml
[bootstrap.secrets]
api_token = "EXAMPLE_API_TOKEN"
[dotfiles."~/.config/example/credentials"]
source = "dotfiles/credentials.tmpl"
mode = "template"
```
## Fixed
- **lock:** Installing from a committed `mise.lock` no longer fails when the locked release is younger than `minimum_release_age`. The cutoff still applies when resolving unlocked fuzzy requests and when generating or bumping a lockfile, and `npm:`/`pypi:` still forward it to unpinned transitive dependencies, but a reviewed lock entry now reproduces immediately in CI instead of waiting for the release to cool. ([#13128](https://github.com/jdx/mise/pull/13128) by @jdx)
- **config:** A `.python-version` (or other idiomatic version file) containing `system` selects the system interpreter without printing the mise-specific `@system` deprecation warning, matching the existing `.tool-versions` exception. Explicit `python@system` requests from mise configuration or command arguments still warn. ([#13132](https://github.com/jdx/mise/pull/13132) by @jdx)
- **npm:** Embedded aube is updated to 2.2.16, fixing the Bun checksum install regression and ensuring local npm tarballs keep their manifest package name. ([#13145](https://github.com/jdx/mise/pull/13145) by @jdx)
- **registry:** The `mc` shorthand uses `aqua:minio/mc` again now that the upstream Aqua registry entry is restored, with `asdf:mise-plugins/mise-mc` kept as the fallback. ([#13124](https://github.com/jdx/mise/pull/13124) by @jdx)
## Security
- **history:** `history.describe_command` is now global-only. Previously an implicitly trusted project could set it and have a later dotfiles history checkpoint execute the project-controlled command with unencrypted tracked-file diffs. The setting is honored only from system/global configuration or `MISE_HISTORY_DESCRIBE_COMMAND`; project values are ignored with a warning. ([#13134](https://github.com/jdx/mise/pull/13134) by @jdx)
- **oci:** `mise oci build` now renders dotfile templates with a restricted engine: `secret()` is rejected and the `env` context, `get_env()`, `exec()`, and `read_file()` are unavailable, so ambient credentials cannot be baked into a publishable image layer. ([#13140](https://github.com/jdx/mise/pull/13140) by @jdx)
## Breaking Changes
- **Lockfile revision 2 is not readable by older mise versions.** Newly created lockfiles use revision 2, and existing files switch only when you run `mise lock --upgrade`. Upgrade collaborators and CI to this release before committing a revision 2 `mise.lock`, and commit the `.mise/locks/` (or `.config/mise/locks/`) sidecar directory alongside it. Revision 2 `--locked` installs fail if a recorded graph is missing or its digest does not match. If you gitignore `mise.local.lock`, also ignore its matching sidecar subdirectory (for example `.mise/locks/mise.local/`).
- **`history.describe_command` in project configuration is ignored.** Move it to `~/.config/mise/config.toml` or set `MISE_HISTORY_DESCRIBE_COMMAND`.
- **`mise oci build` dotfile templates** can no longer call `secret()`, `get_env()`, `exec()`, or `read_file()` or read the `env` context.
**Full Changelog**: https://github.com/jdx/mise/compare/v2026.9.6...v2026.9.7
## 💚 Sponsor mise
mise is built and maintained by [@jdx](https://github.com/jdx), an open source developer at [**entire.io**](https://entire.io/), the title sponsor of his open source work.
If mise saves you or your team time, please consider becoming an [individual or company sponsor](https://jdx.dev/sponsors.html). Your support funds ongoing development and helps keep mise fast, free, and independent.
Related Repositories
A cross-platform desktop All-in-One assistant for Claude Code, Codex, OpenCode, OpenClaw, Grok Build & Hermes Agent. Only official website: ccswitch.io
An open-source remote desktop application designed for self-hosting, as an alternative to TeamViewer.
Build smaller, faster, and more secure desktop and mobile applications with a web frontend.
π RuView turns commodity WiFi signals into real-time spatial intelligence, vital sign monitoring, and presence detection — all without a single pixel of video.
Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one