glep

Indexed grep + glob for AI agents.

ripgrep pays the full scan cost on every query. glep pays it once: a persistent, self-healing trigram index answers warm searches in milliseconds, with text output byte-identical to ripgrep's.

pip install glep cargo install glep github.com/anishfyi/glep →
let hits = index.lookup("gle");

every 3-byte window of your code is indexed once; queries become lookups, not scans

the honest part

When to use it

glep is a specialist. It wins when the same tree gets searched again and again; it loses to a cold ripgrep run exactly once, while building its index.

Use glep Stick with rg / fd
Coding-agent sessions that fire dozens of Grep/Glob calls over one repo. The bundled Claude Code hook reroutes them automatically. pays the scan once, answers every call after from the index One-off searches in a tree you will never search again. the first query costs a full scan either way; no payback
Monorepos and large trees where ripgrep takes hundreds of milliseconds to seconds per query. measured: 21 ms burst, 173-298 ms with the full sweep Small repos where rg already answers in under ~50 ms. indexing overhead nets you nothing measurable
Repeated file listings: glep --files '**/*.rs' answers from the manifest with no directory traversal. fd-style listings without touching the filesystem tree Ephemeral environments (CI runners, throwaway containers) where the index never survives to be reused. cold build per run means rg is simply cheaper
Read-heavy exploration bursts: add --ttl 5 to amortize the freshness sweep across consecutive queries. sweep once, answer many Features glep does not have: replacements, PCRE2, compressed files. rg has a decade of surface area; glep covers the agent 95%
Anywhere correctness is non-negotiable. Every query self-heals (mtime sweep, incremental reindex); patterns the index cannot narrow fall back to a full parallel scan. never a wrong answer; worst case is rg-speed Corpora that are mostly binaries or files over the 1 MB cap. Those files skip the index and get live-scanned anyway. an index that indexes nothing is pure overhead
under the hood

How it works

  1. Index once. A gitignore-aware parallel sweep reads your tree; every distinct 3-byte window lands in a memory-mapped postings file under .glep/, a few percent of corpus size.
  2. Self-heal on every query. A fast mtime sweep diffs the tree against the manifest; only changed files are re-indexed, into a log-structured delta segment. Edit a file, search, see it. Always.
  3. Narrow, then match. Your regex becomes a trigram plan; postings intersection shrinks 20,000 files to the handful that can match; ripgrep's own engine runs over just those.
  4. Stay honest. Output is byte-compatible with rg, exit codes match, and a differential harness in CI compares every release against real ripgrep.
receipts

Verified, not vibes

21 ms

warm query on a Linux kernel checkout (86,605 files) with --ttl; 173 ms paying the full self-healing sweep (macOS bulk-attribute fast path); ripgrep on the same box: 1.4 s

22/22

pattern cases byte-identical to ripgrep in the differential parity harness, including Unicode case folding, multiline, counts, and context

0

daemons, watchers, or background processes; one binary and one directory of index files