Independent AI intelligence Two editions daily · ET
Fervor AI

Analysis · September 9, 2026 · repo

microsoft/tgrepripgrepagent-harnessagent-infrastructureclaude-codecodex

microsoft/tgrep Is 52x Faster Than ripgrep, and the 52x Is a macOS Number

What trigram-indexed search really buys a coding agent, why the same repo shows 51.9x on macOS and 7.36x on Linux, and the two flags that can silently empty your index

Read the tgrep benchmark table top to bottom and a strange thing happens. Same repository, gecko-dev, 388,000 files. On macOS arm64, ripgrep takes 33,402ms per query and tgrep takes 643ms, a 51.9x margin. On Windows, 17,841ms against 463ms, 38.6x. On Linux, 1,195ms against 162ms, and the margin collapses to 7.36x.

The index did not get worse on Linux. ripgrep got faster. Its number dropped from 33 seconds to 1.2 seconds on identical work, which means the thing the 51.9x is mostly measuring is not how good the trigram index is. It is how badly the host operating system handles walking 388,000 files.

Microsoft made tgrep public this week, and it is already the search backing GitHub Copilot CLI's grep on large repositories. That makes it worth understanding properly rather than by headline, because a coding agent doing repeated regex scans over a monorepo is exactly the workload it was built for, and the honest version of its pitch is more useful than the marketing version.

What the index actually does

ripgrep scans every file on every search. That is O(total bytes) per query, and it is the correct design for a one-shot tool you run by hand: no state, no daemon, no staleness, nothing to invalidate.

tgrep pre-builds a trigram index. It walks the repo, extracts every overlapping 3-byte sequence from each text file, and writes a compact inverted index mapping trigrams to file IDs. When a query comes in, the regex is decomposed into literal fragments, those fragments become trigram hashes, the posting lists are intersected or unioned, and only the surviving candidate files get verified with the full regex engine. The scan still happens. It just happens over a set of files that could possibly match instead of over all of them.

Three commands:

tgrep index .     # build the trigram index
tgrep serve .     # start the server, which watches for changes
tgrep "fn main" . # instant, auto-connects to the running server

The architecture is an mmap'd on-disk index plus an in-memory overlay for files modified after the server started, merged by a hybrid layer where the overlay wins. Every 50,000 files or five minutes, the in-memory side flushes to disk and the reader swaps, which is how memory stays bounded on a repo that never stops changing.

That is a real engineering artifact, and I want to be clear that the criticism below is about how the number is read, not about whether the work is good.

Where the margin comes from

The README is more honest about this than the headline is. It states plainly that tgrep wins 17 of 18 measured cells, and that the exception is Kubernetes on Linux at 0.93x, a near-tie where the index loses. It also says the margin depends on repository size and on how many matches a query returns, because a search returning tens of thousands of matches spends more on delivering them than the index saves on finding them.

Put the platform rows next to each other and the pattern is hard to miss:

Repo Platform ripgrep tgrep Speedup
gecko-dev macOS arm64 33,402ms 643ms 51.9x
gecko-dev Linux 1,195ms 162ms 7.36x
chromium macOS arm64 41,806ms 2,643ms 15.8x
chromium Linux 2,404ms 631ms 3.81x
linux macOS arm64 5,390ms 256ms 21.0x
linux Linux 427ms 46ms 9.38x

ripgrep on Linux is between 10x and 28x faster than ripgrep on macOS on the same repositories. tgrep is faster than ripgrep everywhere except one near-tie, but the size of the win tracks the baseline's misery. If you are on Linux, the honest expectation is something in the 4x to 9x range, not 52x. If you are a developer on an Apple Silicon laptop searching a 400,000-file monorepo, the 52x is real, and you were the person suffering most.

One small note on the number itself, since precision is the whole point of this piece. The README says "up to 52x faster." The measured maximum in the table is 51.9x. That is rounding, not inflation, and I am flagging it only so you know which figure came from a measurement.

What this changes for a coding agent

Here is why any of this matters more for an agent than for a human at a terminal.

A person searching a repo does it a handful of times an hour and absorbs a two-second wait without noticing. An agent working through a task does it constantly, often in a loop, often with slight variations on the same pattern, and every one of those searches is a turn where the model is waiting and the context is filling up with results. A 33-second grep is not just slow. It is a turn that times out, or a turn the harness retries, or a turn whose output gets truncated in a way that makes the model guess.

Turning that into a 643ms lookup changes the shape of what the agent can do, not just how fast it does it. Searching becomes cheap enough to be exploratory rather than something the agent has to plan around.

That is the actual argument for tgrep in an agent harness, and it survives even at 4x.

Put this into practice

Fifteen minutes, on one repo, measured before and after.

Install.

brew install tgrep

Or from source:

git clone https://github.com/microsoft/tgrep.git
cd tgrep
cargo install --path tgrep-cli --locked

Pre-built binaries for Linux, macOS Intel and Apple Silicon, and Windows are on the releases page. Current release is v1.0.5, dated 2026-09-08.

Measure your own baseline first. This is the step people skip, and it is the only one that tells you whether any of the above applies to you.

time rg "some_real_pattern_you_actually_search" .
tgrep index .
tgrep serve . &
time tgrep "some_real_pattern_you_actually_search" .

Use a pattern from your actual work, not a synthetic one. Match count drives the margin, and a pattern returning 40,000 hits will look very different from one returning 12.

Read the query plan when a result surprises you.

tgrep "pattern" . --stats

--stats prints the query plan and candidate statistics, which is how you find out that your regex decomposed into a trigram set so common the index selected half the repo.

Point your agent at it. The repo ships an AGENTS.md for exactly this. tgrep implements ripgrep's flag surface closely enough that --json emits a ripgrep-compatible stream and --vimgrep emits the standard file:line:col:content rows, so most harness integrations are a binary swap rather than a parser rewrite.

Keep index and serve flags identical. This is the one that will bite you, and it is worth reading twice.

Flags that decide which files belong in the index (--no-require-git, --no-ignore, --max-filesize, --exclude) must match between the tgrep index that built an index and the tgrep serve that serves it. The server compares the index against the filesystem at startup and treats an indexed file it cannot see as deleted. Serve an uncapped index under a --max-filesize 8M server and every file above 8 MiB is dropped from that index, permanently. Both sides default to 64 MiB, so this only fires when one side names a limit, which is precisely why it will fire in a script somebody wrote at 11pm.

tgrep index . --max-filesize 8M
tgrep serve   --max-filesize 8M

Honest limitations

The default 64 MiB file cap makes a match into a non-match. tgrep skips files larger than 64 MiB by default, a deliberate divergence from ripgrep, which has no default limit. The README explains the reasoning well: a file the walk picks up is a file the index carries and re-reads on every query that makes it a candidate, so an outlier costs repeatedly rather than once. On one 292,911-file enlistment where a single 13.41 GiB build artifact was 71% of all searchable bytes, the cap cut a cold build from 214.5s to 64.2s and a warm query from 21.30s to 0.55s. The cost is stated just as plainly: an oversized file is counted but its path is never recorded, so a match inside one is reported as no match. --no-max-filesize restores ripgrep-identical behavior. Decide which failure you would rather have.

A cold server returns nothing rather than an error. When tgrep serve has to build an index from scratch, queries during that first build are answered from an empty index and return no results, with tgrep status reporting that indexing is in progress. An agent that cannot read tgrep status will interpret an empty result as "this string does not exist in the codebase," which is a wrong answer delivered confidently. Build the index before the agent starts, or teach the harness to check status.

You are now running a stateful daemon over your source. A TCP JSON-RPC server, an mmap'd index on disk, a 50,000-entry content cache, and a filesystem watcher registering inotify subscriptions on Linux. The default watch budget is 8,192 subscriptions, and the README is careful to say that is a conservative process-local ceiling rather than an estimate of free capacity, because the Linux inotify quota is shared with every other process running as you. Exceed it and the whole process switches to polling, and that fallback is sticky until restart. None of this is hidden, and all of it is a thing you did not have before.

Every benchmark on the page is the project's own. Eighteen cells, one repo family, Microsoft's hardware, Microsoft's queries, published alongside the tool. That is normal for a launch and it is still self-measurement. The Kubernetes-on-Linux near-tie being included is a point in the project's favor, and it is also the number that tells you these are not adversarial benchmarks.

Contributions require a Microsoft CLA. MIT licensed, copyright Microsoft Corporation, but most contributions require agreeing to the Contributor License Agreement at cla.microsoft.com. Worth knowing if you were planning to upstream a fix rather than carry a patch.

What to do with this

Do not adopt tgrep because of 52x. Adopt it, or do not, based on one measurement you take yourself: time your agent's most common grep pattern on your actual repository on your actual machine, then time it again with the server warm. If you are on Linux with a mid-size repo, you may find a 4x improvement that is not worth a daemon. If you are on a Mac with a 400,000-file monorepo and a coding agent that greps in a loop, you may find the number that made this repository trend.

The broader habit is the one worth keeping. When a tool's headline speedup is enormous, the first question is not whether the tool is good. It is what the baseline was doing to earn a number that large. Sometimes the answer is that the new thing is remarkable. Sometimes the answer is that your operating system has been charging you 33 seconds a query for years and nobody sent you the bill.

Go find out which one you have.

Sources: microsoft/tgrep README and BENCHMARKS.md, read 2026-09-09; release v1.0.5, dated 2026-09-08; GitHub Copilot CLI.


Medium metadata

  • Title: microsoft/tgrep Is 52x Faster Than ripgrep, and the 52x Is a macOS Number
  • Subtitle: What trigram-indexed search really buys a coding agent, why the same repo shows 51.9x on macOS and 7.36x on Linux, and the two flags that can silently empty your index
  • Tags: Developer Tools, AI Agents, Rust, Open Source, Programming
  • Recommended topic: Programming
  • Canonical: import from the fervorai.dev URL