v2026.9.9
jdx/misev2026.9.9Sep 15, 2026by mise-en-dev
Upgrading?
AI Summary
This release addresses critical dotfiles history bugs, introduces encrypted history tracking for sensitive files, adds semantic configuration options for PyPI tools (uv), and fixes issues with npm global locks, packslip private repositories, and PowerShell activation.
Key Highlights
- Fixes false file deletion in dotfiles history caused by shared scratch git indexes.
- Adds encrypted history tracking via `mise dot track --encrypt`.
- Introduces semantic options (`with`, `expose`, `dependency_prereleases`) for PyPI tools to replace opaque `uvx_args`.
- Adds `--replace-history` to `mise bootstrap --adopt` to discard unrelated local history.
- Fixes installation from private GitHub repositories for packslip.
Breaking Changes
- The doubled `--` workaround for PowerShell sessions is no longer supported in activated shells.
- Global npm tools with `lockfile = true` now remain version-only unless explicitly opted in via `mise lock --global`.
- Ansible and Azure CLI registry entries now use the new semantic PyPI options by default; users forcing pipx must clear defaults with an empty list.
New Features
- Encrypted dotfiles tracking via `mise dot track --encrypt`.
- Bootstrap history replacement via `mise bootstrap --adopt --replace-history`.
- Semantic PyPI options (`with`, `expose`, `dependency_prereleases`) for uv-based tooling.
- New registry entry for `nubr` (TypeScript runner).
Full Release Notes
The dotfiles history watcher no longer records files as deleted when a checkpoint and a sync compose snapshots at the same time, `mise dot track --encrypt` enrolls a file with encrypted history from its first checkpoint, `mise bootstrap --adopt --replace-history` discards unrelated local history in one shot, and `pypi:` tools gain lock-aware `with`, `expose`, and `dependency_prereleases` options. Also fixed: `packslip:` installs from private GitHub repositories, stale history watchers after upgrading, global npm tools being reinstalled under `lockfile = true`, and the `--` separator in activated PowerShell sessions.
## Added
- **dotfiles:** `mise dot track --encrypt` writes `encrypt = true` into the tracked declaration and encrypts the initial baseline checkpoint, for files that must never have plaintext history. `[history.encryption].recipients` must be configured first; if the encrypted baseline cannot be saved, enrollment fails closed and rolls back the declaration without committing history metadata. Run it as a standalone command rather than inside `mise dot capture`. Enabling encryption on a file that already has plaintext history does not rewrite that history. ([#13180](https://github.com/jdx/mise/pull/13180) by @jdx)
```sh
mise dot track ~/.config/app/credentials --encrypt
```
- **bootstrap:** Fresh `mise bootstrap --adopt` now compares existing live files against the incoming setup before creating any local history, so identical files adopt the origin's history instead of being rejected as an unrelated root (for example right after the history store was removed). Differences still pause for an explicit decision. For machines that genuinely hold unrelated local history, `--replace-history` discards it and adopts the setup repository's branch in one shot; `--dry-run` previews the local and origin commits, and a failed replacement restores the previous branch and sync state. Ordinary sync never replaces divergent history and there is no persistent force setting. ([#13182](https://github.com/jdx/mise/pull/13182) by @jdx)
```sh
mise bootstrap --adopt <url> --replace-history --yes
```
- **pypi:** Three new tool options express common uv install behavior without opaque `uvx_args`, and unlike free-form arguments they participate in dependency graph locking: `with` installs extra requirements, `expose` installs extra requirements and links their executables (requires uv 0.8.5 or newer), and `dependency_prereleases` sets uv's prerelease policy (`disallow`, `allow`, `if-necessary`, `explicit`). Setting any of them selects uv as the installer. `uvx_args` and `pipx_args` remain available as version-only escape hatches. The Ansible and Azure CLI registry entries now use these options by default; if you force pipx for one of them, clear the default with an empty list, e.g. `"pypi:ansible" = { version = "latest", uvx = false, expose = [], pipx_args = "--include-deps" }`. ([#13181](https://github.com/jdx/mise/pull/13181) by @jdx)
```toml
[tools]
"pypi:azure-cli" = { version = "latest", with = ["pip"], dependency_prereleases = "allow" }
"pypi:ansible" = { version = "latest", expose = ["ansible-core"] }
```
- **registry:** Added `nubr` (`npm:@nubjs/runner`), the Nub project's TypeScript runner for a file, `package.json` script, or installed bin on plain Node. ([#13191](https://github.com/jdx/mise/pull/13191) by @colinhacks)
## Fixed
- **dotfiles:** With `history.sync = "sync"` and a running watcher, a checkpoint could record a sorted prefix of tracked files as deleted even though they were untouched on disk; those deletions then synced to other machines and removed their copies. Two compositions in one process (the watcher's checkpoint and the sync it started) shared a single scratch git index, and one resetting it mid-flight truncated the other's tree. Each composition now uses its own scratch index, and indexes left by killed processes are swept. Files recorded as falsely deleted are still in history and can be restored from an earlier checkpoint. ([#13195](https://github.com/jdx/mise/pull/13195) by @jdx)
- **dotfiles:** A history watcher started before mise 2026.9.5 (which moved history locks into `$MISE_STATE_DIR/history/`), or started with a different `MISE_STATE_DIR` than the shell, kept running the old process without watching the current store, while `mise bootstrap services apply` considered the unchanged service converged and skipped it. `services apply` now restarts a `history-watch` service whose process is not watching this store, and `mise doctor` and `mise dot status` report "running but not watching this store" instead of "not running" (`service-not-watching` in `mise dot status --json`). Users already in this state are recovered by running `mise bootstrap services apply`. ([#13190](https://github.com/jdx/mise/pull/13190) by @jdx)
- **npm:** With `lockfile = true` in effect, an npm tool pinned in the global config was resolved with a graph-specific install identity that no automatic flow could persist, so every `mise exec` treated the installed tool as unsatisfied, re-ran an install pass, and warned that it was missing. Global requests now stay version-only unless resolved from an explicitly generated revision 2 global lockfile; opt in with `mise lock --global`. ([#13186](https://github.com/jdx/mise/pull/13186) by @jdx)
- **packslip:** Installing from a private GitHub repository failed with `404 Not Found` on the manifest because GitHub only serves private release assets through its API, not the `releases/download/` URLs a packslip records. mise now falls back to the API asset endpoint using the same credentials as the `github:` backend (`MISE_GITHUB_TOKEN`, `GITHUB_API_TOKEN`, or `GITHUB_TOKEN`) with no configuration changes; signature, identity, digest, and size verification are unchanged. Tags containing `/` (such as `@biomejs/biome@2.5.2` or monorepo `tool/v1.0.0` tags) and `#` are also resolved correctly now. Non-GitHub hosts and GitHub Enterprise are not covered. ([#13188](https://github.com/jdx/mise/pull/13188) by @jdx)
- **activate:** In a shell activated with `mise activate pwsh`, `mise exec -- pnpm --version` failed with `unexpected argument '--version'` because PowerShell's parameter binder removes the first bare `--` before the `mise` wrapper function sees its arguments. The wrapper now recovers the separator from the raw invocation line, fixing `mise exec`/`mise x`, `mise tasks add`, `mise dotfiles capture`, `mise oci run`, `mise generate git-pre-commit`, and `mise bootstrap`; `mise run` was not affected. Open sessions pick up the fix the next time `mise activate pwsh` runs (normally at shell start). The doubled `mise exec -- -- cmd` workaround now fails in an activated shell, as it always did without activation, so drop back to a single `--`. ([#13202](https://github.com/jdx/mise/pull/13202) by @jdx)
- **registry:** The `dbt-fusion` install test now expects `dbt <version>`, matching what `dbt --version` actually prints. ([873c400](https://github.com/jdx/mise/commit/873c4009ebb92a34cbaffd88e1304bcac203784b) by @jdx)
## Documentation
- The GitHub star count on mise.jdx.dev now also appears in the nav overflow menu at medium viewport widths. ([#13193](https://github.com/jdx/mise/pull/13193) by @jdx)
**Full Changelog**: https://github.com/jdx/mise/compare/v2026.9.8...v2026.9.9
## 💚 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