rtk-ai/rtk

bug(rewrite): false positives for systemctl, make; next build drops subcommand arg

Open

#1,714 opened on 2026年5月5日

GitHub で見る
 (1 comment) (0 reactions) (0 assignees)Rust (2,914 forks)batch import
area:clibughelp wantedplatform:linuxpriority:high

Repository metrics

Stars
 (48,085 stars)
PR merge metrics
 (平均マージ 11d 1h) (30d で 45 merged PRs)

説明

rtk version: 0.38.0 OS: Linux (Ubuntu, x86_64) Discovered via: rtk-hermes plugin (Hermes Agent integration)


Summary

rtk rewrite produces incorrect rewrites for 3 commands. Two are false positives (rewriting unsupported commands to broken rtk invocations), and one drops a required subcommand argument.

Bug 1: next buildrtk next (drops build arg)

$ rtk rewrite "next build"; echo "exit: $?"
rtk next
exit: 3

The build subcommand is dropped entirely. Running rtk next without build either errors or does nothing useful.

Looking at #241, the rule was intentionally written this way:

// "next build" is stripped to "rtk next" — the build subcommand is internal
rtk_cmd: "rtk next",
rewrite_prefixes: &["npx next build", "pnpm next build", "next build"],

But rtk next requires the build (or dev, etc.) subcommand — without it, clap rejects the invocation. The rewrite should be rtk next build, not rtk next.

Bug 2: systemctl status nginxrtk systemctl status nginx (false positive)

$ rtk rewrite "systemctl status nginx"; echo "exit: $?"
rtk systemctl status nginx
exit: 3

RTK has no systemctl first-class subcommand. There is a TOML filter (systemctl-status.toml from #386) scoped to ^systemctl\s+status\b, but the rewrite registry appears to match systemctl broadly — rewriting any systemctl command to rtk systemctl, which then fails at runtime because clap has no systemctl subcommand.

This turns a working command into a broken one.

Bug 3: make buildrtk make build (false positive)

$ rtk rewrite "make build"; echo "exit: $?"
rtk make build
exit: 3

Same pattern. RTK has a TOML filter for make (#349), but no rtk make subcommand exists in clap. The rewritten command fails. The hook silently replaces a working make build with a broken rtk make build.

Impact

Bugs 2 and 3 are particularly dangerous when used with auto-rewrite hooks (Claude Code, Hermes, Cursor, etc.) — the hook transparently replaces working commands with broken ones. The LLM agent sees a confusing error instead of the expected output and has to waste tokens diagnosing the failure and retrying.

This is the same class of bug as #336/#244 (docker compose false positives).

Root cause

The rewrite registry (rules.rs) matches commands that have TOML filters but no corresponding clap subcommand. When rtk <cmd> is executed, clap rejects it because the subcommand does not exist in the CLI interface.

Two possible fixes:

  1. Only rewrite commands that have an actual clap subcommand — TOML-only filters should not be added to the rewrite registry unless rtk <cmd> is also wired into clap.
  2. Add clap passthrough for TOML-filtered commands — if a command matches a TOML filter but has no dedicated Rust handler, route it through the TOML fallback engine (similar to rtk run).

Test cases to add

# Bug 1: next build should keep the subcommand
assert_rewrite "next build" "rtk next build"
assert_rewrite "npx next build" "rtk next build"

# Bug 2: systemctl should not be rewritten (or only systemctl status)
assert_rewrite "systemctl status nginx" "rtk systemctl status nginx"  # only if rtk systemctl exists
# or: exit 1 (no rewrite) if no rtk systemctl subcommand

# Bug 3: make should not be rewritten unless rtk make subcommand exists
assert_rewrite "make build" "rtk make build"  # only if rtk make exists
# or: exit 1 (no rewrite)

コントリビューターガイド