v2026.9.14
jdx/misev2026.9.14Sep 25, 2026by mise-en-dev
Upgrading?
AI Summary
Configuration is now more modular with `conf.d` folder fragments, and dotfiles gain GNU Stow-style options for relative symlinks and `dot_prefix`. Public GitHub repo metadata now uses a dedicated mirror.
Key Highlights
- `conf.d` folder fragments allow for modular configuration.
- Relative dotfile symlinks and `dot_prefix` options.
- `mise-versions` integration for public GitHub repos (avoids API rate limits).
- Registry-required GitHub attestations for specific tools.
New Features
- `mise use`/`mise set` never write to `conf.d` folder fragments.
- `mise oci build` honors dotfile exclude and include lists.
- pipx/pypi `latest` no longer resolves to PEP 440 developmental releases.
- `brew source builds` follow HTTPS-to-HTTP mirror redirects.
- npm backend on Windows fixes lifecycle scripts.
Full Release Notes
A folder inside any `conf.d` directory now loads as its own config fragment and serves as the config root for the files in it, which gives `[bootstrap].config_roots` users a direct migration path. `[dotfiles]` gains two GNU Stow-style options: relative symlinks and `dot-<name>` sources. Release metadata for any public github.com repo now comes from mise-versions, and the registry can require GitHub attestations for specific tools.
## Added
- **conf.d folder fragments.** A folder in a global, system, or project `conf.d` directory now loads as a fragment. Relative paths, `{{ config_root }}`, and task working directories resolve inside that folder, so a bundle can keep its files next to its config. Each folder can hold `mise.toml`, `mise.local.toml`, `mise.<env>.toml`, and `mise.<env>.local.toml`. Folders are not searched recursively, and folders whose names start with `.` are skipped. A folder can be a symlink. Folder fragments load after the single-file fragments in the same `conf.d` (in folder-name order) and before `config.toml`. `mise use`/`mise set` never write to them. [#13603](https://github.com/jdx/mise/pull/13603)
```text
~/.config/mise/conf.d/
├── git.toml # single-file fragment, unchanged
└── git-tools/ # folder fragment
├── mise.toml
└── gitconfig
```
```toml
# ~/.config/mise/conf.d/git-tools/mise.toml
[dotfiles]
"~/.gitconfig" = "gitconfig" # resolves to conf.d/git-tools/gitconfig
```
**Compatibility:** if a directory inside a `conf.d` that mise reads already contains a `mise.toml`, that file now loads.
- **Relative dotfile symlinks.** `symlink` and `symlink-each` entries can now point at their source by a relative path, so links keep working when a home directory is mounted at a different path or moved. Turn this on for all entries with `dotfiles.relative_symlinks = true` (or `MISE_DOTFILES_RELATIVE_SYMLINKS=1`), or per entry with `relative = true/false`. When you turn it on, existing absolute links are re-pointed on the next apply. Turning it off does not convert relative links back to absolute ones. This option has no effect on Windows. [#13583](https://github.com/jdx/mise/pull/13583)
```toml
[settings]
dotfiles.relative_symlinks = true
[dotfiles]
"~/.config/foo" = { source = "~/dotfiles/foo", mode = "symlink" } # -> ../dotfiles/foo
"~/.bashrc" = { source = "~/dotfiles/bashrc", relative = false } # stays absolute
```
- **`dot_prefix` for dotfiles.** With `dot_prefix = true` on a `symlink-each` or directory `copy` entry, any path component named `dot-<name>` deploys as `.<name>` (for example, `home/dot-config/foo` deploys as `~/.config/foo`). `exclude` and `manifest = "git"` still match source names. If two sources map to the same target, apply fails. `mise dot add` refuses to capture into `dot_prefix` entries, and `mise oci` builds use the same mapping. [#13585](https://github.com/jdx/mise/pull/13585)
```toml
[dotfiles]
"~" = { source = "home", mode = "symlink-each", dot_prefix = true, exclude = ["README.md"] }
```
- **mise-versions for any public github.com repo.** For `github:`, `aqua:`, and `packslip:` tools that aren't in the registry, version listing, release lookup, and attestation lookup now go through mise-versions, so they no longer use your GitHub API rate limit in the common case. Private repos still use your own token against api.github.com. [#13584](https://github.com/jdx/mise/pull/13584)
- mise treats the mirror as untrusted. Download URLs must match the configured repo, release tag, and asset name, and mirrored attestations must name the requested repo.
- In `paranoid` mode, mise checks a "no attestations" answer from the mirror against GitHub before skipping verification.
- If `url_replacements` reroutes GitHub API paths, mise skips mise-versions for that metadata.
- If mise-versions fails for any reason other than a 404, mise falls back to api.github.com and logs a warning.
- **Registry-required GitHub attestations.** Registry `github:` backends can declare `attestations_since = "<semver>"`. For versions at or after that boundary:
- `mise lock` records `github-attestations` provenance.
- Installs require a verified attestation for every downloaded asset. This requirement overrides weaker provenance recorded in a lockfile.
- A missing attestation is a hard error.
42 registry tools now set this boundary, including `aube`, `aqua`, `pixi`, `ty`, `pandoc`, `fnox`, `doppler`, and `syncthing`. Users who have turned off `github_attestations` are not affected. [#13586](https://github.com/jdx/mise/pull/13586)
## Fixed
- **Install lock waits:** when one process is waiting for another to finish installing the same tool version, the message now names the process holding the lock (`waiting for install lock held by pid 61907`). This is usually a shim auto-installing the tool. [#13588](https://github.com/jdx/mise/pull/13588)
- **Slow downloads:** mise now warns once per download if throughput stays below 16 KiB/s for a full minute, naming the host and suggesting a mirror. The download is not aborted; `http_download_timeout` is still the hard limit. [#13589](https://github.com/jdx/mise/pull/13589)
- **Interrupted installs:** a half-installed version no longer appears in version listings, can't be picked as the latest installed version, and doesn't keep `latest`/`1`/`1.2` runtime symlinks pointing into it. [#13596](https://github.com/jdx/mise/pull/13596)
- **`mise prune`:** no longer deletes versions pinned by another project when you run it from a directory whose `.miserc.toml` lists that project in `ignored_config_paths`. The same fix applies to `mise ls --prunable` and the stale-version check in `mise upgrade`. These commands now honor `ignored_config_paths` only from `MISE_IGNORED_CONFIG_PATHS` and global or system `miserc.toml`. [#13602](https://github.com/jdx/mise/pull/13602)
- **`mise oci build`:** directory `[dotfiles]` entries (`symlink-each` and directory `copy`) now honor `exclude` and `manifest = "git"`, so the image contains the same files `mise dot apply` deploys. [#13591](https://github.com/jdx/mise/pull/13591)
- **pipx/pypi:** `latest` no longer resolves to PEP 440 developmental releases such as `2026.9.16.232951.dev0`, matching what pip and uv do. Local labels like `1.1+gpu.dev0` are still treated as stable. [#13601](https://github.com/jdx/mise/pull/13601)
- **pipx/pypi:** `mise use 'pypi:git+ssh://git@github.com/psf/black.git'` now works. Previously, the `@` in `git@` was read as the version separator. [#13610](https://github.com/jdx/mise/pull/13610)
- **`MISE_USE_VERSIONS_HOST=0`:** now fetches the version list from the source instead of reusing a cached, possibly older list from the versions host. [#13605](https://github.com/jdx/mise/pull/13605)
- **brew source builds:** checksum-pinned formula source downloads now follow HTTPS-to-HTTP mirror redirects (such as those from `ftpmirror.gnu.org`) and still reject tarballs whose checksum doesn't match. This affects Unix only. Every other download still refuses HTTPS-to-HTTP redirects. [#13611](https://github.com/jdx/mise/pull/13611)
- **npm backend on Windows:** updating the bundled aube to v2.4.0 fixes lifecycle scripts failing with `EISDIR: illegal operation on a directory, lstat 'C:'` during `npm:` installs. [#13608](https://github.com/jdx/mise/pull/13608)
## Changed
- The `[bootstrap].config_roots` deprecation warning now explains how to move each root into a `conf.d` folder, either by moving it or by symlinking it. The removal date (mise 2027.3.3) is unchanged. [#13598](https://github.com/jdx/mise/pull/13598)
- Registry: `spin-framework` now installs through aqua by default. The previous backend is still available. [#13594](https://github.com/jdx/mise/pull/13594) by @scop
**Full Changelog**: https://github.com/jdx/mise/compare/vfox-v2026.9.15...v2026.9.14
## 💚 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