Skip to content

feat(hooks): add task references to hooks and watch_files#8400

Merged
jdx merged 4 commits intomainfrom
feat/hooks-task-ref
Mar 2, 2026
Merged

feat(hooks): add task references to hooks and watch_files#8400
jdx merged 4 commits intomainfrom
feat/hooks-task-ref

Conversation

@jdx
Copy link
Copy Markdown
Owner

@jdx jdx commented Mar 1, 2026

Summary

  • Allow hooks and watch_files to reference mise tasks instead of inline scripts using { task = "name" } syntax
  • Tasks are executed as subprocesses via mise --cd <root> run <task>, which naturally respects MISE_NO_HOOKS=1 and reuses the full task system (deps, env, etc.)
  • Supports mixed arrays of scripts and task references: enter = ["echo hello", { task = "setup" }]

Closes #8392 (partial)

TOML syntax

# Hook with task reference
[hooks]
enter = { task = "setup" }

# Watch file with task reference
[[watch_files]]
patterns = ["uv.lock"]
task = "uv-deps"

Test plan

  • Unit: HookDef deserialization of TaskRef variant
  • E2E: test_hooks_task_ref — task runs on enter/leave/preinstall hooks, mixed script+task arrays
  • E2E: existing hook tests pass (test_hooks, test_hooks_error_handling, test_hooks_global)
  • Lint and build pass

🤖 Generated with Claude Code


Note

Medium Risk
Adds a new execution path that shells out to mise run during hook/watch execution, which can affect environment propagation and experimental feature gating. Risk is moderated by keeping existing script-based behavior intact and adding coverage plus schema validation.

Overview
Enables task-backed hooks by allowing [hooks] entries to reference a mise task via { task = "name" }, including mixed arrays of scripts and task refs; hook execution now dispatches either to existing inline script handling or to a new subprocess call to mise run (with MISE_NO_HOOKS=1 and the usual hook env vars).

Extends [[watch_files]] to support task = "..." as an alternative to run, validates this in the JSON schema (exactly one of run/task), and updates parsing to template-render task names. Adds docs and an e2e test covering task refs for enter/leave/preinstall and mixed script+task arrays.

Written by Cursor Bugbot for commit 18468a9. This will update automatically on new commits. Configure here.

Allow hooks and watch_files to reference mise tasks instead of inline
scripts using `{ task = "name" }` syntax. Tasks are executed as
subprocesses via `mise --cd <root> run <task>`, which naturally respects
MISE_NO_HOOKS and reuses the full task system (deps, env, etc.).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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 significantly enhances mise's automation capabilities by integrating its powerful task system directly into hooks and watch_files. This allows users to define more complex and reusable actions that are triggered by lifecycle events or file changes, leveraging mise's existing environment and dependency management for a more robust and streamlined workflow.

Highlights

  • Task References in Hooks: Introduced the ability for mise hooks (e.g., enter, leave, preinstall) to reference defined tasks using a { task = "name" } syntax in mise.toml.
  • Task References in Watch Files: Enabled watch_files configurations to trigger mise tasks when specified file patterns match, using a task = "name" syntax.
  • Unified Task Execution: Implemented task execution for both hooks and watch files as subprocesses via mise --cd <root> run <task>, ensuring proper environment setup, dependency resolution, and MISE_NO_HOOKS=1 respect.
  • Mixed Hook Arrays: Supported mixed arrays for hooks, allowing configurations to combine both inline scripts and task references within a single hook definition (e.g., enter = ["echo hello", { task = "setup" }]).
  • Schema Updates: Updated the mise.json schema to reflect the new configurations for hooks and watch_files, accommodating the task reference syntax.
Changelog
  • e2e/config/test_hooks_task_ref
    • Added a new end-to-end test to verify task references in enter, leave, and preinstall hooks, including mixed script and task arrays.
  • schema/mise.json
    • Updated the JSON schema to support task references within hooks definitions.
    • Modified the watch_files schema to include a task property.
  • src/config/config_file/mise_toml.rs
    • Modified MiseToml parsing logic to correctly handle task_name for hooks and task for watch_files, including template parsing.
  • src/hooks.rs
    • Introduced a TaskRef variant to the HookDef enum for deserializing task references.
    • Added a task_name field to the Hook struct to store the referenced task.
    • Updated the run_one_hook_with_context function to prioritize and execute tasks if a task_name is present, with a warning for conflicting shell and task_name.
    • Implemented the execute_task asynchronous function to run mise tasks as subprocesses, setting relevant environment variables like MISE_NO_HOOKS=1.
  • src/watch_files.rs
    • Modified the WatchFile struct to include an optional task field alongside the existing run field.
    • Updated execute_runs to check for and execute a task if specified, falling back to run if task is absent, and warning if neither is present.
    • Added an execute_task asynchronous function specifically for watch_files to run mise tasks, including MISE_WATCH_FILES_MODIFIED environment variable.
    • Removed commented-out ignore::WalkBuilder code.
Activity
  • No human activity has been recorded on this pull request yet.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a great new feature allowing hooks and watch_files to reference mise tasks directly. The implementation is solid, with good test coverage for the new functionality. I've made two suggestions for improvement: one to enhance the JSON schema for watch_files to be more strict, and another to ensure consistency in environment variable handling between hooks and watch_files.

Comment thread src/watch_files.rs
Comment on lines +129 to +132
env.insert(
"MISE_PROJECT_ROOT".to_string(),
root.to_string_lossy().to_string(),
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For consistency with how hooks are handled, consider setting the MISE_CONFIG_ROOT environment variable here as well. In hooks.rs, both MISE_PROJECT_ROOT and MISE_CONFIG_ROOT are set to the root path. This would also address the TODO in the execute function in this file.

Suggested change
env.insert(
"MISE_PROJECT_ROOT".to_string(),
root.to_string_lossy().to_string(),
);
env.insert(
"MISE_PROJECT_ROOT".to_string(),
root.to_string_lossy().to_string(),
);
env.insert(
"MISE_CONFIG_ROOT".to_string(),
root.to_string_lossy().to_string(),
);

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 1, 2026

Greptile Summary

This PR adds task reference support to hooks and watch_files, allowing configuration like enter = { task = "setup" } instead of inline scripts. Tasks execute as subprocesses via mise --cd <root> run <task>, properly setting MISE_NO_HOOKS=1 to prevent recursion.

Key Changes:

  • Added TaskRef variant to HookDef enum for deserializing task references
  • Added execute_task functions in both hooks.rs and watch_files.rs
  • Updated JSON schema to support task references in both hooks and watch_files
  • Comprehensive E2E tests for hooks with task references (enter, leave, preinstall, mixed arrays)

Areas for Improvement:

  • watch_files.rs silently prefers task when both task and run are set, unlike hooks which warns about conflicts
  • Missing E2E test coverage for watch_files with task references (only hooks are tested)
  • JSON schema allows invalid states for watch_files (both or neither run/task can be set)

Confidence Score: 4/5

  • Safe to merge with minor inconsistencies in error handling and test coverage
  • Core implementation is solid with proper recursion prevention and good test coverage for hooks. Minor issues: watch_files lacks warning for conflicting fields and missing E2E tests. Schema validation could be stricter. No blocking issues.
  • src/watch_files.rs needs test coverage for task references and consider adding warning when both run and task are set

Important Files Changed

Filename Overview
src/hooks.rs Added TaskRef variant to HookDef enum and execute_task function. Properly handles task execution with MISE_NO_HOOKS=1 to prevent recursion. Warns when both task and shell are set.
src/watch_files.rs Added task field to WatchFile and execute_task function. Silently prefers task over run when both are set (no warning). Missing test coverage for task references.
src/config/config_file/mise_toml.rs Updated template parsing to handle optional task fields in watch_files and hooks. Clean implementation with proper error handling.
schema/mise.json Extended JSON schema to support task references in hooks and watch_files. Allows invalid states (both or neither run/task in watch_files).
e2e/config/test_hooks_task_ref Comprehensive tests for hooks with task references (enter, leave, preinstall, mixed arrays). Does not test watch_files with task references.

Sequence Diagram

sequenceDiagram
    participant User
    participant mise
    participant Hook System
    participant Task Executor
    participant Task
    
    User->>mise: trigger hook (e.g., enter directory)
    mise->>Hook System: run_one_hook_with_context()
    
    alt Hook has task reference
        Hook System->>Hook System: Check h.task_name.is_some()
        Hook System->>Task Executor: execute_task()
        Note over Task Executor: Set MISE_NO_HOOKS=1<br/>to prevent recursion
        Task Executor->>Task Executor: cmd("mise", ["--cd", root, "run", task_name])
        Task Executor->>Task: Execute task as subprocess
        Task-->>Task Executor: Task output
        Task Executor-->>Hook System: Result
    else Hook has script
        Hook System->>Hook System: execute()
        Note over Hook System: Render template<br/>and run script
        Hook System-->>mise: Result
    end
    
    Hook System-->>mise: Hook completed
    mise-->>User: Continue
Loading

Fix All in Claude Code

Last reviewed commit: 7df3342

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment thread src/watch_files.rs
Comment on lines +45 to +51
let result = if let Some(task_name) = &wf.task {
execute_task(config, ts, &root, task_name, files).await
} else if let Some(run) = &wf.run {
execute(config, ts, &root, run, files).await
} else {
warn!("watch_file hook has neither run nor task set, skipping");
continue;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Silently prefers task when both task and run are set. Consider adding a warning for consistency with hooks.rs:225-230 which warns when both task and shell are set.

Fix in Claude Code

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 1, 2026

Additional Comments (1)

schema/mise.json
The schema allows both run and task to be absent or both to be present. Consider adding validation (e.g., oneOf or required) to enforce that exactly one must be set.

Fix in Claude Code

Comment thread src/watch_files.rs
Comment thread src/hooks.rs Outdated
Comment thread schema/mise.json
jdx and others added 3 commits March 1, 2026 23:49
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add warning in watch_files when both run and task are set
- Remove unreachable task+shell guard in hooks (serde untagged makes it
  impossible)
- Fix schema oneOf overlap for hooks by removing redundant string array
  variant
- Add oneOf constraint to watch_files schema enforcing exactly one of
  run/task

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jdx
Copy link
Copy Markdown
Owner Author

jdx commented Mar 2, 2026

bugbot run

@halms
Copy link
Copy Markdown
Contributor

halms commented Mar 2, 2026

Shouldn't this also be extended to (custom) prepare steps?
Allowing task instead of run?

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

@jdx
Copy link
Copy Markdown
Owner Author

jdx commented Mar 2, 2026

not sure about that yet, I think in general prepare steps should not be using tasks since they shouldn't be that complicated

@jdx jdx merged commit 1c7244e into main Mar 2, 2026
37 checks passed
@jdx jdx deleted the feat/hooks-task-ref branch March 2, 2026 00:17
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 2, 2026

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.24 x -- echo 28.9 ± 0.7 27.7 31.6 1.18 ± 0.04
mise x -- echo 24.5 ± 0.6 23.2 26.3 1.00
✅ Performance improvement for x -- echo is 18%

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.24 env 29.0 ± 0.9 27.3 36.1 1.23 ± 0.05
mise env 23.5 ± 0.5 22.6 25.4 1.00
✅ Performance improvement for env is 23%

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.24 hook-env 29.8 ± 0.8 28.2 34.0 1.22 ± 0.04
mise hook-env 24.4 ± 0.5 23.4 27.0 1.00
✅ Performance improvement for hook-env is 22%

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.24 ls 23.9 ± 0.6 22.4 27.8 1.07 ± 0.04
mise ls 22.3 ± 0.7 21.2 27.3 1.00

xtasks/test/perf

Command mise-2026.2.24 mise Variance
install (cached) 166ms 153ms +8%
ls (cached) 91ms 83ms +9%
bin-paths (cached) 99ms ✅ 87ms +13%
task-ls (cached) 845ms 829ms +1%

✅ Performance improvement: bin-paths cached is 13%

jdx pushed a commit that referenced this pull request Mar 2, 2026
### 🚀 Features

- **(hooks)** add task references to hooks and watch_files by @jdx in
[#8400](#8400)
- **(prepare)** add git-submodule built-in provider by @jdx in
[#8407](#8407)
- **(prepare)** add human-readable stale reasons to prepare output by
@jdx in [#8408](#8408)
- **(prepare)** add dependency ordering to prepare steps by @jdx in
[#8401](#8401)
- **(prepare)** add --explain flag for provider diagnostics by @jdx in
[#8409](#8409)
- **(prepare)** add per-provider timeout support by @jdx in
[#8405](#8405)
- **(prepare)** add blake3 content-hash freshness checking by @jdx in
[#8404](#8404)
- **(tasks)** monorepo vars and per-task vars by @halms in
[#8248](#8248)

### 🐛 Bug Fixes

- **(aqua)** restore bin_paths disk cache with fresh_file invalidation
by @jdx in [#8398](#8398)
- **(idiomatic)** use generic parser for idiomatic files by @risu729 in
[#8171](#8171)
- **(install)** apply precompiled options to all platforms in lockfile
by @jdx in [#8396](#8396)
- **(install)** normalize "v" prefix when matching lockfile versions by
@jdx in [#8413](#8413)
- **(prepare)** improve git submodule parser and fix check_staleness
error handling by @jdx in [#8412](#8412)
- **(python)** respect precompiled settings in lock file generation by
@jdx in [#8399](#8399)
- **(python)** clarify uv_venv_auto docs + prevent uv shim recursion in
venv creation by @halms in
[#8402](#8402)
- **(task)** remove deprecated `# mise` task header syntax by @jdx in
[#8403](#8403)
- **(vfox)** avoid eager metadata loading during config file detection
by @jdx in [#8397](#8397)
- clarify GitHub attestations to be artifact ones by @scop in
[#8394](#8394)
- ignore comments in idiomatic version files by @iloveitaly in
[#7682](#7682)

### 🚜 Refactor

- unify archive detection by @risu729 in
[#8137](#8137)

### 📚 Documentation

- remove duplicated docs for npm.package_manager by @risu729 in
[#8414](#8414)
@reitzig
Copy link
Copy Markdown
Contributor

reitzig commented Mar 2, 2026

❔ This enables us to reference tasks by name, but not pass parameters to it, correct?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants