Bundled search wrappers narrow silently and exit 0
Environment: Claude Code 2.1.217, macOS, zsh.
Summary
The shell-snapshot functions that shadow grep (ugrep with --ignore-files --hidden -I)
and rg (bundled ripgrep with default ignore behavior) exclude gitignored, hidden, and binary
files from results. The narrowing is a reasonable default. The problem is that it is never
disclosed. The search prints its matches, exits 0, and gives no signal that any files were
skipped, so a thin or empty result is indistinguishable from an exhaustive one.
Reproduction (deterministic)
Plant a unique string in 10 files, one behind each narrowing channel (a plain file, a hidden
file, a hidden directory, a gitignored directory, a gitignored file, a gitignored glob, a
binary file, and an untracked file):
| search | files found |
|---|---|
| command grep -rl STRING . | 10 of 10 |
| wrapped grep -rl STRING . | 5 of 10 |
| wrapped rg -l STRING | 3 of 10 |
All three exit 0. None print any indication that files were skipped.
Why the silence has a cost (measured)
Two independent measurements on one user's environment:
- A controlled experiment: 48 runs (Claude Sonnet) against a planted corpus with a known
answer key. In the baseline condition, 25% of runs concluded a string was absent when it
was present, and stopped searching early. Transcripts show the agent's spelling and variant
hypotheses were usually correct. It trusted an incomplete, exit-0 tool result over its own
correct hypothesis.
- The same user's Claude Code transcripts across 74 days (41,428 tool calls, 6,398 of them
search-shaped). The rate of "empty search result, then no further search that turn" was 22
to 27% depending on the measurement window, consistent with the experiment's 25%.
This is one user's data, so treat the rates as indicative rather than fleet-representative. The
deterministic reproduction above does not depend on them.
Suggested fix (minimal)
Emit one line to stderr when a search was narrowed, for example:
note: 312 files skipped by ignore rules, 40 binary; pass --no-ignore --hidden --binary for full coverage
The narrowing can stay the default. Only the silence needs to change. A distinct exit code for
"results were narrowed" would additionally let scripts and agents branch on incompleteness
rather than reading exit 0 as a clean, exhaustive search.