Skip to content

feat(task): add command inputs to cache - #11381

Merged
jdx merged 8 commits into
mainfrom
agent/task-cache-runtime-inputs
Jul 28, 2026
Merged

jdx merged 8 commits into
mainfrom
agent/task-cache-runtime-inputs

Conversation

@jdx

@jdx jdx commented Jul 27, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • add experimental cache.command_inputs commands whose command text and raw stdout/stderr hashes participate in task artifact cache keys
  • run command inputs in the task working directory with its configured/default inline shell and resolved tool environment
  • validate empty and failing commands, suppress command output, and avoid executing command inputs during dry runs
  • document the configuration, update generated schemas, and check off command-output inputs in the parity tracker

User impact

Cacheable tasks can now invalidate on command-derived state that is not naturally represented by source files, such as compiler versions or generated configuration fingerprints. The setting also works through scoped [task_config.cache] defaults.

Validation

  • cargo test --bin mise task::task_cache::tests
  • mise run test:e2e e2e/tasks/test_task_artifact_cache_command_inputs
  • mise run render:schema
  • mise run lint-fix

Summary by CodeRabbit

  • New Features
    • Added cache.command_inputs to run specified commands before cache lookup and include their stdout/stderr (and the command text) in task cache keys.
    • Updated task schema and documentation for the new cache-key behavior.
  • Bug Fixes
    • Rejects empty/whitespace-only command inputs and surfaces clear configuration errors.
    • Ensures command inputs aren’t executed in dry-run/raw modes, and respects sandboxed environment and correct task-directory context.
  • Tests
    • Expanded end-to-end coverage for cache reuse, invalidation, and validation/error cases.
    • Added unit tests for streaming, size-limited hash-based stdout/stderr capture.

Note

Medium Risk
Runs user-defined shell commands on every cache key computation with task env/sandbox; mistakes could cause stale hits or unexpected side effects, though output is capped and the feature remains experimental.

Overview
Adds experimental cache.command_inputs so cacheable tasks can fold runtime-derived state (e.g. node --version) into artifact cache keys, not only declared sources and cache.env.

Before lookup, each listed command runs in the task directory with the same inline shell (including --shell), resolved tools/env, sandbox policy, and timeout as the task (30s default). Command text plus blake3 hashes of stdout/stderr are serialized into cache key material; output is not printed or stored. Empty commands and non-zero exits fail configuration/lookup; dry runs, raw tasks, and invalid overlap checks skip running them.

TaskArtifactCache::new is split into prepare (sources/outputs validation) and finish (after command inputs resolve). CmdLineRunner::execute_hashes_async streams piped output into hashes with a 16 MiB cap, uses process groups for cleanup on timeout/limit breaches, and refactors Unix/Windows tree kill helpers used by timeout handling.

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

@coderabbitai

coderabbitai Bot commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Task artifact caching adds cache.command_inputs, executing configured commands before cache lookup and incorporating captured stdout/stderr hashes into cache keys. Schemas, documentation, validation, process handling, dry-run behavior, and end-to-end coverage are updated.

Changes

Runtime cache inputs

Layer / File(s) Summary
Cache command-input contract
schema/mise*.json, src/task/task_cache.rs, src/task/mod.rs, src/task/task_template.rs, docs/tasks/task-configuration.md, TASK_CACHE_PARITY.md
Adds the command_inputs configuration field, documents its cache-key behavior, validates empty values, updates parsing expectations, and marks command-output parity complete.
Bounded command-output hashing
src/cmd.rs
Adds streamed stdout/stderr hashing with output limits, timeout handling, process-tree termination, and async tests.
Command-input cache-key integration
src/task/task_executor.rs, src/task/task_cache.rs
Resolves commands using task context, sandbox-filtered environments, shell handling, and dry-run behavior, then incorporates output hashes into cache keys.
End-to-end behavior coverage
e2e/tasks/test_task_artifact_cache_command_inputs, e2e/tasks/test_task_info
Covers cache invalidation, task-directory execution, failures, blank commands, dry-run and raw-task behavior, shell overrides, overlap validation, timeout fallback, sandbox filtering, and updated task information output.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TaskExecutor
  participant CmdLineRunner
  participant TaskArtifactCache
  TaskExecutor->>TaskArtifactCache: prepare cache
  TaskExecutor->>CmdLineRunner: execute cache.command_inputs
  CmdLineRunner-->>TaskExecutor: return stdout/stderr hashes
  TaskExecutor->>TaskArtifactCache: finish with command inputs
  TaskArtifactCache-->>TaskExecutor: restore or populate artifact cache
Loading

Possibly related PRs

  • jdx/mise#11328: Extends the same task artifact cache and cache-key implementation.
  • jdx/mise#11347: Shares the task artifact cache integration and command execution paths.
  • jdx/mise#11363: Provides sandbox environment filtering used when evaluating cache command inputs.

Suggested reviewers: risu729

Poem

A rabbit hashed commands bright,
And cached their echoes overnight.
When outputs changed, the task ran new,
Dry runs left no tracks in view.
The burrow’s keys now fit just right! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding command inputs to the task cache.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread src/task/task_cache.rs Resolved
Comment thread src/task/task_cache.rs Resolved
@greptile-apps

greptile-apps Bot commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds command-derived task-cache inputs and the bounded execution infrastructure needed to hash their output safely.

  • Extends task and scoped cache configuration, schemas, documentation, and task-info output with command_inputs.
  • Runs command inputs with the task shell, working directory, resolved environment, sandbox, and timeout before finalizing the cache key.
  • Streams and hashes stdout and stderr with output limits, pipe-drain deadlines, and process-tree cleanup.
  • Adds unit and end-to-end coverage for invalid commands, cache invalidation, dry runs, shell overrides, sandboxing, timeouts, and descendant cleanup.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
src/cmd.rs Adds bounded streaming output hashing and process-tree cleanup; the current implementation resolves the previously reported timeout, partial-hash, and terminal-descendant issues.
src/task/task_cache.rs Splits cache construction into preparation and finalization stages and incorporates command text and output hashes into cache-key material.
src/task/task_executor.rs Evaluates command inputs in the task runtime context and now mirrors normal Windows shell path, argument, and environment preparation.
e2e/tasks/test_task_artifact_cache_command_inputs Covers command-driven invalidation, validation failures, execution context, dry-run and raw behavior, shell overrides, timeout fallback, and sandbox filtering.
docs/tasks/task-configuration.md Documents command-input semantics, limits, defaults, and scoped configuration.

Reviews (8): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile

Comment thread src/task/task_cache.rs Resolved
Comment thread src/task/task_cache.rs Resolved

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/task/task_executor.rs (1)

540-559: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Bypass cache construction before evaluating runtime inputs.

TaskArtifactCache::new evaluates cache.runtime before this branch discards caching for raw/interactive execution. A raw task can therefore run a hidden probe such as touch marker even though artifact caching is bypassed. Gate this before new (or pass a bypass flag), and add a regression test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/task/task_executor.rs` around lines 540 - 559, Update the artifact-cache
setup in the task execution flow to detect raw or interactive execution before
calling TaskArtifactCache::new, bypassing cache construction and runtime-input
evaluation entirely in that case. Preserve the existing warning and None result,
while retaining normal cache construction for eligible tasks, and add a
regression test covering a runtime probe that must not execute for raw or
interactive tasks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@schema/mise.json`:
- Around line 2972-2977: Add the existing `runtime` array property definition to
`$defs.task_config.properties.cache`, alongside `enabled` and `env`, so
scoped-cache configurations accept and document runtime commands while
preserving `unevaluatedProperties: false`.

In `@src/task/task_cache.rs`:
- Around line 368-391: Update the runtime probe execution in the task-cache flow
around the process command construction so cache.runtime uses TaskExecutor’s
sandboxed, platform-normalized runner instead of invoking
tokio::process::Command directly. Preserve the existing command, environment,
working-directory, and output behavior while ensuring deny_env,
filesystem/network restrictions, CLI sandbox overrides, and Windows
POSIX-shell/PATH normalization are applied; add coverage for these policy paths.

---

Outside diff comments:
In `@src/task/task_executor.rs`:
- Around line 540-559: Update the artifact-cache setup in the task execution
flow to detect raw or interactive execution before calling
TaskArtifactCache::new, bypassing cache construction and runtime-input
evaluation entirely in that case. Preserve the existing warning and None result,
while retaining normal cache construction for eligible tasks, and add a
regression test covering a runtime probe that must not execute for raw or
interactive tasks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 84f3fcfb-6bed-446a-bc47-5419ddac0425

📥 Commits

Reviewing files that changed from the base of the PR and between 26a6404 and dcbcbaf.

📒 Files selected for processing (9)
  • TASK_CACHE_PARITY.md
  • docs/tasks/task-configuration.md
  • e2e/tasks/test_task_artifact_cache_runtime_inputs
  • schema/mise-task.json
  • schema/mise.json
  • src/task/mod.rs
  • src/task/task_cache.rs
  • src/task/task_executor.rs
  • src/task/task_template.rs

Comment thread schema/mise.json Resolved
Comment thread src/task/task_cache.rs Resolved
@jdx jdx changed the title feat(task): add runtime cache inputs feat(task): add command inputs to cache Jul 27, 2026
Comment thread src/task/task_cache.rs Resolved

@coderabbitai coderabbitai Bot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
e2e/tasks/test_task_artifact_cache_command_inputs (1)

44-52: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the working-directory probe path-sensitive.

pwd succeeds from any directory, and this test never validates its output, so it passes if command inputs run from the caller’s directory. Use test -f nested-only-input.txt with a sentinel created only under nested/ to make the assertion meaningful.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/tasks/test_task_artifact_cache_command_inputs` around lines 44 - 52,
Update the command-inputs test around the [tasks.check] configuration to use a
path-sensitive probe: create the sentinel file only inside nested/, replace the
pwd command input with test -f nested-only-input.txt, and retain the existing
assertion that the task runs once. Ensure the probe can succeed only when
command inputs execute from the nested working directory.
src/task/task_cache.rs (1)

383-392: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Stream command input outputs into BLAKE3 hashes.

resolve_command_inputs() uses .output() after piping stdout/stderr, accumulating the entire command output before hashing it. Since only digest values are needed, write the child’s stdout and stderr directly into hash writers and add a timeout/break when the hash writes too much.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/task/task_cache.rs` around lines 383 - 392, Update the command execution
flow in resolve_command_inputs() to stream the child process’s stdout and stderr
into BLAKE3 hash writers instead of collecting them with output(). Preserve the
digest-only behavior, and enforce a timeout or size limit that aborts processing
when hash writes exceed the allowed threshold.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@e2e/tasks/test_task_artifact_cache_command_inputs`:
- Around line 44-52: Update the command-inputs test around the [tasks.check]
configuration to use a path-sensitive probe: create the sentinel file only
inside nested/, replace the pwd command input with test -f
nested-only-input.txt, and retain the existing assertion that the task runs
once. Ensure the probe can succeed only when command inputs execute from the
nested working directory.

In `@src/task/task_cache.rs`:
- Around line 383-392: Update the command execution flow in
resolve_command_inputs() to stream the child process’s stdout and stderr into
BLAKE3 hash writers instead of collecting them with output(). Preserve the
digest-only behavior, and enforce a timeout or size limit that aborts processing
when hash writes exceed the allowed threshold.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 3be3136c-f616-4fc5-bc6e-8863862dd52b

📥 Commits

Reviewing files that changed from the base of the PR and between dcbcbaf and bfcbd8c.

📒 Files selected for processing (8)
  • TASK_CACHE_PARITY.md
  • docs/tasks/task-configuration.md
  • e2e/tasks/test_task_artifact_cache_command_inputs
  • schema/mise-task.json
  • schema/mise.json
  • src/task/mod.rs
  • src/task/task_cache.rs
  • src/task/task_template.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/task/task_template.rs
  • src/task/mod.rs

Comment thread src/cmd.rs Resolved
Comment thread src/cmd.rs Resolved

@cursor cursor Bot left a comment

Copy link
Copy Markdown

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 be62db9. Configure here.

Comment thread src/task/task_executor.rs Resolved

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
e2e/tasks/test_task_artifact_cache_command_inputs (1)

114-127: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

shell-override test doesn't verify anything shell-specific.

command_inputs = ["true"] succeeds identically regardless of which shell runs it, so this test would pass even if the --shell "sh -c" CLI override were silently ignored for command-input resolution. Every other test added in this file ends with a concrete assert/assert_fail_contains; this one only has a trailing comment.

Consider a command that only succeeds/produces distinguishable output under the overridden shell (e.g. writing shell-specific syntax to a marker file and asserting its contents), so the test actually exercises the described "command inputs honor the CLI shell override" behavior rather than just "the invocation didn't crash."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/tasks/test_task_artifact_cache_command_inputs` around lines 114 - 127,
Strengthen the shell-override test around the shell-override task so
command_inputs uses syntax or behavior specific to the CLI-provided “sh -c”
shell, then add a concrete assertion validating the resulting marker/output.
Replace the current universally successful command_inputs entry and trailing
comment while preserving the existing mise run invocation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/cmd.rs`:
- Around line 1082-1170: Make TimeoutGuard self-cancelling by implementing Drop
for the TimeoutGuard type and invoking its existing idempotent cancel method
during destruction. Preserve the explicit cancellation in execute_hashes_async
and other existing call sites, ensuring all early returns from consume errors,
wait failures, and drain failures also stop the timeout worker.

In `@src/task/task_executor.rs`:
- Around line 1258-1264: Update the timeout parsing in
resolve_cache_command_inputs around the timeout expression to match
exec_program’s non-fatal behavior: warn when task.timeout cannot be parsed, then
fall back to running without an enforced timeout rather than propagating the
error with wrap_err_with and ?. Preserve COMMAND_INPUT_TIMEOUT for absent or
otherwise valid timeout values as appropriate.

---

Nitpick comments:
In `@e2e/tasks/test_task_artifact_cache_command_inputs`:
- Around line 114-127: Strengthen the shell-override test around the
shell-override task so command_inputs uses syntax or behavior specific to the
CLI-provided “sh -c” shell, then add a concrete assertion validating the
resulting marker/output. Replace the current universally successful
command_inputs entry and trailing comment while preserving the existing mise run
invocation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 70bb6475-35ad-4e8a-b8aa-133d052f4ac4

📥 Commits

Reviewing files that changed from the base of the PR and between bfcbd8c and 90cdaad.

📒 Files selected for processing (6)
  • docs/tasks/task-configuration.md
  • e2e/tasks/test_task_artifact_cache_command_inputs
  • schema/mise.json
  • src/cmd.rs
  • src/task/task_cache.rs
  • src/task/task_executor.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/tasks/task-configuration.md

Comment thread src/cmd.rs Resolved
Comment thread src/task/task_executor.rs Resolved
Comment thread src/cmd.rs Resolved
@github-actions

Copy link
Copy Markdown
Contributor

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.7.14 x -- echo 18.2 ± 2.7 15.5 32.5 1.00
mise x -- echo 19.8 ± 1.2 17.1 24.5 1.08 ± 0.17

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.7.14 env 17.6 ± 0.9 15.8 22.0 1.00
mise env 19.1 ± 1.2 16.2 23.9 1.09 ± 0.09

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.7.14 hook-env 18.4 ± 1.0 16.3 22.3 1.00
mise hook-env 20.0 ± 1.1 17.4 25.1 1.09 ± 0.08

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.7.14 ls 16.5 ± 1.1 14.2 21.6 1.00
mise ls 19.1 ± 1.4 16.3 23.9 1.16 ± 0.12
⚠️ Inconclusive: ls measured 16% slower, but the relative uncertainty overlaps the 10% threshold.

xtasks/test/perf

Command mise-2026.7.14 mise Variance
install (cached) 163ms 177ms -7%
ls (cached) 64ms 69ms -7%
bin-paths (cached) 66ms 72ms -8%
task-ls (cached) 90ms 97ms -7%

Cache command inputs are non-interactive probes with piped output, so
detach stdin and always setpgid instead of skipping the process group
when stdin is a terminal. Timeout, output-limit, and stuck-pipe cleanup
now reaches descendants rather than only the direct child.

Also fixes the clippy argument-count error on
TaskArtifactCacheBuilder::finish and the tasks info JSON fixture, which
did not include the new cache.command_inputs field.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

Instruction counts

benchmark trend instructions Δ wall (min) Δ
env ▁▁▁▃█ 84,171,219 → 84,357,212 +0.22% 23.39 → 21.31ms -8.90%
hook-env ▁▄▄▆█ 86,841,367 → 86,924,981 +0.10% 24.38 → 21.17ms -13.16%
ls ▁████ 76,306,704 → 76,302,159 -0.01% 22.20 → 17.97ms -19.06%
registry ▅▁▃▃█ 49,889,046 → 49,974,686 +0.17% 14.30 → 12.02ms -15.98%
startup █▁▁▃█ 15,624,739 → 15,680,800 +0.36% 9.23 → 8.07ms -12.54%

No instruction-count regression above 1%.

Only instruction counts gate. Wall clock is shown for context — on identical hardware it moves 4-20% run to run.

Measured by tak — instruction-counted CLI benchmarks, stored in this repository's git notes.

c5814eb9895c vs 02261ed69a0f · measured on the runner, not pushed to the history.

@jdx
jdx merged commit 2ae3ebf into main Jul 28, 2026
36 checks passed
@jdx
jdx deleted the agent/task-cache-runtime-inputs branch July 28, 2026 01:27
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