Skip to content

v2026.7.15: Experimental Task Output Caching

Latest

Choose a tag to compare

@mise-en-dev mise-en-dev released this 27 Jul 18:51
Immutable release. Only release title and notes can be modified.
v2026.7.15
1877d3c

This release lands the first version of experimental local task output caching, letting eligible tasks restore their declared outputs and replay their logs without rerunning. It also adds structured registry idiomatic-version-file parsing, a standalone Aube installer mode, and a broad batch of task, Homebrew, shell, and Windows path fixes.

Highlights

  • Experimental local task artifact caching restores task outputs (and replays their logs) across deletions, checkouts, and unchanged CI runs, with cache keys derived from source contents, task config, tools, and environment. It works for tasks that produce files, tasks with no filesystem outputs, and multi-task graphs, and stays opt-in and conservative on any failure.
  • Registry-backed tools can now parse idiomatic version files (like dagger.json, Taskfile.yml, .chezmoiversion, and 8 more) in-process, with no plugin or shell execution.

Added

  • task: experimental, opt-in local artifact caching. Tasks with sources and explicit outputs can restore their outputs from a content-addressed cache instead of rerunning, and successful stdout/stderr are replayed through whatever output mode the current run uses. Cache keys combine source contents, task configuration and arguments, declared and allowlisted ambient environment, resolved tools, OS, and architecture. Cache failures degrade to misses or warnings rather than failing a task. (#11328, #11347 by @jdx)

    [tasks.build]
    run = "..."
    sources = ["src/**/*.rs"]
    outputs = ["dist/app"]
    cache = { enabled = true, env = ["CI"] }
  • task: dependency artifact keys now fold into a task's cache key, so downstream tasks reuse cached outputs when their dependencies resolve to the same artifacts, and an upstream input change correctly invalidates downstream results. (#11340 by @jdx)

  • task: result-only caching via outputs = [] for checks like lint, test, and typecheck that produce no files. Their successful result and replayable logs are cached without writing an archive. (#11351 by @jdx)

  • task: reusable and global cache inputs. Define named [task_config.input_groups] referenced from sources as @group:<name>, and task_config.global_inputs to apply config-rooted patterns to every task in scope, so shared lockfiles and toolchain files no longer need repeating per task. (#11356 by @jdx)

  • task: task_config.global_env for scoped environment inputs that participate in cache keys, plus pass_through_env / task_config.global_pass_through_env to keep selected ambient variables (like tokens) available under deny_env without affecting cache keys. (#11363 by @jdx)

  • task: outputs now support ordered ! exclusions and re-inclusions (mirroring sources), with \! escaping. Excluded paths are omitted from freshness hashes and cache archives, and existing excluded files are preserved on restore. (#11367 by @jdx)

  • task: task_config.shell sets a project-scoped default shell for tasks, with task-local and template shell still taking precedence. This gives users a safe migration path after the 2026.7.14 change that ignored project-level default shell-arg settings. (#11354 by @jdx)

  • config: registry idiomatic_files entries can now define structured version_regex, version_json_path, and version_expr parsers, adding in-process idiomatic version-file parsing for 11 tools including Dagger, Task, chezmoi, CMake, Earthly, golangci-lint, GoReleaser, Lefthook, Pixi, pre-commit, and Ruff. Parsing runs without executing plugin or shell code, and remains opt-in per tool. (#11341 by @jdx)

    mise settings add idiomatic_version_file_enable_tools dagger task lefthook
  • npm: new npm.package_manager = "aube_cli" mode installs npm: tools through a separately installed standalone Aube executable while mise still resolves versions itself, avoiding Aube's npm compatibility shim. The default embedded aube behavior is unchanged. (#11357 by @jdx)

  • deps: explicitly configured mise deps providers that are currently inapplicable now stay visible. mise deps --list shows an active/inactive status with a reason (e.g. inactive (missing package-lock.json)), and mise deps <provider> --explain or an explicit run fails with that reason instead of silently disappearing. (#11182 by @risu729)

Fixed

  • task: source_freshness_hash_contents = true now skips mtime comparison entirely, so tasks no longer re-run on every CI job after a cache restore resets timestamps. Output integrity is tracked with a content hash that also detects missing, partially deleted, and modified outputs. (#11319 by @rabadin)
  • task: confirming (or auto-confirming) the executable-bit prompt for a file task now runs the task in the same mise run, instead of chmod-ing the file and still failing with "no task found". Respects --yes, MISE_YES, and the trusted yes setting. (#11337 by @jdx)
  • task: circular dependency detection now runs on the fully resolved graph, so cycles through wait_for, {{usage.*}} dependencies, and depends_post are reported with a concrete path before any task runs, while valid post-dependency graphs are no longer rejected. (#11329 by @jdx)
  • task: $ ... task headers now display forwarded arguments accurately for inline and shebang tasks, no longer making multiline tasks appear to pass args to their first command. (#11344 by @jdx)
  • task: --output and MISE_TASK_OUTPUT overrides now honor raw and interactive tasks the same way task.output config does, fixing mixed command/timing output for tasks that need inherited stdio. (#11355 by @jdx)
  • brew: mise bootstrap packages upgrade no longer fails to link kegs when formulae were already installed and linked by real Homebrew. mise now recognizes brew's directory symlinks, resolves link targets one hop like brew does, and expands directory symlinks into real directories before linking. This also fixes second-upgrade failures for formulae shipping versioned dylib aliases in pure-mise setups. (#11320 by @mjun0812)
  • brew: mise bootstrap packages prune now correctly removes a keg's unversioned dylib alias links instead of leaving them dangling. (#11330 by @mjun0812)
  • env: ~/ paths now expand using the platform path separator, so Windows install and tool locations no longer surface mixed separators (e.g. C:\Users\me\.local/share/mise) through mise where, shims, and related output. (#11312 by @JamBalaya56562)
  • shell: mise activate pwsh now works under Set-StrictMode, guarding uninitialized globals that previously aborted activation, fixing a bare mise invocation, restoring chpwd hook chaining, and silencing command-not-found errors when PSReadLine is unavailable. (#11314 by @JamBalaya56562)
  • backend: a plugin whose backend is listed in disable_backends no longer shadows the registry entry, so a registry shorthand falls back to an enabled backend instead of failing to install. Already-installed tools keep reporting their recorded backend. (#11362 by @JamBalaya56562)
  • generate: mise generate task-docs --inject now errors with a clear message when the <!-- mise-tasks --> markers are missing or reversed, instead of truncating or clobbering the target file. (#11359 by @JamBalaya56562)
  • mcp: the MCP initialize response now reports the server as mise at mise's version, instead of inheriting rmcp's default identity. (#11361 by @jdx)

Documentation

  • settings: choice descriptions now render markdown. (#11335 by @jdx)
  • tasks: clarified shebang argument behavior. (#11336 by @jdx)
  • shims: documented how activate treats the shims directory with auto-install. (#11366 by @JamBalaya56562)

Registry

New Contributors

Full Changelog: v2026.7.14...v2026.7.15

💚 Sponsor mise

mise is maintained by @jdx, an open source developer for entire.io, the title sponsor of the jdx.dev open source tools. Development is funded by sponsors.

If mise saves you or your team time, please consider sponsoring at jdx.dev. Individual and company sponsorships keep mise fast, free, and independent.