rtk-ai / rtk-ai/rtk

bug(discover): a tab between command and subcommand classifies as Supported but never rewrites

Open
#4,100 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area:cli bug good first issue priority:low
Dominant language
Rust
Stars
81k
Forks
5.1k
Avg merge
4d 21h
Merged PRs (30d)
35

Description

Same class as #3995 (absolute-path arm, fixed 2026-09-13): classify_command and the rewrite
disagree about what separates a command from its subcommand.

  • the rule patterns match \s+^pnpm\s+(exec|i|install|…), ^cargo\s+(build|test|…), …

  • strip_word_prefix (src/discover/registry.rs:1930) accepts only a literal ASCII space:

    } else if cmd.len() > prefix.len()
        && cmd.starts_with(prefix)
        && cmd.as_bytes()[prefix.len()] == b' '
    

So a tab-separated command is classified Supported and then returned unchanged by the hook.
rtk discover and rtk session count it as covered; the command streams raw.

Verified on develop (5e0f92cd) with rtk rewrite, tab written as \t:

command rewrite
git status rtk git status
git\tstatus (nothing)
cargo\tbuild (nothing)
npm\trun build (nothing)
pnpm\tinstall (nothing)

Not tool-specific — it is every rule that goes through strip_word_prefix.

A tab really is a valid separator here, so the classify side is the one that is right:
the shell grammar treats space and tab as blanks when tokenising a command line, independent
of IFS. bash -xc $'git\t--version' traces as + git --version and prints
git version 2.53.0.

And it reaches the hook. Feeding a PreToolUse payload to rtk hook claude — the tab
survives JSON transport as \t:

tool_input.command updatedInput.command returned
git status rtk git status
git\tstatus (none — unchanged)
pnpm\tinstall (none — unchanged)

Frequency: low. An agent writing shell almost always uses a single space, so this is a
correctness gap rather than a material source of lost savings — worth closing for the
consistency of the two sides, not urgent.

Found while reviewing #3275 with a differential fuzz asserting
classify == Supported(rtk pnpm) ⇒ rewrite fires. Over 6528 generated pnpm spellings it trips
64 times, all tab-separated, and the count is identical on develop and on that PR's head
so this is pre-existing and #3275 neither adds to it nor fixes it.

A fix should make the two sides share one notion of the boundary rather than widening
strip_word_prefix alone: widening only the classify side is what #3275 round 1 had to close,
and widening only the rewrite side would rewrite forms classify still calls Unsupported.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/discover/registry.rs:1930 at strip_word_prefix, then trace classify_command and the rewrite path to understand their command-boundary handling. Run the reported rtk rewrite cases with space and tab separators, and use the differential fuzz scenario if available. Done means supported tab-separated commands are rewritten consistently and classification and rewriting share the same boundary behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
cli
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.