Thank you for this incredible software
@neogoose_btw π«Ά
TLDR: I migrated ffgrep rg to fff after benchmarks showed...
- 3.5x faster plain search
- 5.3x faster regex
- ~9x on the target-corpus gate
But speed only earned consideration. Shipping required correctness sentinels, zero-match checks, stable output contracts, hard limits, deterministic behavior, and fallbacks.
The whole story:
I've been working on Magi-code, a private coding harness I'm using in production environments. Recently I came across `fff` and the hype around it so dug in and eventually I migrated `ffgrep rg` to `fff` but it was a process of validation and proof.
I started with a lower blast radius: path discovery first (`fffind`), then benchmarks, then content-search benchmarks, adapter prototype, contract decisions and ultimately default switch.
**Benchmarks came before migration:**
Path search showed obvious wins:
- cold unfiltered p95: 160ms vs 294ms
- warm unfiltered: 2.3ms vs 250ms
- repeated query: 1.7ms vs 231ms
Content search was stronger:
- plain search: 50/50 wins, median p95 speedup 3.5x
- regex search: 30/30 wins, median p95 speedup 5.3x
- target-corpus adapter gate: 28/28 wins, median speedup ~9x
Beyond speed, we needed contract and quality so we checked: known literal regex sentinels, zero-match mismatch checks, cwd-relative, slash-normalized paths, hard visibile-line limits, deterministic output, context bounds.
Fallbacks are important too, sometimes things just don't work in different environments. Smart fallback path: `fff` -> `rg` -> Rust regex walker
Important caveat: this was not a relevance/ranking benchmark. It was also not byte-for-byte `rg` equivalence; I intentionally separated product contract from implementation detail, particularly because we have only internal users and don't need backwards compatibility.
- Exact `rg` traversal order? Not product contract
- Exact context subset under tiny limits? Not product contract
- Stable output shape, limits, path semantics, safety, and fallback? **Product contract**
Migration can be super simple if you migrate behavior contracts and not implementation details.