Add moon filter — route underlying-tool output through existing rtk filters
#1,877 opened on 2026年5月13日
Repository metrics
- Stars
- (48,085 stars)
- PR merge metrics
- (平均マージ 11d 1h) (30d で 45 merged PRs)
説明
[Feature] Add moon filter — pass underlying-tool output through rtk's existing filters
TL;DR
moon (the moonrepo task runner) is the #1 unhandled command in our rtk discover snapshot — 3363 invocations / 30 days. moon's own chrome is already pretty terse on success, but when a moon run invocation triggers a verbose underlying tool (vitest, jest, tsc, eslint, prettier, cargo test), all of that tool's output streams through unfiltered. The ask: have rtk moon detect the underlying tool per task and apply the matching rtk <tool> filter to that task's stdout/stderr.
What moon run actually looks like
Real captures from moon 2.2.0 against a Bun/pnpm-workspace TypeScript monorepo (7 projects).
Default cold-cache success (7 projects, :typecheck --force)
▮▮▮▮ There's a new version of moon available, 2.2.4 (currently on 2.2.0)!
▮▮▮▮ Daemon, AI skill, async experiments, and more!
▮▮▮▮ Run moon upgrade or install from https://moonrepo.dev/docs/install
▮▮▮▮ config:typecheck (64afa622)
▮▮▮▮ observability:typecheck (0b06b2c7)
▮▮▮▮ types:typecheck (794ed526)
▮▮▮▮ db:typecheck (1969c43e)
▮▮▮▮ web-api:typecheck (371ccfb2)
▮▮▮▮ web-ui:typecheck (4563caad)
▮▮▮▮ agent-core:typecheck (169e5c4e)
▮▮▮▮ observability:typecheck (2s 888ms, 0b06b2c7)
▮▮▮▮ types:typecheck (3s 223ms, 794ed526)
▮▮▮▮ config:typecheck (3s 446ms, 64afa622)
▮▮▮▮ db:typecheck (3s 580ms, 1969c43e)
▮▮▮▮ web-api:typecheck (3s 710ms, 371ccfb2)
▮▮▮▮ web-ui:typecheck (4s 294ms, 4563caad)
▮▮▮▮ agent-core:typecheck (6s 166ms, 169e5c4e)
Tasks: 7 completed
Time: 6s 418ms
~18 lines / ~400 tokens. Already terse. moon hides the tasks' own stdout on success by default.
Cache hit (single project)
▮▮▮▮ agent-core:typecheck (cached, 1ms, 169e5c4e)
Tasks: 1 completed (1 cached)
Time: 148ms ❯❯❯❯ to the moon
~30 tokens. Nothing to compact.
With --summary detailed (or MOON_SUMMARY=detailed)
Same as default, plus a 20-line breakdown of every pipeline action (pass SyncWorkspace, pass SyncProject(types), pass RunTask(...), skip SetupToolchain(...), etc.). Roughly doubles the output. Many users have this on by default in CI configs and shell aliases.
Failure case (not captured here, behavior known from documentation)
When a task fails, moon streams that task's full stdout/stderr inline. So moon run :test where one project's vitest suite fails dumps all of vitest's output (passing tests, slow-test warnings, coverage summary, the failure itself) — exactly the kind of output rtk vitest already compacts by 80-90%. Without rtk moon, none of that streamed output is filtered.
Where the wins actually live
| Source of waste | Tokens per call | Frequency | Fix |
|---|---|---|---|
| Streamed output of failing/verbose underlying tool | hundreds to thousands | Every failure + every --verbose run |
Detect underlying tool, route stdout through existing rtk filter |
--summary detailed block |
~150 | Whenever user/CI sets it | Drop or collapse |
| moon upgrade nag banner | ~30 | Every call while outdated | Drop |
▮▮▮▮ ❯❯❯❯ to the moon decoration |
~10 | Every call | Drop |
Hash suffixes (169e5c4e) |
~5/task | Every task | Drop (they're cache keys, useless to the LLM) |
The dominant win — by far — is #1. Without it, an rtk moon filter would only save tens of tokens per call. With it, moon run :test becomes as compact as rtk vitest.
Proposed design
-
Detection.
moon run <project>:<task>runs a command defined in that project'smoon.yml. moon exposes the resolved command viamoon query tasks --json(returns a structured map of{project:task → {command, args, ...}}).rtk mooncan call this once per invocation, cache it per workspace, and know thatagent-core:testis actuallybun testand applyrtk testsemantics. -
Streaming. Wrap each task's stdout/stderr stream through the detected filter. moon's stream output is already line-prefixed with the project name when multiple tasks run in parallel; rtk should preserve that prefix and filter the rest of each line.
-
Strip moon chrome. The upgrade banner, the
❯❯❯❯ to the moonfooter, the hash suffixes — all safe to drop. -
Pass through structured subcommands verbatim.
moon query,moon graph,moon ext,moon dep-graphalready emit JSON / DOT and are typically piped into tooling. Don't touch them. -
Honor
--jsonif/when moon adds it forrun. moon 2.x doesn't have--jsononrunyet; if a future version does,rtk moonshould prefer that.
Suggested CLI mapping
moon run <args> → rtk moon run <args> # apply detection + filtering
moon ci <args> → rtk moon ci <args> # same, ci variant
moon check <args> → rtk moon check <args> # same
moon query <args> → passthrough
moon graph <args> → passthrough
moon ext <args> → passthrough
moon <other subcommand> → passthrough by default
Numbers
- 3363
moon runinvocations / 30 days for a single engineer on this workspace (fromrtk discover). - Most calls are cache hits or all-pass — those would save maybe 30-50 tokens after stripping the upgrade banner / hashes / footer.
- The minority of calls that include real underlying-tool output (failures,
--force,:testruns) are where rtk would save thousands of tokens each — same shape as the currentrtk vitest/rtk jest/rtk cargo testwins. - Rough swag: ~500k-1M tokens / 30 days for one engineer in our shape of workspace.
Happy to help
- More captures available on request (failure case,
:test,:lint,--affectedruns). - moon's output format is stable across the 1.x → 2.x bump (run output structure didn't change), so the filter shouldn't be a maintenance burden.
- If
src/filters/has a template I can crib from, happy to draft a PR.
Environment
moon 2.2.0(also relevant to 2.x line generally)- TS / Bun / pnpm-workspace monorepo, ~7-15 projects per moon workspace
- Typical invocations:
moon run agent-core:test,moon run :lint,moon run :typecheck --affected - Generated this issue while running through
rtk 0.39.0— the recursion is intended