Shell-snapshot grep/find shadowing has no opt-out, and --ignore-files makes gitignored content silently invisible
Environment
- Claude Code 2.1.251, macOS (zsh)
What happens
The generated shell snapshot (~/.claude/shell-snapshots/snapshot-zsh-*.sh) contains a block — "Shadow find/grep with embedded bfs/ugrep" — that redefines grep and find as functions exec'ing the claude binary's embedded ugrep/bfs with extra flags: -G --ignore-files --hidden -I --exclude-dir=.git.
Two consequences:
--ignore-fileshonors.gitignore, sogrep -rn <pattern> .over a repo returns 0 matches at exit 1 for content that exists in a gitignored file (build output,.env.examplecopies, vendored dirs, logs). Combined with-I(skip binaries), a search that "finds nothing" is indistinguishable from the content not existing. In an agent loop that's the dangerous shape: exit 1 + empty output reads as not present, and the model draws the opposite of the true conclusion. We've hit this in practice — one session concluded content was absent that a plaingrepfinds immediately.- Some invocation shapes get mangled — a large newline-joined multi-file argument list (from
$(grep -rl ...)) producedugrep: warning: ... File name too longper file and reported 0 matches where matches existed.
What I looked for
USE_BUILTIN_RIPGREP=0only switches whichrgis used; it does not gate the grep/find shadow.- The snapshot generator appears to emit the block unconditionally for this build, and the shadow functions are defined after profile content, so a user-defined
grepfunction in.zshrcis overridden. - No documented setting or env var found that disables it.
Workaround
command grep / command find bypass the shadow. That works but has to be remembered per-invocation, including by the model itself.
Request
An opt-out — e.g. CLAUDE_CODE_DISABLE_SHELL_SHADOWING=1 (or a granular equivalent, or a settings.json key) that stops the snapshot from shadowing grep/find. Alternatively, dropping --ignore-files from the injected flags would remove the worst hazard while keeping the token-savings intent: a search tool that silently excludes gitignored files changes the meaning of exit 1, not just the output size.
🤖 Filed with Claude Code on the user's behalf.