| name | fast-grep |
| description | Use fast-grep (`fgr`) for regex and literal text search across this repository.
When an index exists it is dramatically faster than `grep`/`ripgrep`; without an
index it is comparable to ripgrep. TRIGGER when: searching for code (function,
symbol, identifier, string), counting occurrences, or listing files matching a
pattern in this repo. SKIP for: git-history search (use `git log -G`/`git grep`),
binary files, or patterns that require lookaround / backreferences (the Rust
`regex` crate does not support them โ fall back to `rg -P` or `grep -P`).
|
fast-grep (fgr) โ agent usage guide
fgr is a drop-in grep replacement with an optional sparse n-gram index.
The CLI flags are intentionally close to grep/rg, so most habits transfer.
This skill captures the non-obvious behaviour so an agent can use fgr
without surprises.
Quick decision tree
Need to search this repo?
โโโ Pattern uses lookaround / backreferences?
โ โโโ Yes โ use `rg -P` or `grep -P` (fgr's regex engine doesn't support them)
โ
โโโ Does ./.fgr/ exist?
โ โโโ Yes โ fgr "<pattern>" . --index .fgr
โ โ If results look stale (recent edits missing):
โ โ fgr update . --index .fgr # incremental, <1s for small changes
โ โ
โ โโโ No โ How big is the repo?
โ โโโ Small (< ~2000 files) โ fgr "<pattern>" . # no index needed
โ โโโ Large, or repeated searches expected:
โ Ask the user before building an index
โ (build is one-time but can take ~60s on 80k+ files).
โ Then: fgr index . && fgr "<pattern>" . --index .fgr
fgr auto-builds an index on first use when --index .fgr is passed and
the directory is missing. This is convenient for small repos but don't
rely on it for unfamiliar large trees โ the implicit ~60s build is
surprising. Confirm with the user first.
Flag cheat-sheet (grep-compatible subset)
| Want | Flag |
|---|
| Case-insensitive | -i |
| File names only | -l |
| Match counts | -c |
| Line numbers | -n (default on) |
| Context lines | -A N / -B N / -C N |
| Literal (not regex) | -F |
| Invert match | -v |
| Only matching part | -o |
| Filter by extension | --type rs (see pitfalls) |
Include .gitignored files | --no-ignore |
| Use persistent index | --index .fgr |
Subcommands: index, update, stats, daemon, bench.
Output format
Matches go to stdout as path:line:content (grep-compatible).
A trailing summary like Searched in 5ms, 2 matches is written to stderr,
so fgr ... | wc -l and other pipes work the same as with grep.
Known pitfalls (verified on v0.3.1)
These are real behavioural quirks an agent must work around. Tracked in
upstream issue #6.
1. Exit code does not reflect match status
fgr exits 0 whether or not anything matched. -q (quiet) also exits 0.
Do not write if fgr "X" .; then ... to detect matches.
Instead, parse the output:
n=$(fgr -c "PATTERN" . | awk -F: '{s+=$NF} END{print s+0}')
[ "$n" -gt 0 ] && echo "found"
fgr "PATTERN" . | grep -q . && echo "found"
2. --include / --exclude glob filters are no-ops
The flags are accepted but currently do not filter results. Don't trust them.
Workarounds:
3. --type <ext> is ignored when --index is used
--type rs works on the no-index path but is silently dropped on the indexed
path. Workaround: post-filter with awk as above, or run without --index
when extension precision is required and the repo is small.
4. No lookaround, no backreferences
The Rust regex crate (which fgr uses) does not support (?=...),
(?<=...), (?!...), (?<!...), or \1 backrefs. fgr will return a
parse error. Fall back to rg -P or grep -P for those patterns.
5. .gitignore is respected by default
Like ripgrep, not like grep. Pass --no-ignore to search ignored files.
6. Index path is relative to the indexed root
If you move or rename the repo, the existing .fgr/ directory is invalidated.
Rebuild after moves.
Index lifecycle
Before the first fgr index in a new repo: make sure .fgr/ is listed
in .gitignore. Index files can be hundreds of MB (postings + bitmaps) and
must never be committed. If .gitignore is missing the entry, add it before
running fgr index.
| Operation | Command | Cost |
|---|
| One-time build | fgr index . [--output .fgr] | ~60s for 80k files |
| Incremental update after edits | fgr update . --index .fgr | <1s for 10โ100 files |
| Inspect | fgr stats --index .fgr | instant |
| Auto-update on FS changes | fgr daemon start . --output .fgr | background process |
If a search returns no results but the user expects matches in recently-edited
files, the index may be stale โ run fgr update before concluding the result
is correct, or suggest the daemon for active sessions.
When not to use fgr
- Searching git history โ
git log -G, git log -S, git grep <rev>.
- Patterns with lookaround / backreferences โ
rg -P / grep -P.
- One-off search of a single small file โ plain
grep is simpler.
- Searching binary files (
fgr skips them; use grep -a if needed).
Worked examples
fgr "frobnicate\(" . --index .fgr
fgr -c "TODO" . --index .fgr
fgr -l "struct Foo" . --type rs
fgr -i -C 2 "panic" . --index .fgr
fgr update . --index .fgr