Skip to content

fix(task): forward task help args and add raw_args#9118

Merged
jdx merged 4 commits intomainfrom
fix/task-help-passthrough
Apr 16, 2026
Merged

fix(task): forward task help args and add raw_args#9118
jdx merged 4 commits intomainfrom
fix/task-help-passthrough

Conversation

@jdx
Copy link
Copy Markdown
Owner

@jdx jdx commented Apr 15, 2026

Summary

  • Forward task-side --help/-h after -- to the task instead of letting the usage parser intercept it.
  • Add raw_args = true for task definitions and file headers so proxy tasks can skip mise/usage argument parsing entirely.
  • Treat -- as the single boundary between mise parsing and task parsing: mise run task -- -- --help forwards -- --help to the task.
  • Keep non-run subcommands intact when their command args contain a literal run after --, such as mise exec -- npm run test --help.

Refs #5460.

Behavior

[tasks.manage]
raw_args = true
run = 'python manage.py'
mise run manage --help            # forwarded to manage.py
mise run manage migrate --fake    # all flags reach manage.py unchanged
mise run othertask -- --help      # forwarded ad hoc, no raw_args needed
mise run othertask -- -- --help   # forwarded as -- --help

mise run task --help without -- and without raw_args still shows mise task help.

Validation

  • cargo test --all-features cli::tests::test_escape_task_args_ignores_run_after_subcommand_separator
  • cargo fmt --check
  • git diff --check
  • target/debug/mise run test:e2e e2e/tasks/test_task_raw_args
  • target/debug/mise run test:e2e e2e/tasks/test_task_help
  • target/debug/mise exec -- bash -c 'printf "%s\n" "$*"' _ npm run test --help
  • pre-commit hk checks during amend

This PR description was updated by Codex.


Note

Medium Risk
Changes core CLI argument preprocessing and task usage parsing, which can subtly affect how flags are routed between mise and tasks across multiple invocation forms.

Overview
Task execution now supports argument passthrough via new raw_args = true, causing tasks to skip mise/usage argument parsing so all flags (including --help/-h) reach the underlying command.

Separately, CLI preprocessing was adjusted so a literal -- is treated as the boundary between mise and task parsing: -- --help bypasses the usage parser (even when a usage spec exists), -- -- --help forwards -- --help, and non-run subcommands with their own -- tails are left untouched. Docs, JSON schemas, and e2e/unit tests were updated to cover the new behavior and edge cases.

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

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 raw_args configuration for tasks, allowing them to act as thin proxies by bypassing mise's argument parsing and forwarding all arguments, including --help and -h, directly to the underlying command. It also implements an escape hatch where arguments following a literal -- separator bypass the usage parser. The review feedback highlights an inconsistency in how subcommands are handled during the parser bypass check and recommends refactoring the duplicated bypass logic into a dedicated Task method to improve maintainability.

Comment thread src/task/mod.rs Outdated
.trailing_args
.iter()
.any(|a| a == "--help" || a == "-h");
if !bypass_parser && has_any_args_defined(&spec) {
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.

high

The condition has_any_args_defined(&spec) is inconsistent with the check in src/task/task_executor.rs. This check misses spec.cmd.subcommands, which can lead to incorrect argument parsing for tasks that only define subcommands.

To ensure consistent behavior, I recommend updating this to match the more comprehensive check in task_executor.rs.

Suggested change
if !bypass_parser && has_any_args_defined(&spec) {
if !bypass_parser && (!spec.cmd.args.is_empty() || !spec.cmd.flags.is_empty() || !spec.cmd.subcommands.is_empty()) {

Comment thread src/task/mod.rs Outdated
Comment on lines +878 to +882
let bypass_parser = self.raw_args
|| self
.trailing_args
.iter()
.any(|a| a == "--help" || a == "-h");
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

This logic for determining whether to bypass the usage parser is duplicated in src/task/task_executor.rs. To improve maintainability and prevent future inconsistencies, consider extracting this into a new method on the Task struct.

For example, you could add this method to impl Task:

pub fn should_bypass_usage_parser(&self) -> bool {
    self.raw_args
        || self
            .trailing_args
            .iter()
            .any(|a| a == "--help" || a == "-h")
}

Then you can call this method here and in task_executor.rs.

Suggested change
let bypass_parser = self.raw_args
|| self
.trailing_args
.iter()
.any(|a| a == "--help" || a == "-h");
let bypass_parser = self.should_bypass_usage_parser();

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 15, 2026

Greptile Summary

This PR adds raw_args = true for task definitions (TOML and #MISE file headers) so proxy tasks skip mise's usage/argument parser entirely, and fixes the -- --help/-- -h escape hatch so arguments after a literal -- bypass the usage crate rather than being intercepted by it. The should_bypass_usage_parser helper consolidates a previously duplicated predicate, and escape_args_after_separator / first_non_global_arg_idx reduce duplication across arg-preprocessing functions.

Confidence Score: 5/5

Safe to merge — no blocking issues found; all changed paths are exercised by e2e tests and the previous P1 predicate-duplication concern is resolved.

All remaining findings are P2 or lower. Core logic (escape/unescape round-trip, bypass predicate, raw_args passthrough) is internally consistent and verified by unit and e2e tests.

No files require special attention.

Important Files Changed

Filename Overview
src/cli/mod.rs Refactors escape_task_args and preprocess_args_for_naked_run into reusable helpers; changes -- handling to escape args after separator; adds four unit tests.
src/cli/run.rs Adds unescape for args_last, records trailing_args, gates early-help-return on !task.raw_args.
src/task/mod.rs Adds raw_args/trailing_args fields and should_bypass_usage_parser() helper.
src/task/task_executor.rs Uses should_bypass_usage_parser() to gate usage env-var population.
e2e/tasks/test_task_raw_args New e2e test for raw_args and -- --help bypass.

Reviews (8): Last reviewed commit: "fix(task): preserve passthrough help arg..." | Re-trigger Greptile

Comment thread src/cli/run.rs
Comment thread src/task/mod.rs Outdated
Comment thread e2e/tasks/test_task_raw_args
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 15, 2026

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.15 x -- echo 23.8 ± 0.5 23.1 30.6 1.00
mise x -- echo 24.5 ± 0.6 23.6 28.6 1.03 ± 0.03

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.15 env 23.3 ± 0.7 22.5 30.9 1.00
mise env 24.2 ± 0.5 22.9 26.0 1.04 ± 0.04

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.15 hook-env 24.5 ± 0.4 23.6 25.8 1.00
mise hook-env 25.1 ± 0.5 24.2 27.2 1.03 ± 0.02

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.4.15 ls 21.4 ± 0.4 20.4 22.9 1.00
mise ls 22.3 ± 0.8 21.2 33.2 1.04 ± 0.04

xtasks/test/perf

Command mise-2026.4.15 mise Variance
install (cached) 155ms 155ms +0%
ls (cached) 81ms 82ms -1%
bin-paths (cached) 86ms 87ms -1%
task-ls (cached) 793ms 779ms +1%

jdx and others added 2 commits April 15, 2026 15:05
The usage crate intercepts --help even when passed after `--`, so the
documented escape hatch (`mise run task -- --help`) didn't actually reach
the underlying script. This broke tasks that proxy tools with their own
argument parsers (Django manage.py, next build, argparse scripts).

Two changes:

1. `mise run task -- --help` (or `-- -h`) now bypasses the usage parser
   so --help reaches the script. Other args after `--` continue to be
   parsed as before.

2. New `raw_args = true` task option that always skips mise's argument
   parsing (including the --help interception in `mise run task --help`).
   Use this for thin proxy tasks where the underlying tool fully owns
   argument handling.

Refs #5460

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Address review feedback on #9118:

- Extract the usage-parser bypass condition into
  `Task::should_bypass_usage_parser()` so the rule lives in one place
  instead of being duplicated across `render_run_scripts_with_args` and
  `parse_usage_spec_and_init_env`.

- Honor an inner `--` inside the trailing args as an escape hatch:
  `mise run task -- -- --help` stops the bypass scan at the inner `--`
  so the usage parser sees `--help` as a literal positional value
  instead of triggering the help passthrough.

- Extend `test_task_raw_args` with a file-task variant that exercises a
  real `\$@` proxy (inline TOML scripts can't, since args are appended
  to the command string) and with the inner-`--` escape case.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jdx jdx force-pushed the fix/task-help-passthrough branch from d52124a to 72040d1 Compare April 15, 2026 15:11
@jdx
Copy link
Copy Markdown
Owner Author

jdx commented Apr 15, 2026

Rebased on main and pushed a fixup commit addressing review feedback:

Addressed:

  • Extracted the bypass predicate into Task::should_bypass_usage_parser() so the rule lives in one place (Greptile P2 / Gemini medium).
  • Added an inner--- escape hatch: mise run task -- -- --help stops the bypass scan at the second --, so the usage parser sees --help as a literal positional value instead of triggering the help passthrough.
  • Added a file-task variant to test_task_raw_args so we exercise a real \$@ proxy script (inline TOML scripts can't — args are appended to the command string, not passed as positional parameters). Greptile was right that the inline assertion passed for the wrong reason.

Intentional / not changed:

  • The bypass for -- <flag> only triggers on --help/-h, not on arbitrary flags. Widening it to "any flag after --" would silently change semantics for existing users who rely on -- --foo going through the usage parser (covered by test_task_options, test_task_flag_parsing, etc.). The raw_args = true opt-in is the documented full-passthrough escape hatch.
  • has_any_args_defined vs the explicit args/flags/subcommands check in task_executor.rs: this inconsistency is pre-existing, not introduced by this PR. Worth fixing in a follow-up but I'd rather keep this PR scoped.

CI failure (e2e-7): unrelated — env/test_env_module_tools_no_spurious_warning is failing because installing github:jdx/fnox@1.20.0 hits Verification failed: Invalid certificate issuer: expected sigstore, got 'Fulcio Intermediate l1'. Reproduces locally on this branch and on main, so it's a pre-existing sigstore/Fulcio attestation issue, not something this PR touched.

This comment was generated by Claude Code.

@jdx jdx enabled auto-merge (squash) April 16, 2026 00:57
@jdx jdx disabled auto-merge April 16, 2026 02:09
Comment thread src/task/mod.rs
Comment thread src/task/mod.rs
@jdx jdx force-pushed the fix/task-help-passthrough branch from 2c2af01 to 7e12df3 Compare April 16, 2026 12:52
Comment thread src/cli/mod.rs
@jdx jdx force-pushed the fix/task-help-passthrough branch from 7e12df3 to 876f85c Compare April 16, 2026 13:07
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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 876f85c. Configure here.

Comment thread src/cli/mod.rs
@jdx jdx force-pushed the fix/task-help-passthrough branch from 876f85c to 62feb23 Compare April 16, 2026 13:32
@jdx jdx changed the title fix(task): pass --help through to tasks via -- and add raw_args opt-in fix(task): forward task help args and add raw_args Apr 16, 2026
@jdx jdx force-pushed the fix/task-help-passthrough branch from 62feb23 to 0afc58e Compare April 16, 2026 13:36
@jdx jdx force-pushed the fix/task-help-passthrough branch from 0afc58e to 846510f Compare April 16, 2026 13:52
@jdx jdx merged commit c4b11b5 into main Apr 16, 2026
37 checks passed
@jdx jdx deleted the fix/task-help-passthrough branch April 16, 2026 15:27
mise-en-dev added a commit that referenced this pull request Apr 17, 2026
### 🚀 Features

- **(registry)** add .perl-version support for perl by @ergofriend in
[#9102](#9102)
- **(task)** add Tera template support for inline table run tasks by
@iamkroot in [#9079](#9079)

### 🐛 Bug Fixes

- **(env)** use runtime symlink paths for fuzzy versions by @jdx in
[#9143](#9143)
- **(github)** use full token resolution chain for attestation
verification by @jdx in [#9154](#9154)
- **(go)** Remove install-time version override for subpath packages by
@c22 in [#9135](#9135)
- **(npm)** respect install_before when resolving dist-tag versions by
@webkaz in [#9145](#9145)
- **(self-update)** ensure subcommand exists by @salim-b in
[#9144](#9144)
- **(task)** show available tasks when run target missing by @jdx in
[#9141](#9141)
- **(task)** forward task help args and add raw_args by @jdx in
[#9118](#9118)
- **(task)** remove red/yellow from task prefix colors by
@lechuckcaptain in [#8782](#8782)
- **(task)** merge TOML task block into same-named file task and surface
resolved dir by @jdx in [#9147](#9147)
- **(toolset)** round-trip serialized tool options by @atharvasingh7007
in [#9124](#9124)
- **(vfox)** fallback to absolute bin path if env_keys not set by
@80avin in [#9151](#9151)

### 📚 Documentation

- make agent guide wording generic by @jdx in
[#9142](#9142)

### 📦️ Dependency Updates

- update ghcr.io/jdx/mise:deb docker digest to e019cb9 by @renovate[bot]
in [#9160](#9160)
- update ghcr.io/jdx/mise:copr docker digest to 8d25608 by
@renovate[bot] in [#9159](#9159)
- update ghcr.io/jdx/mise:rpm docker digest to 22e52da by @renovate[bot]
in [#9161](#9161)
- update ghcr.io/jdx/mise:alpine docker digest to a3da97c by
@renovate[bot] in [#9158](#9158)
- update rust docker digest to 4a2ef38 by @renovate[bot] in
[#9162](#9162)
- update ubuntu:24.04 docker digest to c4a8d55 by @renovate[bot] in
[#9164](#9164)
- update rust crate aws-lc-rs to v1.16.3 by @renovate[bot] in
[#9165](#9165)
- update ubuntu docker tag to resolute-20260413 by @renovate[bot] in
[#9169](#9169)
- update rust crate clap to v4.6.1 by @renovate[bot] in
[#9166](#9166)
- update taiki-e/install-action digest to a2352fc by @renovate[bot] in
[#9163](#9163)
- update rust crate ctor to 0.10 by @renovate[bot] in
[#9170](#9170)
- update rust crate tokio to v1.52.1 by @renovate[bot] in
[#9167](#9167)
- update rust crate rmcp-macros to 0.17 by @renovate[bot] in
[#9173](#9173)
- update rust crate signal-hook to 0.4 by @renovate[bot] in
[#9177](#9177)
- update rust crate zipsign-api to 0.2 by @renovate[bot] in
[#9180](#9180)
- update rust crate toml_edit to 0.25 by @renovate[bot] in
[#9179](#9179)
- update rust crate strum to 0.28 by @renovate[bot] in
[#9178](#9178)

### 📦 Registry

- add ibmcloud by @dnwe in
[#9139](#9139)
- add rush by @jdx in [#9146](#9146)

### New Contributors

- @80avin made their first contribution in
[#9151](#9151)
- @atharvasingh7007 made their first contribution in
[#9124](#9124)
- @lechuckcaptain made their first contribution in
[#8782](#8782)
- @ergofriend made their first contribution in
[#9102](#9102)
- @dnwe made their first contribution in
[#9139](#9139)

## 📦 Aqua Registry Updates

#### New Packages (3)

-
[`controlplaneio-fluxcd/flux-operator`](https://github.com/controlplaneio-fluxcd/flux-operator)
-
[`dependency-check/DependencyCheck`](https://github.com/dependency-check/DependencyCheck)
- [`kiro.dev/kiro-cli`](https://github.com/kiro.dev/kiro-cli)

#### Updated Packages (2)

-
[`jreleaser/jreleaser/standalone`](https://github.com/jreleaser/jreleaser/standalone)
- [`sigstore/cosign`](https://github.com/sigstore/cosign)
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