Skip to content

fix(tools): grep content search returns nothing under a hidden root (#18473) - #34017

Open
memosr wants to merge 1 commit into
NousResearch:mainfrom
memosr:fix/search-content-hidden-root-18473
Open

fix(tools): grep content search returns nothing under a hidden root (#18473)#34017
memosr wants to merge 1 commit into
NousResearch:mainfrom
memosr:fix/search-content-hidden-root-18473

Conversation

@memosr

@memosr memosr commented May 28, 2026

Copy link
Copy Markdown
Contributor

Summary

search_files(..., target="content") returns total_count: 0 whenever the search path contains a hidden directory component (e.g. ~/.hermes/workspace/notes/), even when matching content exists. target="files" works for the same paths (fixed in #16672), but the content/grep backend was still affected.

Fixes #18473.

Root cause

ShellFileOperations._search_with_grep unconditionally appended --exclude-dir='.*'. GNU grep matches --exclude-dir against every path component, including the search root itself. When the root is (or lives under) a hidden directory, the entire tree is excluded and grep returns nothing.

Fix

Mirror the logic already used by _search_files (the target="files" path fixed in #16672): compute whether the root has a hidden ancestor and only pass --exclude-dir when it doesn't. This keeps hidden descendants excluded for normal/visible roots (the #1558 prompt-injection regression protection) while allowing explicit hidden-root searches to work.

Tests

Added TestGrepSearchesExplicitHiddenRoot with two cases:

The tests assert on the generated grep command rather than live grep output, so they're deterministic across GNU grep and BSD grep (which differ in how --exclude-dir treats the root). Verified the hidden-root test fails without the fix and passes with it. Full test_file_operations* + test_search_hidden_dirs suite: 123 passed.

…ousResearch#18473)

_search_with_grep unconditionally passed --exclude-dir='.*'. GNU grep
matches --exclude-dir against every path component including the search
root, so searching a path that lives under a hidden directory (e.g.
~/.hermes/workspace) excluded the whole tree and returned total_count: 0.

target='files' was already fixed for this in NousResearch#16672; mirror that logic
in the grep content backend: skip --exclude-dir when the root is hidden,
so explicit hidden-root searches work while hidden descendants are still
excluded for visible roots (NousResearch#1558).

Add regression tests asserting the generated command, which stays
deterministic across GNU grep and BSD grep.
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/tools Tool registry, model_tools, toolsets tool/file File tools (read, write, patch, search) labels May 28, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Competing with #18645 (open) which also fixes #18473. Both mirror the #16672 approach for the grep path. Earlier attempts: #18487 (closed), #18589 (closed).

luxles added a commit to luxles/hermes-agent that referenced this pull request Jun 19, 2026
… search roots

Two bugs in _search_with_grep() when ripgrep is unavailable:

1. BRE mode: grep -rnH uses Basic Regular Expression mode, where | is a
   literal character. ripgrep ships with Rust regex (| = alternation), so
   patterns with alternation silently fail on the grep fallback.
   Fix: add -E to enable ERE (Extended Regular Expression) mode.

2. --exclude-dir='.*': GNU grep applies this to all directory components
   INCLUDING command-line arguments, so a search under ~/.hermes/workspace
   skips the entire tree because .hermes matches .*. Ripgrep only applies
   globs to subdirectories, not the root.
   Fix: only add --exclude-dir when no path component is hidden, mirroring
   the logic already used by _search_files (merged in NousResearch#16672).

Both bugs produce silent false-negatives: search_files returns
total_count=0 without any error. Cross-reference NousResearch#18473, NousResearch#18645, NousResearch#34017.

Fixes NousResearch#18473

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for isolating the GNU grep hidden-root behavior; the current fallback still has the reported defect at tools/file_operations.py:2395.

Problems

  • tools/file_operations.py:1917 omits --exclude-dir for hidden roots but does not replace its descendant filtering. That would expose hidden descendants such as .hub and .git under an explicit hidden root, contrary to the #1558 protection introduced in 7d91b436e. Current file-name fallback code handles this distinction with post-search relative filtering at tools/file_operations.py:2173-2187.
  • The new tests at tests/tools/test_search_hidden_dirs.py:202-234 only assert command construction, so they do not catch that hidden descendants become searchable.

Suggested changes

  • Keep the explicit hidden root searchable while retaining filtering for hidden descendants, then add a live fallback test with both visible and hidden-descendant matches under a hidden root.

Automated hermes-sweeper review.

Comment thread tools/file_operations.py
part not in {".", ".."} and part.startswith(".")
for part in Path(path).parts
)
if not has_hidden_path_ancestor:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skipping --exclude-dir here also stops excluding hidden descendants of an explicit hidden root (for example ~/.hermes/workspace/.hub). #1558 added that exclusion to avoid unvetted hidden-cache content. Please retain descendant filtering, analogous to current _search_files at tools/file_operations.py:2173-2187, and add a test covering both visible and hidden-descendant matches beneath a hidden root.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/tools Tool registry, model_tools, toolsets P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data tool/file File tools (read, write, patch, search) type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: search_files target='content' returns 0 results when search path contains hidden directories (e.g. ~/.hermes/)

3 participants