feat: task runner support (mise, just, task) — intelligent output filtering and delegation
#607 创建于 2026年3月15日
仓库指标
- Star
- (48,085 star)
- PR 合并指标
- (平均合并 11天 1小时) (30 天内合并 45 个 PR)
描述
Problem
Task runners hide underlying commands from RTK's hook system.
When a user runs mise run lint, RTK's hook sees mise — not biome check --write. Result: 0% token savings for task-runner-heavy workflows. The filtering intelligence built into RTK never activates because the hook can't see through the abstraction layer.
Context
Community report from a contributor who wraps all commands in mise run <task>. Same gap applies to just, task (go-task), and any abstraction layer. make already has basic TOML filter support but the problem is identical.
This is a growing issue given mise adoption in AI-assisted coding workflows — where task runners are increasingly the standard entry point for dev operations.
Task Runner Introspection Capabilities
| Runner | Config file | Dry-run | JSON dump | Parse difficulty |
|---|---|---|---|---|
| mise | mise.toml → [tasks.<name>].run |
No native flag | mise tasks ls --json |
Easy (TOML) |
| just | justfile |
just --dry-run <recipe> |
just --dump --dump-format json |
Easy (JSON) |
| task | Taskfile.yml |
task --dry <task> |
task --list --json |
Medium (YAML) |
| make | Makefile |
make -n <target> |
No | Hard (not worth parsing) |
Implementation Plan
Phase 1 — TOML Filters + Registry (quick win, ~2-3h)
Strip task runner boilerplate from output via TOML filters. Register patterns in the rewrite registry so the hook intercepts task runner commands.
New files:
src/filters/mise.toml— strip[mise]banners,$ commandechoes, blank linessrc/filters/just.toml— strip recipe echo lines, timing outputsrc/filters/taskfile.toml— striptask: [Name]headers, timing output
Modified files:
src/discover/rules.rs— add 3 patterns (^mise\s+run\b,^just\s+,^task\s+) + 3 rulesCHANGELOG.md
Impact: 30-50% savings from boilerplate removal. Hook rewrites mise run lint → rtk mise run lint. TOML filter matches in run_fallback().
Ships independently. Zero breaking changes.
Phase 2 — Dedicated Rust Module with Routing (core, ~4-6h)
Single src/task_runner_cmd.rs module that:
- Runs the task runner command, captures stdout/stderr
- Resolves the underlying tool via config file introspection
- Routes output through the specialized
filter_*()function (mirrors npx pattern) - Falls back to TOML filter if no resolution possible
Architecture: Run the task runner (preserves env setup, hooks, dep ordering), then filter captured output through the right RTK filter function. RTK never bypasses the task runner.
Delegation logic:
underlying tool detected → delegate to specialized filter
biome/eslint → lint_cmd::filter_lint_output()
tsc → tsc_cmd::filter_tsc_output()
cargo test → runner test filter
vitest/jest → vitest_cmd filter
pytest → pytest_cmd filter
unknown → TOML filter fallback → summary heuristic → passthrough
New files:
src/task_runner_cmd.rs— unified module withTaskRunnerenum (Mise/Just/Task)tests/fixtures/mise_run_lint_raw.txt,just_lint_raw.txt
Modified files:
src/main.rs— addMise,Just,Taskto Commands enum + routingsrc/lint_cmd.rs,src/tsc_cmd.rs, etc. — exposefilter_*()functions aspubsrc/toml_filter.rs— addmise/just/tasktoRUST_HANDLED_COMMANDS
Needs Phase 1. Ships independently after Phase 1.
Phase 3 — Config Introspection + User Mappings (smart, ~3-4h)
Auto-parse task runner config files to resolve task → command mappings. Add user-configurable overrides.
Resolution priority:
- User config
[task_runners.mappings]inconfig.toml(explicit override, always wins) - Config file introspection (
mise.toml→tasks.lint.run,just --dump --dump-format json) - TOML filter for boilerplate stripping
summaryheuristic detection- Raw passthrough
Config example (~/.config/rtk/config.toml):
[task_runners.mappings]
lint = "biome check"
test = "cargo test"
typecheck = "tsc --noEmit"
Modified files:
src/config.rs— addTaskRunnerConfigwithmappings: HashMap<String, String>src/task_runner_cmd.rs— add introspection functions per runner
Needs Phase 2. Ships independently.
Phase 4 — Discover Integration (polish, ~1h)
rtk discover reports missed savings from task runner commands in Claude Code sessions.
Already covered by Phase 1 registry entries — classify_command() picks up new patterns automatically. Needs verification + a test to confirm classification fires correctly.
Needs Phase 1. Ships independently.
Key Design Decisions
Run the task runner, not the underlying command. RTK executes mise run lint, not biome check --write directly. This preserves task runner semantics: env vars, pre/post hooks, dependency ordering. Bypassing the runner would break workflows that rely on these side effects.
One Rust module for all runners. task_runner_cmd.rs with a TaskRunner enum, not separate modules per runner. The introspection and delegation logic is shared — splitting it across files adds complexity without benefit.
Lazy parsing. Config file introspection happens only when the command is invoked, never on startup. The <10ms startup constraint is non-negotiable.
No persistent cache. In-memory resolution per invocation is sufficient. Parsing mise.toml costs <5ms. A persistent cache adds complexity and invalidation edge cases.
Hook stays dumb. mise run lint → rtk mise run lint. All intelligence lives in the Rust binary, not the hook script.
Acceptance Criteria
-
mise run lintrewritten by hook tortk mise run lint - Output filtered with ≥60% token savings when underlying tool is recognized
- Output filtered with ≥30% savings even when underlying tool is unknown (TOML boilerplate stripping)
-
rtk discoverreports missed savings formise run/just/taskcommands - Exit codes preserved (non-zero from task runner propagates correctly)
- Fallback to raw output on any parsing or introspection failure
- <10ms startup overhead (no config file parsing on startup)
Priority and Effort
| Phase | Effort | Savings | Ships independently |
|---|---|---|---|
| Phase 1 | 2-3h | 30-50% | Yes |
| Phase 2 | 4-6h | 60-90% | Yes (after Phase 1) |
| Phase 3 | 3-4h | Auto-resolution | Yes (after Phase 2) |
| Phase 4 | 1h | Analytics | Yes (after Phase 1) |
Phase 1 is a clear quick win — shippable standalone and unblocks all other phases.