v2026.9.11
CloakHQ/CloakBrowserv2026.9.11Sep 18, 2026by mise-en-dev
Upgrading?
AI Summary
Introduces a macOS app bootstrap manager, task template inheritance, and fixes for Swift on Linux.
Key Highlights
- New `macos-app` manager for `.app` bundles without Homebrew casks
- Task templates now support inheritance of flags and vars
- Swift on Linux fixes for arm64 and distro selection
- Improved error messages for install failures
New Features
- `macos-app` package manager
- Task template inheritance with `extends` and variable reading
- Swift Linux fixes: arm64 support, distro selection from release index, `ldd` error reporting
- `install_env` values now rendered as templates
Full Release Notes
A new `macos-app` bootstrap manager installs `.app` bundles from a pinned URL and checksum when no Homebrew cask exists, task templates now compose `usage` flags and can be extended from file tasks, and Swift on Linux picks its distro build from swift.org's release index instead of a hard-coded map that 404'd on arm64 and on newer Fedora, Amazon Linux, and Arch hosts. Install failures also become far more actionable: errors name the `minimum_release_age` cutoff that hid every version, the child's last stderr line, or the shared libraries a Swift toolchain cannot load.
## Highlights
- **Apps without a cask:** `"macos-app:<name>"` entries in `[bootstrap.packages]` download, checksum-verify, and install a `.app` into `/Applications` using mise's existing cask pipeline, with stricter ownership rules for apps already at the target.
- **Task templates that actually share things:** a task that `extends` a template now inherits the template's `usage` flags alongside its own, file tasks can write `#MISE extends="..."`, and a template's `vars` can read the values the extending task supplies.
- **Swift on Linux:** arm64 downloads resolve on every distro, the build is chosen from what a release actually publishes (with a warning when a fallback is used), and a fallback that cannot start names the missing libraries instead of exiting 127 after a 1 GB download.
## Added
- **bootstrap:** The `macos-app` package manager installs a macOS `.app` bundle from a vendor or internal download. `version`, `url`, `sha256`, and `artifact` are all required (`"latest"` is rejected because mise cannot discover releases behind a plain URL); `{{version}}` is interpolated into `url`, so a release bump is a two-field edit. Only `.dmg` and `.zip` archives containing an app bundle are supported, state is kept in mise's state directory rather than Homebrew's Caskroom, and an app already at the destination that this entry does not own is refused unless `adopt = true` and the contents match. `mise bootstrap packages upgrade` cannot discover new versions for these entries, and `prune --manager macos-app` is unsupported. Prefer `brew-cask` wherever a cask exists. ([#13279](https://github.com/jdx/mise/pull/13279))
```toml
[bootstrap.packages."macos-app:example"]
version = "1.2.3"
url = "<HTTPS URL of the .dmg or .zip; {{version}} is interpolated>"
sha256 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
artifact = "Example.app"
```
- **tasks:** A task that names a template with `extends` and declares its own `usage` now gets the template's flags too, listed first in `--help`. Previously the task's spec replaced the template's entirely, so shared flags had to be copied into every task. Workspace-root task defaults still only fill in `usage` when the task has none. A flag declared in both places is listed twice; declare each flag in one place, or use usage flagsets for replacements. ([#13310](https://github.com/jdx/mise/pull/13310))
```toml
[task_templates.deploy]
usage = 'flag "--env <env>" help="Target environment"'
[tasks.deploy-api]
extends = "deploy"
usage = 'flag "--replicas <n>" help="How many to run"'
run = 'echo "env=$usage_env replicas=$usage_replicas"'
```
- **tasks:** File tasks (including remote HTTP and `git::` scripts) can use `#MISE extends="<template>"` in their header to inherit tools, env, description, aliases, and other fields from a task template; previously the field was warned about and ignored. A task whose command is a script file no longer picks up a template's `run`. ([#13307](https://github.com/jdx/mise/pull/13307))
- **swift:** When a Linux install fails its `swift --version` check, mise runs `ldd` over the toolchain and lists every unresolved shared library (for example `libform.so.6, libncurses.so.6, libpanel.so.6` on an Arch-family host running a ubi9 build), with the tool's `install_env` applied so an `LD_LIBRARY_PATH` remedy is not misreported. `docs/lang/swift.md` documents the workaround. ([#13319](https://github.com/jdx/mise/pull/13319))
## Fixed
- **swift:** Installing Swift on arm64 failed with a 404 on every Linux distro except Ubuntu (and on Windows arm64 lock entries) because only Ubuntu used swift.org's `<platform>-<arch>` download directory. ([#13293](https://github.com/jdx/mise/pull/13293), fixes [#13291](https://github.com/jdx/mise/issues/13291))
- **swift:** The Linux distro build is now chosen from swift.org's release index rather than a hard-coded map: the host's exact distro version wins, then the newest published build older than the host, then the family's oldest, with `ID_LIKE` consulted (Linux Mint gets an Ubuntu build) and unknown distros such as Arch falling back to `ubi9`. Every compromise is announced with a warning, musl hosts and unsupported architectures fail before downloading, and `swift.platform` still overrides selection without contacting swift.org. The `swift_platform` lockfile option now records the host as detected (e.g. `fedora40` instead of `fedora39`); mismatched entries are re-resolved on the next lock. ([#13297](https://github.com/jdx/mise/pull/13297), fixes [#13289](https://github.com/jdx/mise/issues/13289))
- **config:** `install_env` values are now rendered as templates like other tool options, so `LD_LIBRARY_PATH = "{{env.HOME}}/.local/lib/compat"` reaches the install subprocess expanded rather than literally. `{{version}}` is left unchanged. ([#13314](https://github.com/jdx/mise/pull/13314))
- **install:** When `minimum_release_age` (default `24h`) hides every candidate, the error names the setting and cutoff, how many releases it hid, the newest one with its release and eligibility dates, and a copy-pasteable exact pin to install it now, instead of `no versions found ... matching date filter`. A query that matched nothing is no longer blamed on the filter. ([#13308](https://github.com/jdx/mise/pull/13308))
- **cmd:** A failing command run by mise (installs, tasks, plugin scripts) now appends the child's last non-empty stderr line to the error, e.g. `exit code 127; last stderr: swift: error while loading shared libraries: libncurses.so.6 ...`. This also reaches the final error block under `--quiet`, where stderr was previously never shown. ([#13315](https://github.com/jdx/mise/pull/13315))
- **tasks:** A broken `usage` spec now reports the task name and the parser's diagnostic (`invalid usage spec for task 'deploy'` followed by the reason) instead of a bare `Invalid usage config`; file tasks render the same diagnostic rather than a Debug dump, and a missing or unreadable script is reported as such rather than as a bad spec. ([#13312](https://github.com/jdx/mise/pull/13312))
- **tasks:** A task template's `vars` can now read the vars the extending task supplies, so `{{ vars.opt | default(value='none') }}` in a template sees the task's `opt` instead of always taking the default. Literal vars within a single task are also bound first, so `vars = { msg = "hi {{ vars.who }}", who = "world" }` works regardless of declaration order. Config-level `[vars]` are unchanged. ([#13322](https://github.com/jdx/mise/pull/13322))
- **runtime symlinks:** `latest` and version-prefix links under `installs/<tool>/` that point at an install no longer eligible for a link (for example a directory left with an `incomplete` marker by an interrupted install) are now removed on rebuild instead of surviving indefinitely. Configured aliases, hand-made names, and absolute symlinks are left alone. ([#13288](https://github.com/jdx/mise/pull/13288))
- **npm:** Semver pre-releases with numeric suffixes such as `1.3.1-3` no longer claim the `latest`, `1`, and `1.3` runtime symlinks or satisfy `"latest"`/prefix requests over the newest stable install; links an older mise already wrote are cleaned up on the next install. An exact request or the `prerelease` option still selects them. ([#13272](https://github.com/jdx/mise/pull/13272) by @pataar)
- **lockfile:** `mise lock --global` on a `mise.lock` symlinked into a dotfiles repository now keeps native dependency sidecars beside the target lockfile, so `mise install --locked` works from a fresh checkout. If you used this layout on 2026.9.7 through 2026.9.10 and see missing sidecars, run `mise lock --global` again to repair the pointers. ([#13268](https://github.com/jdx/mise/pull/13268) by @nettlesh)
- **lockfile:** With `lockfile_mode = "generate"`, `mise unuse` now removes the tool's entry from `mise.lock` and its `.mise/locks/...` sidecar immediately rather than leaving them until the next `mise install` or `mise lock`. Merge mode is unchanged. ([#13304](https://github.com/jdx/mise/pull/13304))
- **conda:** Commands from `conda:` packages that have nothing to activate (no `activate.d` scripts, no dependency executables, no script entry points) are now plain symlinks instead of shell launchers, so tools like `conda:ripgrep` or `conda:gh` no longer prepend the conda prefix to the `PATH` of every child process and skip the extra shell. Packages that need activation keep their launcher; Windows is unchanged. A relative `MISE_DATA_DIR` is also handled. Existing installs keep their current entries until reinstalled with `mise install --force conda:<pkg>`. ([#13305](https://github.com/jdx/mise/pull/13305))
- **backends:** A tool's `postinstall` hook now receives pre-tools `[env]` from the config on every backend (http, aqua, github, cargo, npm, core tools), not only for asdf plugins, and a hook that changes an env input is visible to hooks ordered after it. ([#13316](https://github.com/jdx/mise/pull/13316))
- **github:** Tools whose release tags repeat the configured `version_prefix` (tag `a-a-1.2.3` with `version_prefix = "a-"`, listed as `a-1.2.3`) can now be installed; `prefix + version` is tried first so every listed version round-trips to its tag. If a repo publishes both `a-1.2.3` and `a-a-1.2.3`, requesting `a-1.2.3` now resolves to the doubled tag. ([#13317](https://github.com/jdx/mise/pull/13317))
## Changed
- **brew-cask:** Cask archives are downloaded concurrently at the configured `jobs` concurrency before the serial install pass, so `--jobs`/`MISE_JOBS` now speed up cask-heavy runs. Placement (mounting, swapping app bundles) remains serial. ([#13282](https://github.com/jdx/mise/pull/13282) by @waynehoover)
## Security
- **http:** Artifact downloads now refuse a redirect that steps down from HTTPS to HTTP, matching the policy the remote-version client already applied; the error names which kind of request was refused. URLs that are plain HTTP to begin with are unaffected. ([#13292](https://github.com/jdx/mise/pull/13292))
- **brew-cask:** The fingerprint used to adopt or refuse an existing app bundle is now computed entirely through the verified directory descriptor (`fstatat`/`openat`/`readlinkat`), so a path component swapped mid-check cannot make mise compare against a different tree than the one it will replace. Digests are unchanged, so existing receipts remain valid; large files are now hashed in-process, which can make adoption checks slower. ([#13294](https://github.com/jdx/mise/pull/13294))
## Documentation
- The bootstrap packages guide is reorganized around choosing a manager, declaring packages, and the command reference, with a dedicated section for direct `macos-app` downloads and app ownership. ([#13298](https://github.com/jdx/mise/pull/13298))
- The variables guide explains when `[vars]` resolve and why a task-local override does not recompute a top-level var that already referenced it, with task templates as the way to defer a fragment. ([#13323](https://github.com/jdx/mise/pull/13323))
- Task Arguments documents sharing flags between tasks with usage `flagset`, `use`, and `include`, in both TOML and file tasks. ([#13313](https://github.com/jdx/mise/pull/13313))
## New Contributors
* @pataar made their first contribution in [#13272](https://github.com/jdx/mise/pull/13272)
**Full Changelog**: https://github.com/jdx/mise/compare/v2026.9.10...v2026.9.11
## 💚 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
public-apis/public-apis★ 491,222
A collective list of free APIs
NousResearch/hermes-agent★ 256,093
The agent that grows with you
yt-dlp/yt-dlp★ 200,268
A feature-rich command-line audio/video downloader
microsoft/markitdown★ 191,563
Python tool for converting files and office documents to Markdown.
Significant-Gravitas/AutoGPT★ 187,700
AutoGPT is the vision of accessible AI for everyone, to use and to build on. Our mission is to provide the tools, so that you can focus on what matters.