v2026.10.9
jdx/misev2026.10.9Oct 13, 2026by mise-en-dev
Upgrading?
AI Summary
This release addresses a critical security vulnerability by requiring trust for `path:` tool versions and significantly expands bootstrap capabilities, adding support for apt repositories, macOS login items, Fedora Atomic layering, and privilege elevation tools like `run0`/`doas`. It also improves GitHub OAuth handling, dotfiles status reporting, and fixes numerous issues across various tool backends.
Key Highlights
- `path:` tool versions now require trust to prevent unauthorized PATH manipulation.
- Added support for apt sources (PPAs), macOS login items, and `run0`/`doas` for privilege elevation.
- Improved handling of `dnf:` installs on Fedora Atomic hosts using `rpm-ostree layering`.
- Added GitHub OAuth conveniences, including copying device codes and caching refresh tokens securely.
- Fixed npm lockfile handling and Homebrew bottle installation issues.
Breaking Changes
- Configs using `path:` versions from untrusted repositories will be skipped until `mise trust` is run.
- `opencode@latest` now installs OpenCode 2; users must pin `opencode@1` to stay on v1.
- `mise bootstrap --adopt` now rejects repository URLs containing embedded credentials (e.g., `user:TOKEN@`) to prevent token leakage.
- Mise no longer shows a deprecation warning for `go.mod` files with an exact `go X.Y.Z` line.
New Features
- [bootstrap.apt.sources] configuration for declaring PPAs and vendor repositories.
- [bootstrap.macos.login_items] configuration for managing 'Open at Login' apps.
- Support for `system_packages.ostree = "layer"` on Fedora Atomic hosts.
- Support for `run0` and `doas` as alternatives to `sudo` for privilege elevation.
- Support for installing package groups via `dnf:` (e.g., `@development-tools`).
- Templated paths in `[bootstrap.repos]` using variables.
- Template functions `libc()` and `avx2()` for selecting build variants in `http:` URLs.
- Support for PEP 691 JSON format on PyPI Simple indexes.
- Support for `RUSTUP_UPDATE_ROOT` to download from Rust mirrors.
Full Release Notes
This release fixes a trust bypass: an untrusted `path:` tool version could put a directory on `PATH`. It also adds several bootstrap features: apt repositories and PPAs, macOS login items, rpm-ostree layering on Fedora Atomic, and `run0`/`doas` support. Beyond that, it improves `mise dot status`, adds GitHub OAuth conveniences, and fixes problems across npm, prune, brew and dotfiles sync.
## Security
- **`path:` tool versions now require trust.** Before, an untrusted repository could ship `node path:./local` in `.tool-versions` or `mise.toml`. `mise activate` would then put `./local/bin` ahead of your `PATH` on the next `cd`, without asking for trust, so a `local/bin/git` there would run in place of your real `git`. Configs with a `path:` version are now skipped until trusted, and you see the usual `is not trusted, run mise trust` warning. After `mise trust`, `path:` works as before. Other version forms are unaffected. Reported by Anthropic and Ada Logics. [#14358](https://github.com/jdx/mise/pull/14358)
- `mise bootstrap --adopt` now rejects repository URLs that embed credentials (a `user:TOKEN@` part). It used to quietly fall back to a plain clone, which left the token in `.git/config`. Use a Git credential helper or SSH agent. [#14315](https://github.com/jdx/mise/pull/14315)
- Download file names decoded from URLs (for example `tool%2F..%2Fpwned.tar.gz`, or `C:` names on Windows) can no longer point outside the download directory. Ordinary escapes such as `%20` still decode. [#14274](https://github.com/jdx/mise/pull/14274) (@JamBalaya56562, @hktitof)
## Added
### Bootstrap
- **`[bootstrap.apt.sources]`** declares PPAs and vendor apt repositories next to the packages that come from them. You no longer need a `pre-packages` hook that runs `add-apt-repository`. Each source is written as a deb822 file at `/etc/apt/sources.list.d/mise-<name>.sources`. Its signing key is fetched, trimmed to the fingerprints you declared, and stored inline in that file, so deleting the file removes both the repository and its key. PPAs need only `ppa = "owner/name"` and are added only on Ubuntu and Ubuntu-based distros, so the same config also works on Debian. Other repositories need `uris`, `key` and `fingerprint`; `suites` and `components` are optional. An unpinned `apt:` package that is installed from the distro is moved to the declared source. Inline keys require apt 2.4 or later (Ubuntu 22.04, Debian 12). [#14306](https://github.com/jdx/mise/pull/14306), [#14348](https://github.com/jdx/mise/pull/14348)
```toml
[bootstrap.apt.sources]
git-core = { ppa = "git-core/ppa" }
fish = { ppa = "fish-shell/release-4" }
[bootstrap.packages]
"apt:git" = "latest"
"apt:fish" = "latest"
```
- **macOS login items.** `[bootstrap.macos.login_items]` declares the apps listed under "Open at Login". `status` and `plan` report missing apps, and `mise bootstrap` adds them. The list is additive by default, so apps that register themselves are left alone. Set `exclusive = true` to have the config own the whole list. [#14354](https://github.com/jdx/mise/pull/14354)
```toml
[bootstrap.macos.login_items]
apps = ["/Applications/Ghostty.app", "~/Applications/Example.app"]
```
- **Fedora Atomic hosts.** On ostree-booted hosts (Silverblue, Bazzite, secureblue, ...), `dnf:` installs now stop with an explanation instead of failing inside dnf on read-only `/usr`. To layer packages instead, set `system_packages.ostree = "layer"`. mise then runs one `rpm-ostree install` for the whole batch and reports layered packages as `pending reboot` until you reboot. Version pins are skipped, and `upgrade` points you to `rpm-ostree upgrade`. [#14353](https://github.com/jdx/mise/pull/14353), [#14357](https://github.com/jdx/mise/pull/14357)
- **`run0` and `doas` for privilege elevation.** On hosts without `sudo`, mise uses the first of `sudo`, `run0` or `doas` it finds on `PATH`. To always use a specific one, set `system_packages.elevate_with` (or `MISE_SYSTEM_PACKAGES_ELEVATE_WITH`), for example `"run0"`. [#14351](https://github.com/jdx/mise/pull/14351)
- **dnf package groups.** Entries such as `"dnf:@development-tools" = "latest"` are now installed, upgraded and checked as groups. Before, `status` always reported them as missing. Environment groups (`@^name`) are not supported. [#14347](https://github.com/jdx/mise/pull/14347)
- **Templated `[bootstrap.repos]` paths.** Repo keys can use templates, so each machine can choose its own clone location with a var answered once through `mise vars prompt`. Unanswered vars use their `default`. [#14359](https://github.com/jdx/mise/pull/14359)
```toml
[vars.repos_dir]
default = "~/src"
prompt = "Where should repositories be cloned?"
[bootstrap.repos]
"{{ vars.repos_dir }}/project-a" = { url = "git@github.com:example/project-a.git" }
```
### Tools and backends
- **`libc()` and `avx2()` template functions** for `http:` URLs. They let one entry pick `-musl` and no-AVX2 `-baseline` builds: append `{{ avx2(yes="", no="-baseline") }}{{ libc(gnu="", musl="-musl") }}` to the `url` template after `{{ os() }}-{{ arch() }}`. `mise lock` records every variant. [#14298](https://github.com/jdx/mise/pull/14298)
- **PyPI Simple indexes:** when `pypi.registry_url` is not a `/json` URL, mise now asks for the PEP 691 JSON format. If the index supports it, upload times come from the index, so `minimum_release_age` now works with private indexes. HTML-only indexes behave as before. [#14352](https://github.com/jdx/mise/pull/14352)
- **Rust mirrors:** when `RUSTUP_UPDATE_ROOT` is set, `rustup-init` is downloaded from `{root}/dist/<host-triple>/rustup-init` instead of `sh.rustup.rs`. This lets mirrors such as panamax serve the first download too. mise also forwards `RUSTUP_DIST_SERVER` and `RUSTUP_UPDATE_ROOT` from config env to rustup. [#14356](https://github.com/jdx/mise/pull/14356)
### GitHub OAuth
- `github.oauth_copy_code` copies the one-time device code to the clipboard during `mise token github --oauth`, like `gh auth login --clipboard`. When the setting is unset, mise asks in an interactive terminal. Only the device code is copied, never the token. [#14269](https://github.com/jdx/mise/pull/14269)
- `github.oauth_cache_get` and `github.oauth_cache_set` keep the long-lived refresh token in a password manager or keychain, so the plaintext cache file holds only the 8-hour access token. Both settings must be set and can only go in global config. An existing cached refresh token moves into the store at the next refresh. If the store can't be read, mise keeps the cached token. If it can't be written, mise warns and keeps the token in the file. [#14360](https://github.com/jdx/mise/pull/14360)
```toml
[settings.github]
oauth_cache_get = "pass show mise/github-oauth"
oauth_cache_set = "pass insert -m -f mise/github-oauth"
```
### Dotfiles and skills
- **`mise dot status` output is grouped into sections:** Tracking, Repository, Conflicts, Automatic capture and Bootstrap, followed by a "Next steps" list of commands. The table now lists only entries that need attention and counts the rest. Use `--verbose`/`-v` to list every entry. `--json` and `--missing` are unchanged. [#14361](https://github.com/jdx/mise/pull/14361)
- `mise dot status` now shows tracked entries whose variants don't match this machine as `not on this machine (variants: work)`, instead of plain `tracked`. In `--json`, `state` stays `tracked` and a `reason` field is added. [#14266](https://github.com/jdx/mise/pull/14266)
- `mise skills sync` now lists the skill links it creates, plus `.mise-skills.json`, in the repository's `.git/info/exclude`, so they stay out of `git status`. Your hand-written skills are unaffected, and nothing in the repository itself changes. [#14374](https://github.com/jdx/mise/pull/14374)
## Changed
- **Registry:** `opencode` now installs OpenCode 2 from npm (`npm:@opencode/cli`). `opencode@latest` moves to v2 on your next upgrade. `opencode@1` keeps v1 from aqua. [#14295](https://github.com/jdx/mise/pull/14295)
- **Go:** if `go.mod` or `go.work` has an exact `go X.Y.Z` line and no `toolchain` line, mise now uses it as the toolchain version and no longer shows the deprecation warning. This matches how Go reads the file. The old advice to add a `toolchain` line didn't work, because `go mod tidy` removes it. `go X.Y` lines without a patch version are still deprecated. [#14308](https://github.com/jdx/mise/pull/14308)
- The official `-debian` Docker image now includes `libatomic1`, so Node.js 26 installs and runs without extra steps. [#14303](https://github.com/jdx/mise/pull/14303)
## Fixed
### Tools, shims and updates
- `auto_update` now updates only tools that are already installed. Since 2026.10.7, the first shell prompt could install every lazy tool declared with `auto_update`. [#14368](https://github.com/jdx/mise/pull/14368) (@ryanrhughes)
- Downloads started by `mise exec`, `mise x` and shims now retry up to `http_retries`, like `mise install`. Before, they made a single attempt. Remote version lookups still make one attempt, so shims don't get slower. [#14342](https://github.com/jdx/mise/pull/14342)
- npm tools installed from a lockfile in one project no longer show up as missing, or as `<version>~aube~<digest>`, in another config that requests `latest` or a version prefix without a lockfile. With `install_layout = "identity"`, unlocked requests get their own plain install, separate from the project's lockfile-built one. The same applies to uv-locked pipx tools. [#14307](https://github.com/jdx/mise/pull/14307), [#14309](https://github.com/jdx/mise/pull/14309)
- `mise prune` no longer removes tool versions used only by inline task `tools`. It also keeps a uv-locked `pipx:`/`pypi:` tool's installs for every Python version, not just the one in the current directory. [#14334](https://github.com/jdx/mise/pull/14334), [#14335](https://github.com/jdx/mise/pull/14335)
- Running reshim in one project no longer deletes `[wrappers]` command wrappers defined in other projects. [#14355](https://github.com/jdx/mise/pull/14355)
- With `skills.auto_sync`, `mise upgrade` now relinks agent skills to the new version. Before, the links kept pointing at the replaced install, which `prune` could then delete. [#14373](https://github.com/jdx/mise/pull/14373)
- Remote tasks no longer break commits when they are fetched from a git hook. Their clone was writing over the commit's index (`GIT_INDEX_FILE`). Fixed by updating gix to 0.89. [#14316](https://github.com/jdx/mise/pull/14316) (@any-victor)
- Packslip tools whose signing workflow moved, such as aube moving from `release-plz.yml` to `release.yml`, now upgrade when both workflows are in the `workflow` list. `mise lock` also keeps the signer of a renamed or transferred project. [#14338](https://github.com/jdx/mise/pull/14338), [#14362](https://github.com/jdx/mise/pull/14362)
- aqua packages that have no repo now print the "cannot list versions" warning once, and it tells you to pin an exact version. [#14336](https://github.com/jdx/mise/pull/14336)
- On Windows, the `tool-update` service no longer opens a console window that stops the updater when you close it. [#14344](https://github.com/jdx/mise/pull/14344)
### Homebrew and system packages
- Brew bottles now install their `etc`/`var` files and run the formula's `post_install_steps`. For example, `openssl@4` now gets its CA bundle and `openssl.cnf`. Existing files are kept, and the bottle's copy is saved next to them as `.default`. Protected `copy` steps (`overwrite: false`) are respected. [#14272](https://github.com/jdx/mise/pull/14272), [#14311](https://github.com/jdx/mise/pull/14311)
- On Linux, Homebrew `uses_from_macos` dependencies are now installed. This fixes runtime errors such as `libbz2.so.1.0` missing for `brew:chafa`. [#14288](https://github.com/jdx/mise/pull/14288) (@itskyf)
- `mise bootstrap` no longer runs `chown` on a Homebrew prefix owned by another non-root user. It stops with an explanation instead. [#14345](https://github.com/jdx/mise/pull/14345)
- Casks that mise evaluates itself now support the `generate_completions_from_executable` stanza. [#14255](https://github.com/jdx/mise/pull/14255) (@pmmmwh)
- `mise oci build` no longer runs the host's apt hooks against the image. Those hooks broke non-root builds that install packages such as `cmake`. [#14296](https://github.com/jdx/mise/pull/14296)
- When elevation is unavailable, mise no longer tells you to run privileged helpers that read their plan from stdin, because they can't run on their own. It now tells you to re-run the mise command as root. [#14350](https://github.com/jdx/mise/pull/14350)
### Dotfiles
- When another machine had saved a profile-variant file while that profile was inactive here, turning the profile on no longer publishes a deletion or reverts the shared file. Status reports it as `not applied here`, and `mise dot pull` applies it, or stops with a conflict that you resolve with `--take-remote` or `--keep-local`. [#14275](https://github.com/jdx/mise/pull/14275)
- After `mise bootstrap --adopt`, unchanged encrypted files reuse the ciphertext already in history. Before, they were re-encrypted, and `mise dot sync` paused on a conflict. [#14300](https://github.com/jdx/mise/pull/14300)
- When `/home` is a symlink (Fedora Atomic), adopting now restores `config/` entries, and `mise dot origin set` no longer shows a false "Not portable" warning. [#14315](https://github.com/jdx/mise/pull/14315)
- `mise dot apply` applies entries that write mise's own config first, then plans everything else from the new config. A newly added entry now takes effect in a single run. [#14339](https://github.com/jdx/mise/pull/14339)
- `mise dot diff` now shows per-file hunks, missing files and type mismatches for directory copy entries. [#14333](https://github.com/jdx/mise/pull/14333)
### Schema
- The JSON schema now accepts `[bootstrap.secrets]`, `[bootstrap.groups]`, `[bootstrap.users]`, and table forms of `vars._.file` and `vars._.source`. Editors and linters such as tombi and Taplo no longer flag configs that mise accepts. [#14322](https://github.com/jdx/mise/pull/14322), [#14340](https://github.com/jdx/mise/pull/14340), [#14383](https://github.com/jdx/mise/pull/14383) (@JamBalaya56562, @risu729)
## Documentation
- New guidance on when to use `mise bootstrap --from` versus `--adopt`, why `fish = "auto"` is recommended for fish activation, when to use `mise dot sync`, `pull` and `apply`, and how to check from a shim whether a tool is installed. [#14301](https://github.com/jdx/mise/pull/14301), [#14304](https://github.com/jdx/mise/pull/14304), [#14343](https://github.com/jdx/mise/pull/14343), [#14337](https://github.com/jdx/mise/pull/14337)
## Upgrade notes
- If an untrusted project uses a `path:` tool version, run `mise trust` in it.
- Scripts that parse the default table from `mise dot status` should add `--verbose` or switch to `--json`.
- `opencode@latest` moves to OpenCode 2. Pin `opencode@1` to stay on v1.
- `mise bootstrap --adopt` with a URL that contains credentials now fails. Use a credential helper or SSH agent instead.
## Registry
- New aqua packages: [`Alice39s/xmtr`](https://github.com/Alice39s/xmtr), [`bufbuild/protoschema-plugins/protoc-gen-jsonschema`](https://github.com/bufbuild/protoschema-plugins) and [`takumin/qemu-bin`](https://github.com/takumin/qemu-bin).
## New Contributors
* @pmmmwh made their first contribution in [#14255](https://github.com/jdx/mise/pull/14255)
* @itskyf made their first contribution in [#14288](https://github.com/jdx/mise/pull/14288)
**Full Changelog**: https://github.com/jdx/mise/compare/v2026.10.8...v2026.10.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