v2026.9.9
anomalyco/opentuiv2026.9.9Sep 15, 2026by mise-en-dev
Upgrading?
AI Summary
This release addresses a critical dotfiles false-deletion bug and introduces encrypted history tracking for sensitive files. It also adds semantic options for PyPI tools and resolves issues with private GitHub repositories and stale history watchers.
Key Highlights
- Encrypted dotfiles history via `mise dot track --encrypt`.
- Discard unrelated local history with `mise bootstrap --adopt --replace-history`.
- Semantic options (`with`, `expose`, `dependency_prereleases`) for PyPI tools.
- Fixes for `packslip:` installing from private GitHub repositories.
- Fixes for stale history watchers after upgrading.
New Features
- Encrypted history tracking for dotfiles
- History replacement with `--replace-history` flag
- Semantic PyPI tool options (`with`, `expose`, `dependency_prereleases`)
- New registry tool: `nubr`
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
openclaw/openclaw★ 392,716
The AI that really does things. Any OS. Any Platform. The lobster way. 🦞
nilbuild/developer-roadmap★ 370,092
Interactive roadmaps, guides and other educational content to help developers grow in their careers.
morluto/rea★ 359,589
Reverse engineer anything with agents, from app behavior down to native binaries.
anomalyco/opencode★ 219,823
The open source coding agent.
n8n-io/n8n★ 208,270
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.