Everyone knows optimized Rust is faster than Go, right? So why chase meeting or beating ripgrep’s speed with an optimized port in Go?
Let me get this out of the way. I love Rust. And I have massive respect for ripgrep and the engineering that went into it. Big shoutout to Andrew Gallant and everyone that’s contributed. But as I sat at my desk, building out a new agent harness in Go, I had a passing thought:
What if instead of needing to shell out to ripgrep, we could meet or beat its speed in Go with a CLI/SDK? And what if I wasn’t allowed to write a single line of code by hand, but had to do all of the work with AI?
Well, it’s more than possible. Meet gripgrep. It’s currently got the majority of ripgrep flags supported and is continually meeting or beating most of the benchmarks.
That said, the build itself matters less than what it taught me about driving agents through a hard optimization problem.
Quick Strategy Overview
With Fable 5 still available in the Claude Code plan, I figured it’d be a great opportunity to kick the tires. Fable’s role would be two-fold:
- Complete the initial research
- Orchestrate/Review/Create follow ups for each round of work
- Each round to be completed by a Sonnet-based agent with an Opus advisor, following the plan designed by the Fable-based orchestrator agent in Claude Code
- After building the key features, we’d loop till we meet or beat the scores on core features consistently
- Afterward, fill in the other missing features and ensure they performed well
Lessons Learned
Most of the time, as you’d expect, was spent on optimizing to lean on Go’s strengths. Here’s what I learned along the way.
Pick a benchmark with a real ground truth
The value of this experiment came from choosing a target that couldn’t be faked. ripgrep is a well-respected CLI with 100+ flags, meticulously engineered for speed, written in a systems language. Reimplementing it in a garbage-collected language gave me an unambiguous scoreboard: either gripgrep matched ripgrep’s output and speed, or it didn’t.
When you want to stress-test an agent (or a model), give it a problem where success is externally verifiable and the horizon is long. Vague tasks let both you and the agent declare victory too early. A hard reference implementation won’t.
This benchmark needs to be as consistent as possible, and the agent needs to be able to kick it off and report back. This enables the autoresearch style loops.
Find the real constraint before you optimize anything
The single most important research finding shaped everything after it: to compete, gripgrep had to minimize time spent in regex. Go’s regexp runs in guaranteed linear time, which is great for safety but won’t set speed records out of the box.
Identifying that core constraint early meant every later optimization pointed in the same direction. Spend real effort up front figuring out where the actual bottleneck lives, because it determines which experiments are worth running at all.
Ground the agent in evidence, not common wisdom
The biggest time-sink was the agent reaching for common, plausible-sounding solutions that weren’t grounded in what was actually happening. That wastes time, tokens, and money.
The fix was forcing it to profile before proposing: count syscalls (like read operations), compare rg against gg directly, and require hard evidence of a gap before writing a single optimization. This turned low-odds guesses into high-leverage experiments with far better success rates.
The general principle: an agent will happily pattern-match to “how people usually make things fast.” Make it measure first. Evidence-gated experiments beat idea-generated ones.
Give the agent the right instruments
Grounding only works if the agent can actually see the ground truth. That means putting the right local tools in its hands—strace, pprof, and similar profilers—so it operates from real data instead of assumptions.
It’s the same lesson as running distributed systems with great observability tooling: higher quality data from the tooling enables higher quality decisions.
Trust your measurements—and control the environment
Measurement itself was a challenge, especially on Mac runners in GitHub Actions. Scores swung wildly between runs at first. Background processes, Spotlight indexing, and noisy runners all polluted the numbers. The fix was consistent local scoring in a controlled environment so a change in the benchmark actually reflected a change in the code, not the machine. With a few tweaks on the setup, I was able to reduce the noise, but it’s not perfect.
If your feedback signal is noisy, every optimization decision downstream is built on sand. Stabilize measurement before you trust it to guide the loop.
(Still fighting benchmark variance on macOS—if you’ve solved this cleanly, I’d love to hear how.)
Despite those challenges, having consistent benchmarks that could be executed remotely by an agent meant progress could be made continuously.
Where it landed
After a couple of days, gripgrep meets or beats ripgrep on a lot of benchmarks. Is it battle-tested and production-ready? Probably not. But I’ll be using it in my next agent harness, right along with continuing to build on this same workflow.
Till next time!