feat(task): allow passing arguments to task dependencies via {{usage.*}} templates#8893
feat(task): allow passing arguments to task dependencies via {{usage.*}} templates#8893
Conversation
…*}} templates
Task dependencies can now reference parent task arguments using {{usage.*}}
templates. This enables patterns like:
[tasks.deploy]
usage = 'arg "<app>"'
depends = [{ task = "build", args = ["{{usage.app}}"] }]
run = 'echo "deploying {{usage.app}}"'
Running `mise run deploy myapp` will pass "myapp" to the build dependency.
Arguments flow through dependency chains (A -> B -> C) and work with both
positional args and flags.
Closes discussion #4331
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR introduces Key behaviors:
Confidence Score: 5/5Safe to merge — implementation is correct, prior review concerns have been addressed, and only minor P2 style suggestions remain. All P0/P1 concerns from previous review threads have been resolved: dep_has_usage_ref now correctly strips whitespace and matches {{usage. as a unit (no false positives), debug logging was added on parse failure, and the has_usage_deps guard properly inspects raw dep lists rather than just checking Option::is_some(). The two remaining findings are P2: a double-rendering of non-usage deps that is functionally a no-op in all realistic cases, and a mildly fragile echo-based test assertion. The e2e coverage is thorough (positional args, flags, parallel fan-out, string syntax, three-level chain) and all 563 unit tests pass. src/task/mod.rs (render_depends_with_usage re-renders all deps from raw); e2e/tasks/test_task_dep_args (echo "$output" assertion pattern) Important Files Changed
Sequence DiagramsequenceDiagram
participant CLI as mise run deploy myapp
participant Run as run.rs
participant TaskList as get_task_lists()
participant Mod as Task::render()
participant RDU as render_depends_with_usage()
participant Deps as Deps::new()
participant Resolve as resolve_depends()
CLI->>Run: task="deploy", args=["myapp"]
Run->>TaskList: get_task_lists(skip_deps=false)
TaskList->>Mod: task.render() for each task
Note over Mod: Saves depends_raw/depends_post_raw/wait_for_raw<br/>Defers deps with {{usage.*}} — renders rest
Mod-->>TaskList: tasks with deferred usage deps
TaskList-->>Run: task_list=[deploy(args=["myapp"])]
Run->>Run: For each task with args in task_list
Run->>Mod: parse_usage_values_from_task(deploy)<br/>→ {"app": "myapp"}
Run->>RDU: deploy.render_depends_with_usage({"app":"myapp"})
Note over RDU: Restores from depends_raw<br/>Renders "build {{usage.app}}" → task="build", args=["myapp"]
RDU-->>Run: deploy.depends = [build(args=["myapp"])]
Run->>Resolve: resolve_depends(task_list)
Resolve-->>Run: resolved_tasks
Run->>Deps: Deps::new(resolved_tasks)
loop For each task popped from stack
Deps->>Deps: has_usage_deps(task.depends_raw)?
alt task has args AND raw usage deps
Deps->>Mod: parse_usage_values_from_task(build)<br/>→ {"app": "myapp"}
Deps->>RDU: build.render_depends_with_usage({"app":"myapp"})
end
Deps->>Resolve: task.resolve_depends() — filters remaining {{usage.*}} deps
Deps->>Deps: add edges to graph
end
Deps-->>Run: dependency graph built
Reviews (3): Last reviewed commit: "[autofix.ci] apply automated fixes (atte..." | Re-trigger Greptile |
Add documentation for the new {{usage.*}} template support in task
dependencies, with examples for positional args, flags, string syntax,
and dependency chaining. Cross-reference from task-arguments.md.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request enables passing arguments and flags from a parent task to its dependencies using {{usage.*}} templates. It implements deferred rendering for dependency templates containing usage references, ensuring they are resolved only after the parent task's arguments are available. The changes include updates to the task model to store raw templates, logic in the CLI and dependency resolver to trigger re-rendering, and a new E2E test suite. Review feedback suggests simplifying the Tera context insertion by leveraging direct serialization and broadening the template reference detection to support a wider range of Tera syntax.
src/task/mod.rs
Outdated
| let usage_ctx: HashMap<String, tera::Value> = usage_values | ||
| .iter() | ||
| .map(|(k, v)| (k.clone(), tera::Value::String(v.clone()))) | ||
| .collect(); |
There was a problem hiding this comment.
The manual conversion of usage_values to a HashMap<String, tera::Value> is unnecessary. Tera's Context::insert can directly handle any type that implements serde::Serialize, and IndexMap<String, String> already does. This simplification avoids redundant allocations and cloning.
| let usage_ctx: HashMap<String, tera::Value> = usage_values | |
| .iter() | |
| .map(|(k, v)| (k.clone(), tera::Value::String(v.clone()))) | |
| .collect(); | |
| tera_ctx.insert("usage", usage_values); | |
src/task/mod.rs
Outdated
|
|
||
| /// Check if a TaskDep contains {{usage.*}} references that need deferred rendering. | ||
| fn dep_has_usage_ref(dep: &TaskDep) -> bool { | ||
| let has_ref = |s: &str| s.contains("{{") && s.contains("usage."); |
There was a problem hiding this comment.
The heuristic for detecting usage references in dependency templates is a bit narrow. It currently only checks for {{ tags and dot notation (e.g., usage.app). Tera also supports statement tags ({% ... %}) and bracket notation (e.g., usage['app']). Expanding this check will make the deferred rendering more robust for complex templates.
| let has_ref = |s: &str| s.contains("{{") && s.contains("usage."); | |
| let has_ref = |s: &str| { | |
| (s.contains("{{") || s.contains("{%") || s.contains("{#")) | |
| && (s.contains("usage.") || s.contains("usage[")) | |
| }; |
- Tighten dep_has_usage_ref to strip whitespace and check for
"{{usage." as a single substring (avoids false positives)
- Log debug message when usage parse fails instead of silently
swallowing the error
- Check if raw deps actually contain usage refs before calling
parse_usage_values_from_task (avoids unnecessary work)
- Simplify tera context insertion using direct serialize
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…errors
Wrap inline {{usage.*}} mentions with <span v-pre> so VitePress
doesn't try to parse them as Vue template interpolations.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 3f32496. Configure here.
- Check depends_post_raw and wait_for_raw (not just depends_raw) when deciding whether to re-render deps with usage values in Deps::new - Don't restore deps from raw templates if they were cleared by skip_deps, preventing unintended dependency execution Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.3 x -- echo |
22.4 ± 0.4 | 21.6 | 24.9 | 1.00 |
mise x -- echo |
22.9 ± 0.5 | 22.1 | 26.5 | 1.02 ± 0.03 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.3 env |
22.0 ± 0.7 | 21.1 | 27.1 | 1.00 |
mise env |
22.7 ± 0.6 | 21.7 | 26.0 | 1.03 ± 0.04 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.3 hook-env |
22.8 ± 0.5 | 21.8 | 24.8 | 1.00 |
mise hook-env |
23.4 ± 0.6 | 22.3 | 25.7 | 1.03 ± 0.03 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.4.3 ls |
19.8 ± 0.4 | 19.1 | 21.9 | 1.00 |
mise ls |
20.6 ± 0.5 | 19.5 | 23.3 | 1.04 ± 0.03 |
xtasks/test/perf
| Command | mise-2026.4.3 | mise | Variance |
|---|---|---|---|
| install (cached) | 149ms | 149ms | +0% |
| ls (cached) | 79ms | 78ms | +1% |
| bin-paths (cached) | 83ms | 83ms | +0% |
| task-ls (cached) | 806ms | 804ms | +0% |
### 🚀 Features - **(ci)** auto-convert external PRs to draft mode by @jdx in [#8896](#8896) - **(deps)** add `depends` field for user-specified tool dependencies by @cprecioso in [#8776](#8776) - **(dotnet)** support runtime-only installs by @fragon10 in [#8524](#8524) - **(npm)** apply install_before to transitive dependencies by @risu729 in [#8851](#8851) - **(task)** allow passing arguments to task dependencies via {{usage.*}} templates by @jdx in [#8893](#8893) - add options field to BackendListVersionsCtx by @esteve in [#8875](#8875) ### 🐛 Bug Fixes - **(backend)** filter PEP 440 .dev versions in fuzzy version matching by @richardthe3rd in [#8849](#8849) - **(ci)** update COPR BuildRequires rust version to match MSRV 1.88 by @jdx in [#8911](#8911) - **(ci)** add Ruby build dependencies to e2e Docker image by @jdx in [#8910](#8910) - **(ci)** add missing build dependencies to e2e Docker image by @jdx in [#8912](#8912) - **(ci)** add missing build dependencies to e2e Docker image by @jdx in [#8914](#8914) - **(ci)** use Node 24 LTS for corepack e2e test by @jdx in [#8915](#8915) - **(ci)** add libxml2 and pkg-config to e2e Docker image by @jdx in [#8917](#8917) - **(ci)** add libxml2-dev to e2e image and disable Swift SPM tests by @jdx in [#8918](#8918) - **(docs)** use sans-serif font for badges by @jdx in [#8887](#8887) - **(env)** parse --env=VALUE and -E=VALUE flag forms correctly by @jdx in [#8889](#8889) - **(exec)** use i64::from() for seccomp syscall numbers to survive autofix by @jdx in [#8882](#8882) - **(github)** preserve tool options like filter_bins when version specified via CLI by @jdx in [#8888](#8888) - **(github)** use alias-specific options when tool_alias has its own config by @jdx in [#8892](#8892) - **(install)** add locked_verify_provenance setting and detect github attestations at lock time by @jdx in [#8901](#8901) - **(lock)** prune stale version entries during filtered `mise lock <tool>` runs by @altendky in [#8599](#8599) - **(python)** use lockfile URL for precompiled installs by @hehaoqian in [#8750](#8750) - **(release)** verify all build targets succeed before releasing by @jdx in [#8886](#8886) - **(ruby)** support build revisions for precompiled binaries in mise.lock by @jdx in [#8900](#8900) - **(swift)** fall back to Ubuntu 24.04 for unsupported Ubuntu versions by @jdx in [#8916](#8916) - **(zsh)** avoid duplicate trust warning after cd by @timothysparg in [#8898](#8898) - update flake.lock and add fix for rust-bindgen to default.nix by @esteve in [#8874](#8874) - when direnv diff is empty, do not try to parse it by @yaleman in [#8857](#8857) - skip trust check for plain .tool-versions in task list by @dportalesr in [#8876](#8876) ### 🚜 Refactor - **(go)** rename go_* settings to go.* namespace by @jdbruijn in [#8598](#8598) ### 📚 Documentation - **(tasks)** clarify task_config.includes behavior by @risu729 in [#8905](#8905) ### 🧪 Testing - **(ci)** run e2e tests inside Docker containers by @jdx in [#8899](#8899) ### 📦️ Dependency Updates - bump ubi from 0.8 to 0.9 by @jdx in [#8906](#8906) - bump zip from 3 to 8 by @jdx in [#8908](#8908) - update lockfile deps (hold back rattler) by @jdx in [#8909](#8909) - update bun.lock by @jdx in [#8913](#8913) ### 📦 Registry - add turso ([github:tursodatabase/turso-cli](https://github.com/tursodatabase/turso-cli)) by @kenn in [#8884](#8884) - remove carp test by @jdx in [#8894](#8894) ### Chore - **(ci)** add workflow to warn PRs modifying vendored aqua-registry by @jdx in [#8897](#8897) - **(ci)** use github.token for draft conversion in auto-draft workflow by @jdx in [#8903](#8903) - remove deprecated settings older than 12 months by @jdx in [#8904](#8904) ### New Contributors - @dportalesr made their first contribution in [#8876](#8876) - @timothysparg made their first contribution in [#8898](#8898) - @hehaoqian made their first contribution in [#8750](#8750) - @jdbruijn made their first contribution in [#8598](#8598) - @cprecioso made their first contribution in [#8776](#8776) - @yaleman made their first contribution in [#8857](#8857) - @kenn made their first contribution in [#8884](#8884) - @fragon10 made their first contribution in [#8524](#8524) ## 📦 Aqua Registry Updates #### New Packages (6) - [`ahkohd/oyo`](https://github.com/ahkohd/oyo) - [`bellicose100xp/jiq`](https://github.com/bellicose100xp/jiq) - [`kurama/dealve-tui`](https://github.com/kurama/dealve-tui) - [`micahkepe/jsongrep`](https://github.com/micahkepe/jsongrep) - [`textfuel/lazyjira`](https://github.com/textfuel/lazyjira) - [`ubugeeei/vize`](https://github.com/ubugeeei/vize) #### Updated Packages (1) - [`sigstore/cosign`](https://github.com/sigstore/cosign)

Summary
{{usage.*}}templates independs,depends_post, andwait_forarg) and flags (flag), and with both string and structured dependency syntaxExample
Closes discussion #4331
Implementation
Dependency templates containing
{{usage.*}}are deferred during initial config loading (since CLI args aren't available yet). They are re-rendered later with actual usage values at two points:run.rs, before dependency graph constructionDeps::new()graph building, when a task receives args from its parentKey changes:
Taskstores raw (unrendered) dependency templates independs_raw/depends_post_raw/wait_for_rawrender_depends_with_usage()method re-renders deps with ausagecontextparse_usage_values_from_task()parses a task's usage spec against its args to extract named valuesresolve_depends,all_depends) skips deps with unresolved{{usage.*}}refsTest plan
test_task_dep_argscovering:depends = ["child {{usage.name}}"])🤖 Generated with Claude Code
Note
Medium Risk
Touches task dependency resolution and graph building to defer and later re-render dependency specs, which can affect what tasks run and with what args across chains. Added e2e coverage reduces risk but dependency parsing/rendering changes can have edge cases (e.g.,
skip_deps, mixed template/env syntax).Overview
Enables
{{usage.*}}templates insidedepends,depends_post, andwait_forso a task can forward its resolved usage args/flags to dependency tasks (including through multi-level dependency chains).Implements deferred rendering for dependency entries that reference
{{usage.*}}by preserving raw dependency templates onTask, skipping unresolved deps during initial resolution, then re-rendering them later once CLI/parent-provided args are known (duringmise runtask list creation and again while building the dependency graph).Adds an end-to-end test covering positional args, flags, string vs structured dependency syntax, fan-out dependencies, and chained forwarding, and updates docs to describe the new argument-forwarding behavior.
Reviewed by Cursor Bugbot for commit 076b9c5. Bugbot is set up for automated code reviews on this repo. Configure here.