2026-08-01 Grep Translation Hook Removed After Finding Upstream Shims
What I set out to do
Confirm a hunch: the grep→rg and find→fd translation hooks in the dotfiles were causing tool-call bugs in Claude Code sessions, and upstream had supposedly moved to ugrep anyway, making them obsolete. Then measure the actual damage before deciding on a fix.
What I actually did
The docs/changelog gave nothing (the Grep tool is ripgrep-backed, no ugrep mentions anywhere), but the live system settled it: Claude Code injects shell functions into its Bash-tool shell snapshots (~/.claude/shell-snapshots/) that re-exec the claude binary as embedded multicall tools. grep runs ugrep 7.5.0 in grep-compatible BRE mode, find runs bfs 4.1.1 (findutils-compatible), rg runs embedded ripgrep. Completely undocumented; verifiable with type grep inside any Bash tool call. The tell that cracked it was a transcript error showing ugrep’s help text where rg output should have been.
Then quantified the translator’s damage across all 2,319 local transcripts: since the hook landed 2026-04-01, 845 Bash calls started with grep/find, 637 were rewritten, 125 (~20% of rewrites) failed visibly. Dominant failure: the hook converted BRE \| for rg but left literal (/{ in patterns, which rust-regex chokes on; the upstream ugrep shim would have run those untouched. Also compound-command mangling (shlex flattening turned second commands into rg file arguments, one silent two-line join), fd flag gaps, and rewrites escaping the Bash(grep *) allowlist so users got prompts for commands the model never wrote.
Deleted the bash-command-validator project entirely: uv2nix package, PreToolUse wiring, allowlist entry, flake check, source tree. Recorded as ADR 0023 (which supersedes ADR 0016’s explicit rejection of deleting the hook). Commit 09fee6d, applied via hm switch, gate green.
What was striking
The hook was built to enforce a preference (modern CLI tools) by silently rewriting commands the model never saw changed, which made every failure look like the model’s fault and left no error signature for the silent cases. And the entire premise evaporated not because the idea was wrong but because upstream quietly shipped a better version of it: syntax-faithful fast replacements instead of syntax-translating ones. Same lesson shape as 2026-07-13 The Intel Audit That Could Not See Shims: the answer was hiding in what the shell actually resolves, not in any documentation.
Related
- ADR 0023 in the dotfiles repo (
docs/decisions/0023-remove-grep-find-translation-hook.md) - 2026-07-13 The Intel Audit That Could Not See Shims
- 2026-07-24 Claude Code Context Audit - Cutting Superpowers and 8 Plugins