Skip to content

Hook: find/grep rewrite breaks on native flags — workaround with smart translation #236

@Shankhara

Description

@Shankhara

Context

The recommended Claude Code hook blindly prefixes find and grep/rg commands with rtk, which breaks in many common cases (relates to #204, #229).

find — syntax mismatch

rtk find has a completely different syntax than GNU find:

  • GNU: find <path> <predicates> (e.g., find . -not -path '*/.git/*' -name '*.pdf')
  • RTK: rtk find <PATTERN> [PATH] [--max N] [-t f|d]

The hook rewrites find . -not -path ... | head -n 500rtk find . -not -path ... | head -n 500, which fails because:

  1. RTK's Clap parser doesn't know -not, -path, -type, -exec, etc.
  2. The argument order is reversed (pattern vs path)
  3. Piped commands like | head -n get their flags parsed by Clap (the -n error from find and grep commands fail (unexpected argument '-n' found) #204)

grep — Clap intercepts rg flags

rtk grep declares extra_args: Vec<String> with trailing_var_arg = true, but Clap still intercepts short flags like -i, -r, -n, -A etc. before reaching the trailing var arg. This means:

  • rtk grep -i "pattern" .error: unexpected argument '-i' found
  • rtk grep -rn "pattern" .error: unexpected argument '-n' found (grep: unexpecter argument #229)

The only way to pass rg flags is AFTER the positionals: rtk grep "pattern" path -- -i

Workaround: smart hook translation

We wrote a hook that properly translates instead of blindly prefixing:

find — syntax translation with safety guards

# Detect unsupported find features using case patterns
FIND_UNSUPPORTED=false
case "$MATCH_CMD" in
  *-exec*|*-delete*|*-print0*|*-newer*|*-mtime*|*-not*|*'!'*) FIND_UNSUPPORTED=true ;;
  *-maxdepth*|*-mindepth*|*-path*|*'|'*|*'&&'*) FIND_UNSUPPORTED=true ;;
esac

# Only translate simple: find <path> -name <pattern> [-type f|d]
# Complex cases pass through to native find
if [ "$FIND_UNSUPPORTED" = false ]; then
  # Translate: find . -name "*.pdf" -type f → rtk find *.pdf . -t f
  FIND_PATH=<extracted>
  FIND_PATTERN=<extracted>
  REWRITTEN="rtk find ${FIND_PATTERN} ${FIND_PATH}"
fi

grep — flag reorganization

# Parse args, separate RTK-known flags from rg-passthrough flags
# Strip -r/-R/-n/--recursive (redundant: rtk grep is recursive + line-numbered)
# Map --type → -t (RTK's Clap flag)
# Move unknown flags (like -i, -w, -A 3) after positionals with -- separator
# Result: grep -rn -i -A 3 "pattern" src/ → rtk grep "pattern" src/ -- -i -A 3

Suggestions for RTK

  1. find: Consider either adding external_subcommand / passthrough fallback (like PR feat: passthrough fallback when Clap parse fails #200 suggests), or documenting that the hook should translate syntax rather than prefix
  2. grep: The trailing_var_arg on extra_args doesn't work as expected — Clap intercepts short flags before they reach extra_args. Consider using allow_hyphen_values = true on extra_args, or moving to a -- separator approach in the Clap definition
  3. Hook template: The default hook in the README should handle these edge cases — happy to contribute the full working hook if helpful

Environment

  • RTK: installed via Homebrew
  • OS: macOS (Darwin 24.6.0)
  • Claude Code hook (PreToolUse:Bash)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions