Repository navigation
grep: optional tgrep backend for large workspaces #1086
Description
Feature Description
Let the grep tool run against a tgrep trigram index when one exists for the session root, and fall back to the bundled ripgrep otherwise. Opt-in, not a default change — tgrep only pays off with an index plus a live server, and it is slower than ripgrep on patterns the index cannot narrow.
Today there is no setting to change the grep backend, and a mod cannot register a tool named grep (colliding names are skipped with mod_error), so the only seam is beforeToolCall interception.
Use Case
On a 124,465-file / 29 GB workspace, a selective search such as TODO takes ~3.1s through the grep tool. Agents issue dozens per session, serially. With a live tgrep server the same search returns in 31ms end to end — 100x. Measured on macOS arm64, tgrep 1.2.5, ripgrep 15.2.0, warm cache, best of 5:
| query | ripgrep (full search) | tgrep |
|---|---|---|
TODO (selective, 1,280 files) |
3.07s | 31ms |
function (broad, 65,004 matching lines) |
3.37s | 163ms |
| absent token | 3.01s | 16ms |
For comparison, engine-to-engine with full output the broad case is only 1.2x (3.31s vs 2.83s); the 21x through a tool result comes from stopping at the page limit instead of materialising everything.
Additional Context
I built this as a mod and hit six things a native implementation would need to handle:
output_modedefaults differ — the built-in isfiles_with_matches, tgrep is content, so-lmust be passed when the field is absent.- tgrep omits line numbers unless
-nis given explicitly. head_limit/offsetneed a stream that aborts atoffset + limit + 1lines; buffering a broad match set hit 23 MB and a 285k-line result.- An index without a running server is not safe. It silently misses files written since the build. Reproduced: a newly created file returned exit 1 (no matches) from tgrep while ripgrep found it. A native backend should require a live server, not just an index on disk.
- A cheap
tgrep status .probe gates it (0.00s live, 0.08s dead), plus a stderr check forfalling back to local indexto cover a server dying mid-query. - Patterns with no literal trigrams scan every indexed file —
\d{9,}took 40.5s against ripgrep's 3.0s — so a timeout fallback or trigram heuristic is required. My mod caps at 30s and then defers to the built-in.
Prototype with methodology, raw output and limitations: https://github.com/Hashimlokasher/cmd-mod-tgrep-grep (BENCHMARKS.md). tgrep also powers GitHub Copilot CLI's grep, so it is actively maintained.
Proposal: a grep.backend: "tgrep" setting, or auto-detect when tgrep is installed and a live index is present, keeping ripgrep as the default and the fallback. Happy to test or contribute.
Priority: Important for my workflow
Activity