Tasks can now skip themselves with a skip_if check, and bootstrap gains Snap packages, Fedora COPR repositories, and branch selection for --adopt. This release also fixes several mise dot pull problems that could loop, stall, or leave sharing paused on long histories. On the Windows side, it fixes .mise-bins executables and npm installs restored from a cache.
Added
-
skip_iffor tasks. Before a task runs, mise runs itsskip_ifshell command. If the command exits 0, mise skips the task and counts it as successful. Any other exit status runs the task as usual. #14399[tasks.setup] skip_if = "test -f .initialized" run = "touch .initialized"
The check runs after
dependsand beforeconfirm. It uses the task's directory, shell, environment, sandbox andtimeout, and it supports Tera templates and task arguments. Its output is discarded and it gets no stdin. It does not receive the task'ssecrets. File tasks can set it with#MISE skip_if="...".mise run --forceskips the check,--dry-runprints it without running it, andmise tasks infoshows it. If the check can't start, times out, or is killed, the task fails. -
Snap packages in bootstrap. On Linux, you can declare snaps in
[bootstrap.packages]alongside apt and flatpak, with optionalchannelandclassic, andstate = "absent"to remove a snap. If a snap tracks a different channel than you declared,statusshows it andapplymoves it withsnap refresh --channel. snapd can't install or hold a specific version, soapplyandupgradeskip entries with a version pin and print a warning. #14402[bootstrap.packages] "snap:jq" = "latest" "snap:node" = { channel = "22/stable", classic = true }
-
COPR repositories with
[bootstrap.dnf.repos]. You can declare a COPR next to thednf:packages that come from it, instead of using apre-packageshook. mise writes the same/etc/yum.repos.dfile thatdnf copr enabledoes. It does not need the copr plugin, so this also works on Fedora Atomic hosts that layer packages. The chroot is chosen from/etc/os-release(Fedora, EL, Amazon Linux). Without--yes, mise asks before enabling any COPR. mise never disables or removes repositories, butmise bootstrap unapplynames any leftover files. #14401[bootstrap.dnf.repos] ghostty = { copr = "scottames/ghostty" } [bootstrap.packages] "dnf:ghostty" = "latest"
-
mise bootstrap --adopt <url>?ref=<branch>adopts a branch other than the default, either for global config or for a setup history. This also works withmise bootstrap remote. The ref must be a branch: tags, commits and missing branches are refused before anything is cloned. mise never switches an existing~/.config/misecheckout to another branch, even with--update, so usegit switchfirst. The docs now also explain howmise dot origin setrelates to an adopted global config. #14400 -
GitHub OAuth refresh token in the Secure Enclave. On a Mac with Touch ID, set
github.oauth_cache_secure_enclave = trueto keep the native GitHub OAuth refresh token behind Touch ID instead of in plaintext ingithub-oauth-tokens.toml. Touch ID asks for a fingerprint only when the token needs refreshing. If you cancel the prompt, mise skips the refresh and keeps the cached access token. This needs the Developer ID-signed release build. Homebrew and source builds print a warning and keep the token in the cache file. #14413
Changed
- On Windows,
experimental = truenow turns on the identity install layout by itself, which keeps deep npm, pipx and Java trees under the 260-character path limit. Only new installs use it. Existing installs stay where they are, andmise installs migratecan move them. To keep the old layout, setinstall_layout = "legacy"(orMISE_INSTALL_LAYOUT=legacy). Linux and macOS still needinstall_layout = "identity"set explicitly. #14392
Fixed
Dotfiles
- Machines that share an origin and track an encrypted file no longer swap ciphertext back and forth forever. age encryption gives different ciphertext for the same content, so
mise dot watchcould publish commits endlessly without any real edits. Now mise keeps the ciphertext that history already has whenever it decrypts to the same content, mode and recipients. Machines that are already looping settle after one more sync. #14405 mise dot pullon long histories is much faster. The number of git processes no longer grows with the length of the history: in one test with 2,000 commits, a pull went from 137 s to under 6 s. #14407, #14415- When a pull's plan went out of date because another operation saved first, it was treated as a failed apply and paused sharing until someone ran
mise dot pullby hand. Now, if nothing has been written yet, mise retries on the next attempt and the watcher keeps applying changes. #14414 - After an interrupted history operation,
mise dot pull --yesno longer fails with "local saved history changed since planning". The pull now recovers the interrupted operation before it plans. #14410 - A file that already has the incoming version (content and mode) is no longer held as an unsaved edit or conflict that pauses sharing. Running
mise dot pull --take-remote <path>again for a path an earlier pull already resolved no longer fails with "is not a conflict". #14411
Windows
mise xand shims now run the original executable instead of its copy in.mise-bins, for tools installed with aquasymlink_bins, githubfilter_bins, or packslip. Programs that look for DLLs or data next to their own executable, such as exiftool, now start correctly. Tools installed by older versions needmise install --forceto get this. A shell frommise activatethat finds the copy onPATHstill runs the copy. #14397- npm tools installed with the built-in aube installer are reinstalled if their dependency links are missing, for example after a CI cache restore drops NTFS junctions. Before, mise reported them as installed and they failed at run time with
ERR_MODULE_NOT_FOUND. #14418
Tools and installs
rust@nightly,mise ls-remote rust, andmise outdated/upgradenow read the nightly manifest fromRUSTUP_DIST_SERVER, so a mirror such as panamax no longer needs access tostatic.rust-lang.org. If[env]setsRUSTUP_DIST_SERVERorRUSTUP_UPDATE_ROOT, mise also passes them torustup-initandrustup toolchain install. #14384- With a global
minimum_release_age,mise use --tool-option minimum_release_age=0s <tool>now installs the actual latest version instead of the version the global cutoff allows. #14398 (@halms) - Upgrading a global npm tool that
mise lock --globallocked with a dependency graph now regenerates the graph for the new version, including with--bump. Before, the upgrade dropped the graph and the nextmise install --lockedfailed. #14419 (@altendky) - Reinstalling a packslip tool signed by a shared reusable workflow works again with its saved pin. In v2026.10.9, mise rejected the unchanged signer as "not a workflow of" the tool's repository. Signer, workflow or repository changes are still refused. #14408
- Building Erlang from source now shows
compiling with kerlwhile the build runs, instead of staying onverifying checksum. kerl's output now prints above the progress row instead of writing over it. #14391 mise prunenow shows a progress line while it scans for unused versions, instead of printing nothing for what could be a long time. #14420- The JSON schema now rejects unknown keys in
env._.pythonand itsvenvoptions, matching what mise already refused at load time. Editors now flag these mistakes. #14387 (@JamBalaya56562, @risu729)
Documentation
- The configuration docs now explain how mise searches for config before listing the per-directory file names. #14390
- The bootstrap overview and run order now include
[bootstrap.apt.sources]. #14396
Full Changelog: v2026.10.9...v2026.10.10
💚 Sponsor mise
mise is built and maintained by @jdx, an open source developer at 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. Your support funds ongoing development and helps keep mise fast, free, and independent.