fix(env): include watch_files in fast-path early exit check#8317
Conversation
The fast-path `should_exit_early_fast()` runs before config is loaded and only checked loaded_configs, tera_files, and data dir for changes. Files from `[[watch_files]]` patterns were not checked because they weren't stored in the session. This caused watch_files to only trigger on the first file change — subsequent changes were invisible to the fast-path, which would exit early before the full check could run. Store resolved watch_file paths in HookEnvSession and check them in the fast-path so file modifications are detected on every prompt. Closes #8264 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary of ChangesHello @jdx, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request resolves an issue where changes to files defined in Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
The pull request addresses a critical bug where watch_files run commands were not consistently triggering due to the fast-path early exit check. The changes correctly integrate watch_files into the HookEnvSession and the fast-path logic, ensuring that modifications to watched files are always detected. The solution is well-implemented and directly resolves the reported issue. The changes also include a minor refactoring to improve how watch_files are handled during session building, which is a good improvement for clarity and maintainability.
| // Check if any files from [[watch_files]] patterns have been modified | ||
| for path in &PREV_SESSION.watch_files { | ||
| if let Ok(metadata) = path.metadata() { | ||
| if let Ok(modified) = metadata.modified() | ||
| && mtime_to_millis(modified) > PREV_SESSION.latest_update | ||
| { | ||
| return false; | ||
| } | ||
| } else if !path.exists() { | ||
| return false; | ||
| } |
| /// Resolved file paths from [[watch_files]] config patterns. | ||
| /// Stored so the fast-path can detect changes without loading config. | ||
| #[serde(default)] | ||
| watch_files: Vec<PathBuf>, |
There was a problem hiding this comment.
Pull request overview
This PR updates the hook-env “fast-path” early-exit logic so that changes to files referenced by [[watch_files]] can be detected without loading config, preventing missed hook re-runs across repeated file edits.
Changes:
- Persist resolved
[[watch_files]]file paths intoHookEnvSession(__MISE_SESSIONpayload). - Extend
should_exit_early_fast()to stat the persisted watch-file paths alongside loaded config and tera-dependent files.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Check if any files from [[watch_files]] patterns have been modified | ||
| for path in &PREV_SESSION.watch_files { | ||
| if let Ok(metadata) = path.metadata() { | ||
| if let Ok(modified) = metadata.modified() | ||
| && mtime_to_millis(modified) > PREV_SESSION.latest_update | ||
| { |
There was a problem hiding this comment.
Fast-path only checks the previously resolved watch_files paths. For glob-based patterns (root: Some(...)), get_watch_files() resolves to the current matches only, so newly created files that match the glob after the session is built will not be in PREV_SESSION.watch_files and can be missed by the early-exit check. Consider also persisting the glob roots (and/or patterns) in the session and treating any root-dir mtime change as a reason to skip the fast-path so the full get_watch_files() re-glob can run.
| tera_files: config.tera_files.clone(), | ||
| watch_files: resolved_watch_files.into_iter().collect(), | ||
| loaded_configs, |
There was a problem hiding this comment.
HookEnvSession is serialized into the __MISE_SESSION environment variable; storing every resolved [[watch_files]] path here can grow the session payload significantly for broad glob patterns (and increase both serialization cost and per-prompt stat calls in should_exit_early_fast). It may be worth adding a guard/limit, or storing a more compact representation (e.g., roots + patterns / a digest) so large watch globs don’t risk hitting environment size limits or slowing the fast-path.
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.19 x -- echo |
24.0 ± 0.5 | 23.0 | 26.6 | 1.00 |
mise x -- echo |
24.3 ± 1.7 | 23.1 | 49.6 | 1.01 ± 0.07 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.19 env |
22.8 ± 0.6 | 21.8 | 28.5 | 1.00 ± 0.04 |
mise env |
22.7 ± 0.5 | 21.8 | 27.0 | 1.00 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.19 hook-env |
23.2 ± 0.4 | 22.4 | 26.5 | 1.00 |
mise hook-env |
23.4 ± 0.4 | 22.4 | 25.2 | 1.01 ± 0.02 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.19 ls |
20.7 ± 0.4 | 19.9 | 23.5 | 1.00 |
mise ls |
21.1 ± 0.6 | 20.1 | 25.4 | 1.02 ± 0.03 |
xtasks/test/perf
| Command | mise-2026.2.19 | mise | Variance |
|---|---|---|---|
| install (cached) | 126ms | 126ms | +0% |
| ls (cached) | 77ms | 77ms | +0% |
| bin-paths (cached) | 80ms | 80ms | +0% |
| task-ls (cached) | 813ms | -70% |
### 🚀 Features - **(conda)** replace custom backend with rattler crates by @jdx in [#8325](#8325) - **(task)** enforce per-task timeout configuration by @tvararu in [#8250](#8250) - **(vsix)** added vsix archives to http backend by @sosumappu in [#8306](#8306) - add core dotnet plugin for .NET SDK management by @jdx in [#8326](#8326) ### 🐛 Bug Fixes - **(conda)** preserve conda_packages on locked install and fix temp file race by @jdx in [#8335](#8335) - **(conda)** deduplicate repodata records to fix solver error on Linux by @jdx in [#8337](#8337) - **(env)** include watch_files in fast-path early exit check by @jdx in [#8317](#8317) - **(env)** clear fish completions when setting/unsetting shell aliases by @jdx in [#8324](#8324) - **(lockfile)** prevent lockfile writes when --locked is set by @jdx in [#8308](#8308) - **(lockfile)** prune orphan tool entries on mise lock by @mackwic in [#8265](#8265) - **(lockfile)** error on contradictory locked=true + lockfile=false config by @jdx in [#8329](#8329) - **(regal)** Update package location by @charlieegan3 in [#8315](#8315) - **(release)** strip markdown heading prefix from communique release title by @jdx in [#8303](#8303) - **(schema)** enforce additionalProperties constraint for env by @adamliang0 in [#8328](#8328) ### 📚 Documentation - Remove incorrect oh-my-zsh plugin ordering comment by @bvosk in [#8323](#8323) - require AI disclosure on GitHub comments by @jdx in [#8330](#8330) ### 📦 Registry - add `oxfmt` by @taoufik07 in [#8316](#8316) ### New Contributors - @adamliang0 made their first contribution in [#8328](#8328) - @tvararu made their first contribution in [#8250](#8250) - @bvosk made their first contribution in [#8323](#8323) - @taoufik07 made their first contribution in [#8316](#8316) - @charlieegan3 made their first contribution in [#8315](#8315) - @sosumappu made their first contribution in [#8306](#8306) ## 📦 Aqua Registry Updates #### New Packages (3) - [`Tyrrrz/FFmpegBin`](https://github.com/Tyrrrz/FFmpegBin) - [`elixir-lang/expert`](https://github.com/elixir-lang/expert) - [`erikjuhani/basalt`](https://github.com/erikjuhani/basalt) #### Updated Packages (5) - [`caarlos0/fork-cleaner`](https://github.com/caarlos0/fork-cleaner) - [`firecow/gitlab-ci-local`](https://github.com/firecow/gitlab-ci-local) - [`jackchuka/mdschema`](https://github.com/jackchuka/mdschema) - [`kunobi-ninja/kunobi-releases`](https://github.com/kunobi-ninja/kunobi-releases) - [`peco/peco`](https://github.com/peco/peco)
## Summary - Store resolved `[[watch_files]]` paths in `HookEnvSession` so the fast-path `should_exit_early_fast()` can detect changes without loading config - Check these paths in the fast-path alongside loaded_configs and tera_files The fast-path (`should_exit_early_fast()`) runs before config is loaded and previously only checked config files, tera files, and data dirs. Files from `[[watch_files]]` patterns were invisible to it because they weren't stored in the session. This caused `watch_files` run commands to only trigger on the first file change — subsequent changes were missed because the fast-path exited early before the full check could run. Closes jdx#8264 ## Test plan - [x] All unit tests pass (481 tests) - [x] All lints pass - [ ] Manual testing: configure `[[watch_files]]` with a pattern, touch the file multiple times, verify the run command triggers every time 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Small, localized change to hook-env cache invalidation logic; main risk is extra stat calls or incorrect session serialization affecting early-exit behavior. > > **Overview** > Fixes missed reruns for `[[watch_files]]` by making the hook-env fast-path consider watched file changes even before config is loaded. > > `HookEnvSession` now persists the resolved watch file paths, `build_session` captures them when computing `latest_update`, and `should_exit_early_fast()` stats these paths (alongside config and tera files) to prevent incorrect early exits when watched files change or are deleted. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 90fd6c3. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
### 🚀 Features - **(conda)** replace custom backend with rattler crates by @jdx in [jdx#8325](jdx#8325) - **(task)** enforce per-task timeout configuration by @tvararu in [jdx#8250](jdx#8250) - **(vsix)** added vsix archives to http backend by @sosumappu in [jdx#8306](jdx#8306) - add core dotnet plugin for .NET SDK management by @jdx in [jdx#8326](jdx#8326) ### 🐛 Bug Fixes - **(conda)** preserve conda_packages on locked install and fix temp file race by @jdx in [jdx#8335](jdx#8335) - **(conda)** deduplicate repodata records to fix solver error on Linux by @jdx in [jdx#8337](jdx#8337) - **(env)** include watch_files in fast-path early exit check by @jdx in [jdx#8317](jdx#8317) - **(env)** clear fish completions when setting/unsetting shell aliases by @jdx in [jdx#8324](jdx#8324) - **(lockfile)** prevent lockfile writes when --locked is set by @jdx in [jdx#8308](jdx#8308) - **(lockfile)** prune orphan tool entries on mise lock by @mackwic in [jdx#8265](jdx#8265) - **(lockfile)** error on contradictory locked=true + lockfile=false config by @jdx in [jdx#8329](jdx#8329) - **(regal)** Update package location by @charlieegan3 in [jdx#8315](jdx#8315) - **(release)** strip markdown heading prefix from communique release title by @jdx in [jdx#8303](jdx#8303) - **(schema)** enforce additionalProperties constraint for env by @adamliang0 in [jdx#8328](jdx#8328) ### 📚 Documentation - Remove incorrect oh-my-zsh plugin ordering comment by @bvosk in [jdx#8323](jdx#8323) - require AI disclosure on GitHub comments by @jdx in [jdx#8330](jdx#8330) ### 📦 Registry - add `oxfmt` by @taoufik07 in [jdx#8316](jdx#8316) ### New Contributors - @adamliang0 made their first contribution in [jdx#8328](jdx#8328) - @tvararu made their first contribution in [jdx#8250](jdx#8250) - @bvosk made their first contribution in [jdx#8323](jdx#8323) - @taoufik07 made their first contribution in [jdx#8316](jdx#8316) - @charlieegan3 made their first contribution in [jdx#8315](jdx#8315) - @sosumappu made their first contribution in [jdx#8306](jdx#8306) ## 📦 Aqua Registry Updates #### New Packages (3) - [`Tyrrrz/FFmpegBin`](https://github.com/Tyrrrz/FFmpegBin) - [`elixir-lang/expert`](https://github.com/elixir-lang/expert) - [`erikjuhani/basalt`](https://github.com/erikjuhani/basalt) #### Updated Packages (5) - [`caarlos0/fork-cleaner`](https://github.com/caarlos0/fork-cleaner) - [`firecow/gitlab-ci-local`](https://github.com/firecow/gitlab-ci-local) - [`jackchuka/mdschema`](https://github.com/jackchuka/mdschema) - [`kunobi-ninja/kunobi-releases`](https://github.com/kunobi-ninja/kunobi-releases) - [`peco/peco`](https://github.com/peco/peco)
Summary
[[watch_files]]paths inHookEnvSessionso the fast-pathshould_exit_early_fast()can detect changes without loading configThe fast-path (
should_exit_early_fast()) runs before config is loaded and previously only checked config files, tera files, and data dirs. Files from[[watch_files]]patterns were invisible to it because they weren't stored in the session. This causedwatch_filesrun commands to only trigger on the first file change — subsequent changes were missed because the fast-path exited early before the full check could run.Closes #8264
Test plan
[[watch_files]]with a pattern, touch the file multiple times, verify the run command triggers every time🤖 Generated with Claude Code
Note
Low Risk
Small, localized change to hook-env cache invalidation logic; main risk is extra stat calls or incorrect session serialization affecting early-exit behavior.
Overview
Fixes missed reruns for
[[watch_files]]by making the hook-env fast-path consider watched file changes even before config is loaded.HookEnvSessionnow persists the resolved watch file paths,build_sessioncaptures them when computinglatest_update, andshould_exit_early_fast()stats these paths (alongside config and tera files) to prevent incorrect early exits when watched files change or are deleted.Written by Cursor Bugbot for commit 90fd6c3. This will update automatically on new commits. Configure here.