v2026.9.10

CloakHQ/CloakBrowserv2026.9.10Sep 16, 2026by mise-en-dev

Upgrading?

AI Summary

Adds shims exclusion, npm exotic dependency approval, bulk dotfiles conflict resolution, and fixes Windows Ctrl-C handling.

Key Highlights

  • Control over PATH shims with `shims.exclude`
  • Approval for non-registry npm dependencies with `allow_exotic_deps`
  • Bulk conflict resolution for dotfiles with `--take-remote-all`
  • Clean Windows Ctrl-C handling for tasks

New Features

  • `settings.shims.exclude` to prevent shims for specific names
  • `allow_exotic_deps` for npm dependencies from git/tarball URLs
  • Bulk dotfiles conflict flags: `--take-remote-all` and `--keep-local-all`
  • Template rendering for systemd and launchd units
  • vfox plugin hooks: `cmd.stream` and `cmd.exec` timeout

Full Release Notes

New settings let mise manage a tool without claiming its command names (`shims.exclude`) and approve non-registry npm dependencies (`allow_exotic_deps`), `mise dot pull` can decide every sharing conflict at once, and vfox plugin hooks gain `cmd.stream` plus a working `cmd.exec` timeout. On the fix side, `mise run` now survives Ctrl-C on Windows instead of orphaning `cmd.exe`, fish shells launched through shims start much faster with correct PATH order, and several task-resolution, lockfile, and Homebrew cask bugs are corrected.

## Highlights
- **Control over what mise puts on PATH and what it installs:** `settings.shims.exclude` keeps names like `python` resolving to the OS while mise still manages the tool; `allow_exotic_deps` approves specific npm packages fetched from git or tarball URLs; exact `packslip:` pins install during a `minimum_release_age` cooling window; and `mise upgrade --bump` keeps SemVer build metadata such as `+k3s1`.
- **Dotfiles sharing on a second machine:** `mise dot pull --take-remote-all` / `--keep-local-all` resolve all conflicts in one command, paths that cannot be decided are held rather than aborting the pass, and a directory sitting where a tracked file belongs is now reported as exactly that.
- **Task and shell reliability:** Windows Ctrl-C shuts tasks down cleanly, a task's own name always beats another task's alias, glob expansions no longer drop file tasks, Bash completion of `ns:task` names no longer duplicates the prefix, and fish startup through `mise exec`/shims is no longer quadratic in the number of tools.

## Added
- **shims:** `settings.shims.exclude` (env `MISE_SHIMS_EXCLUDE`) lists command names mise never creates shims for. The tool stays installed and version-qualified names like `python3.12` still resolve through mise, but the excluded name resolves to whatever else is on `PATH`; existing shims for those names are removed on the next `mise reshim`. Note that under `mise activate` without `--shims` the tool's `bin` directory still joins `PATH`, and excluding `python3` means `python3 -m venv` silently uses the system interpreter. ([#13266](https://github.com/jdx/mise/pull/13266))

  ```toml
  [settings.shims]
  exclude = ["python", "python3", "pip", "pip3"]
  ```
- **npm:** `allow_exotic_deps` approves dependencies that aube's `blockExoticSubdeps` gate would otherwise block because they come from a git, `file:`, or direct tarball URL. List package names to exempt only those (the gate stays on for the rest of the graph), or set `true` to exempt the whole graph. Applies to the `aube` and `aube_cli` installers. Embedded-aube installs now also warn when `install_env` is set, since it never reached the in-process installer. ([#13231](https://github.com/jdx/mise/pull/13231))

  ```toml
  [tools]
  "npm:@gmickel/gno" = { version = "2.3.0", allow_exotic_deps = ["xlsx"] }
  ```
- **dotfiles:** `mise dot pull --take-remote-all` and `--keep-local-all` decide every pending conflict at once, with per-path `--take-remote`/`--keep-local` naming exceptions. The two blanket flags are mutually exclusive, and paused-sync and adoption messages now point at them. ([#13233](https://github.com/jdx/mise/pull/13233))

  ```sh
  mise dot pull --take-remote-all --keep-local ~/.bashrc
  ```
- **bootstrap:** Every string value in `[bootstrap.linux.systemd.units]` and `[bootstrap.macos.launchd.agents]` is rendered as a template before the unit file or plist is written, so `{{ config_root }}/.env` in `environment_file` resolves to the declaring config's directory. Values without template syntax (including `%h` and `$HOME`) pass through untouched, `exec()` is rejected, and a unit whose template fails is skipped by name without blocking the others. `[bootstrap.services]` is not yet templated. ([#13227](https://github.com/jdx/mise/pull/13227))
- **hooks:** Each `MISE_INSTALLED_TOOLS` entry passed to `postinstall` hooks now carries `requested_version` (for example `latest`, `22`, or an alias) alongside the resolved `version`, so a hook can tell a floating request from a pin. The field is always present; existing hooks reading `name`/`version` are unaffected. ([#13274](https://github.com/jdx/mise/pull/13274))
- **vfox plugins:** `cmd.stream` runs a command with stdin connected and stdout/stderr streamed to the terminal, for hooks that genuinely need input such as a login or license prompt; it pauses the progress renderer and holds the terminal exclusively while it runs. `cmd.exec` and `os.execute` now detach stdin unless `--raw` is set, matching every other subprocess mise spawns, so a plugin that read stdin through `os.execute` should switch to `cmd.stream`. ([#13261](https://github.com/jdx/mise/pull/13261))
- **vfox plugins:** The `timeout` option on `cmd.exec` (and `cmd.stream`) now works instead of being silently ignored. It takes seconds (fractions allowed); on expiry the spawned shell is killed and the call raises a catchable error. Only the shell mise spawned is killed, so background processes it started may keep running. ([#13263](https://github.com/jdx/mise/pull/13263))

  ```lua
  local ok, err = pcall(cmd.exec, "some-tool sync", { timeout = 30 })
  ```

## Fixed
- **task:** On Windows, pressing Ctrl-C during `mise run` no longer kills mise immediately and leaves a `cmd.exe` behind stuck on `Terminate batch job (Y/N)?`. The first Ctrl-C lets running commands exit and stops scheduling new tasks; a second one takes the remaining process tree down. Tasks ended by the console are reported as interrupted instead of failing with exit code -1073741510. ([#13226](https://github.com/jdx/mise/pull/13226))
- **task:** A task's own name now always wins over another task's alias. Previously a parent config's `tests` task with `alias = "test"` could shadow a `test` task in the current directory, depending on alphabetical order. Aliases still resolve wherever no task claims that name. ([#13230](https://github.com/jdx/mise/pull/13230))
- **task:** Glob expansions such as `mise run '//...:lint'` or `'*:lint'` no longer silently drop file tasks (`mise-tasks/lint.sh`) when a sibling package has an exact match. The same-package dedup that stops `hello` and `hello.sh` running twice is preserved. ([#13277](https://github.com/jdx/mise/pull/13277))
- **completions:** Bash completion of namespaced tasks like `update:deps:no<TAB>` no longer produces `update:deps:update:deps:no-cooldown`. Reinstall the script with `mise completion bash --install` if yours predates the prefix-aware wrapper. ([#13276](https://github.com/jdx/mise/pull/13276))
- **exec:** Launching fish through `mise exec` or a shim emitted one `fish_add_path` per directory, which made startup quadratic (over 1s with ~80 tools) and reversed mise's PATH order relative to bash. A single batched call restores both. ([#13235](https://github.com/jdx/mise/pull/13235))
- **dotfiles:** A blanket `--take-remote-all`/`--keep-local-all` no longer aborts the whole pass when one path cannot be decided (a directory on the live side, or unsaved local changes under `--keep-local-all`). Decisions for the other conflicts are recorded, and the error names the held paths so fixing just those finishes the setup. ([#13239](https://github.com/jdx/mise/pull/13239), [#13242](https://github.com/jdx/mise/pull/13242))
- **dotfiles:** A directory or unreadable path where the repository has a file is now reported by `mise dot conflicts`, `mise dot status`, and `mise doctor` as exactly that, with advice to move it aside, instead of as a "changed type" conflict that `--take-remote`/`--keep-local` cannot resolve. Git or process failures while reading a live file now stop the sync with their own error instead of posing as a conflict. ([#13249](https://github.com/jdx/mise/pull/13249))
- **upgrade:** `mise upgrade --bump` preserves SemVer build metadata when rewriting a pin, so k3s bumps to `1.37.0+k3s1` rather than a nonexistent `1.37.0`, and Temurin keeps its `+7` build number. Coarser pins like `1.36` still bump to `1.37`. ([#13258](https://github.com/jdx/mise/pull/13258))
- **packslip:** An exactly pinned version (for example `"packslip:github.com/jdx/hk" = "2.0.1"`) now installs and locks while still inside its `minimum_release_age` window, as the setting documents. Fuzzy requests such as `"2"` or `latest` still wait out the cutoff. ([#13251](https://github.com/jdx/mise/pull/13251))
- **install:** `MISE_LOCKED=1 mise install <tool>` no longer warns about unrelated (often global) tools missing from the lockfile; installing the requested tool or a bare `mise install` still fails if that tool is not locked. ([#13259](https://github.com/jdx/mise/pull/13259) by @jamescassell)
- **pypi:** `mise lock` no longer fails when a `with`/`expose` requirement is pinned to a release needing a newer Python than the tool itself (e.g. `mkdocs` 1.6.1 with `mkdocstrings==1.0.6`). The sidecar's `requires-python` is now intersected across every pinned requirement; unpinned requirements and pins behind an interpreter marker leave the range alone. Existing lockfiles remain valid. ([#13252](https://github.com/jdx/mise/pull/13252))
- **aqua:** With `minimum_release_age` set, the latest release no longer falls back to an older version when the hosted version list lags GitHub. The release date from the `/releases/latest` response mise already fetched is used directly, with no extra requests. ([#13228](https://github.com/jdx/mise/pull/13228))
- **backend:** Tools whose registry entry splits across backends at a version boundary (like `hk`) now list versions from the backend that actually resolves, so `mise ls-remote hk@1.57` and `mise latest hk@1.57` return `1.57.0` instead of nothing. Also covers backends promoted by `MISE_DISABLE_BACKENDS`, platform-scoped entries, and lockfile pins. ([#13238](https://github.com/jdx/mise/pull/13238))
- **http:** GitHub answers an exhausted rate limit with 403 rather than 429, so mise never retried it. A 403 carrying `x-ratelimit-remaining: 0` or `retry-after` is now retried like a 429 under `http_retries`; a 403 with quota remaining is still treated as a refusal. Default backoff (~5s total) will not outlast a long reset, but brief contention no longer fails an install outright. ([#13256](https://github.com/jdx/mise/pull/13256))
- **skills:** `mise skills ls` and `mise skills sync` now warn when a packslip declares a skill the install does not hold, with the reason (`skills.fetch` off, `packslip.exec` off, or a failed download), instead of looking identical to "no skills declared". After an install with `skills.auto_sync` off, a one-time hint points at `mise skills sync`. `--json` output is unchanged. ([#13275](https://github.com/jdx/mise/pull/13275))
- **brew:** `adopt` is now honored for casks named on the command line (`mise bootstrap packages apply brew-cask:menuwhere`) and for tap-qualified names and aliases like `brew-cask:homebrew/cask/firefox`, so existing app bundles are adopted rather than replaced and macOS keeps their Privacy & Security grants. ([#13262](https://github.com/jdx/mise/pull/13262))
- **brew:** Tap formulae declaring requirement symbols such as `depends_on :macos` no longer make `bootstrap packages` try to fetch a formula named `macos` and abort the whole run with a 404. ([#13240](https://github.com/jdx/mise/pull/13240) by @waynehoover)
- **brew:** Tap cask metadata evaluation now understands `appdir` and `HOMEBREW_PREFIX` interpolation, and casks whose app bundle sits in a nested archive directory (`app "nested/Example.app"`) install as `Example.app` instead of being rejected as a relative target; duplicate app targets are rejected before anything is downloaded. ([#13138](https://github.com/jdx/mise/pull/13138) by @Guria, [#13199](https://github.com/jdx/mise/pull/13199) and [#13200](https://github.com/jdx/mise/pull/13200) by @soodoh)
- **bootstrap:** Selecting a Ruby to evaluate third-party Homebrew taps skips mise shims, which the metadata sandbox could not load, so package bootstrap no longer fails when Ruby is installed through mise. ([#13198](https://github.com/jdx/mise/pull/13198) by @jacobbednarz)

## Documentation
- The dotfiles history guide now explains encryption recipients (SSH keys, `age-keygen`, recovery keys) and warns that passphrase-protected SSH keys and plugin-only recipients cannot decrypt in the background; the setup guide covers adopting onto a machine that already has the files and using non-GitHub Git hosts. ([#13232](https://github.com/jdx/mise/pull/13232))
- The PyPI backend's locking limitations now point at the lockable `with`, `expose`, and `dependency_prereleases` options. ([#13222](https://github.com/jdx/mise/pull/13222))

## New Contributors
* @waynehoover made their first contribution in [#13240](https://github.com/jdx/mise/pull/13240)

**Full Changelog**: https://github.com/jdx/mise/compare/v2026.9.9...v2026.9.10

## 💚 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