Skip to content

fix(task): install monorepo subdir tools before running deps#9454

Merged
jdx merged 1 commit intomainfrom
claude/bold-hofstadter-b570eb
Apr 28, 2026
Merged

fix(task): install monorepo subdir tools before running deps#9454
jdx merged 1 commit intomainfrom
claude/bold-hofstadter-b570eb

Conversation

@jdx
Copy link
Copy Markdown
Owner

@jdx jdx commented Apr 28, 2026

Summary

Fixes #9445: in a monorepo, running a task from the root via mise //sub:taskname failed when sub/mise.toml declared both a tool and an auto [deps] provider that used it (e.g. bun = \"latest\" + [deps.bun] auto=true). The deps step ran before the subdirectory's tool was installed, so bun install died with No such file or directory.

The user-reported workaround was running mise -C sub/ deps once so .mise/deps-state.toml skipped the broken path on subsequent runs.

Root cause

In Run::run (src/cli/run.rs):

  1. get_task_lists correctly loaded subdirectory tasks via TaskLoadContext.
  2. ToolsetBuilder::build(&config) was then called against config.config_files only — which contains the root hierarchy when invoked from the monorepo root, not sub/mise.toml.
  3. install_missing_versions ran on that incomplete toolset (no bun).
  4. Only then did resolve_depends populate task.cf with the subdirectory configs, which were dutifully passed to DepsEngine::add_config_files — too late: install had already finished.
  5. engine.run({ auto_only: true }) invoked bun install, which couldn't find bun.

Fix

Reorder so resolve_depends runs before the toolset is built, then collect subdirectory configs from the resolved tasks (task.cf), merge them into a ConfigMap together with config.config_files, and pass the result to the existing ToolsetBuilder::with_config_files(...) API. Subdir tools are now installed before any [deps] step runs. The deps engine continues to receive the same subdir configs as before.

No new APIs; with_config_files already existed on ToolsetBuilder.

The "naked run that does not match a task should fail without installing project tools" invariant still holds — resolve_depends runs after get_task_lists, and any failure short-circuits before the toolset is touched.

Out of scope

Config::get_toolset() is a separate lazily-cached toolset used by usage-spec parsing; it still reflects only the root hierarchy. Extending it to monorepo subdirs has wider blast radius (env, aliases, every parse_usage_values_from_task call) and is not needed to fix this bug.

Test plan

  • Reproduced the reported failure on the released mise (homebrew) and confirmed the fix resolves it on the worktree binary using a tiny/rtx-tiny minimal repro mirroring the discussion.
  • Added a regression e2e test: e2e/tasks/test_task_monorepo_deps_tool_install (uses the tiny tool + a [deps] step that invokes rtx-tiny, all from the monorepo root via //sub:use-tiny).
  • mise run test:e2e tasks/test_task_monorepo — all monorepo task tests pass.
  • mise run test:e2e cli/test_deps cli/test_deps_tool_install cli/test_deps_depends tasks/test_task_deps — pass.
  • mise run test:unit — 785/785 pass.
  • mise run lint-fix and cargo clippy --all-targets -- -D warnings clean.

🤖 Generated with Claude Code


Note

Medium Risk
Changes mise run execution ordering and toolset construction, which can affect tool installation and dependency steps across projects (especially monorepos). Scope is localized to the run path but touches core task/deps orchestration.

Overview
Fixes mise run //sub:task in monorepos by resolving task dependencies before building/installing the toolset, then merging resolved tasks’ subdirectory config files into the toolset’s config map so subdir-declared tools are on PATH before auto [deps] steps execute.

Adds an e2e regression test that sets up a monorepo root + sub/mise.toml with a subdir tool (tiny) and an auto [deps] step that uses it, asserting the tool is installed and both deps and task execution succeed from the repo root.

Reviewed by Cursor Bugbot for commit ad6aec9. Bugbot is set up for automated code reviews on this repo. Configure here.

When running a monorepo task from the root via `mise //sub:taskname`,
tools declared in `sub/mise.toml` were not installed before auto
`[deps]` steps ran. Providers like `[deps.bun] auto=true` then failed
with "No such file or directory" because `bun` wasn't on PATH yet.

Reorder `Run::run` so `resolve_depends` runs before the toolset is
built. The subdirectory config files attached to each resolved task
(`task.cf`) are now combined with `config.config_files` and passed to
`ToolsetBuilder::with_config_files`, so subdir tools get installed
before any deps step runs. The deps engine continues to receive the
same subdir configs as before.

Fixes #9445

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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 fixes a bug in monorepo task execution where tools defined in subdirectory configuration files were not being installed before dependency steps were run. The toolset construction logic in src/cli/run.rs has been moved to follow task resolution, ensuring that all relevant configuration files from sub-tasks are included. Additionally, a regression test has been added to validate that tools from subdirectories are correctly installed and available on the PATH for dependency execution. I have no feedback to provide as there were no review comments.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 28, 2026

Greptile Summary

This PR fixes a monorepo bug where mise //sub:taskname would fail if sub/mise.toml declared both a tool and an auto [deps] step that used it. The root cause was that ToolsetBuilder was built before resolve_depends ran, so subdirectory tools were never installed before the deps stage tried to invoke them.

The fix reorders Run::run so resolve_depends runs first, then collects task.cf configs from the resolved tasks and merges them into config.config_files before calling ToolsetBuilder::with_config_files(combined_configs). This ensures subdir tools are installed before any [deps] step executes.

Confidence Score: 5/5

Safe to merge — targeted reordering of resolve_depends before toolset build, with no new APIs and a dedicated regression test.

No P0 or P1 issues found. The reordering preserves the "no matching task → no tool install" invariant. Config merging via or_insert_with correctly deduplicates root and subdir entries. The test is sourced (not executed) by the runner, so the missing executable bit is harmless. All existing monorepo tests were reported passing.

No files require special attention.

Important Files Changed

Filename Overview
src/cli/run.rs Reorders resolve_depends before toolset build; merges subdir configs into combined_configs via with_config_files — logic is correct and the "no task → no install" invariant is preserved.
e2e/tasks/test_task_monorepo_deps_tool_install New regression test that exercises the exact reported failure path (tiny installed after resolve_depends, deps step uses rtx-tiny); file is sourced by the test runner so missing execute bit is harmless.

Sequence Diagram

sequenceDiagram
    participant RunRun as Run::run
    participant GTL as get_task_lists
    participant RD as resolve_depends
    participant TB as ToolsetBuilder
    participant IM as install_missing_versions
    participant DE as DepsEngine

    RunRun->>GTL: get_task_lists(config, args)
    GTL-->>RunRun: task_list (with subdir tasks via task.cf)

    Note over RunRun: NEW ORDER (after fix)
    RunRun->>RD: resolve_depends(config, task_list)
    RD-->>RunRun: resolved_tasks (task.cf = sub/mise.toml)

    RunRun->>RunRun: collect subdir_configs from task.cf
    RunRun->>RunRun: combined_configs = root config_files + subdir_configs

    RunRun->>TB: ToolsetBuilder::with_config_files(combined_configs).build()
    TB-->>RunRun: ts (includes sub/mise.toml tools e.g. bun/tiny)

    RunRun->>IM: ts.install_missing_versions()
    Note over IM: Installs bun/tiny BEFORE deps run

    RunRun->>DE: DepsEngine::new + add_config_files(subdir_configs)
    DE->>DE: engine.run(auto_only=true)
    Note over DE: bun/rtx-tiny now on PATH

    RunRun->>RunRun: parallelize_tasks(resolved_tasks)
Loading

Reviews (1): Last reviewed commit: "fix(task): install monorepo subdir tools..." | Re-trigger Greptile

@jdx jdx enabled auto-merge (squash) April 28, 2026 16:40
@jdx jdx merged commit 1d5513c into main Apr 28, 2026
38 checks passed
@jdx jdx deleted the claude/bold-hofstadter-b570eb branch April 28, 2026 16:43
@github-actions
Copy link
Copy Markdown

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.25 x -- echo 21.6 ± 1.0 20.8 40.9 1.00
mise x -- echo 21.7 ± 0.5 20.9 25.7 1.00 ± 0.05

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.25 env 21.1 ± 0.9 20.3 31.2 1.00 ± 0.04
mise env 21.1 ± 0.3 20.5 22.5 1.00

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.25 hook-env 21.8 ± 0.7 21.0 34.6 1.00
mise hook-env 21.9 ± 0.4 21.1 24.8 1.00 ± 0.04

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.25 ls 22.1 ± 0.5 21.5 26.5 1.00
mise ls 22.3 ± 1.0 21.3 36.3 1.01 ± 0.05

xtasks/test/perf

Command mise-2026.4.25 mise Variance
install (cached) 154ms 152ms +1%
ls (cached) 79ms 78ms +1%
bin-paths (cached) 79ms 79ms +0%
task-ls (cached) 824ms 801ms +2%

mise-en-dev added a commit that referenced this pull request Apr 29, 2026
### 🚀 Features

- **(deps)** add aube provider by @jdx in
[#9452](#9452)
- **(ls-remote)** add strict metadata mode by @jdx in
[#9448](#9448)

### 🐛 Bug Fixes

- **(env)** parse concatenated short form `-Eval` correctly by @bts in
[#9456](#9456)
- **(http)** improve HTML detection by using Content-Type header by
@phateffect in [#9407](#9407)
- **(task)** install monorepo subdir tools before running deps by @jdx
in [#9454](#9454)

### 📦️ Dependency Updates

- update astral-tokio-tar advisory by @jdx in
[#9449](#9449)
- respect -q flag for provider command stream by @JamBalaya56562 in
[#9457](#9457)

### New Contributors

- @JamBalaya56562 made their first contribution in
[#9457](#9457)
- @bts made their first contribution in
[#9456](#9456)
- @phateffect made their first contribution in
[#9407](#9407)

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
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.

1 participant