I knew I had written down an MCP timeout value somewhere. I could not find it. When I asked the agent to locate every mention of timeouts, it came back with 451 candidate files — 8 MB of text. That is not a list you read.
Antigravity 2.12 improved partial matching for filename search, and that failure came straight back to mind. Searching by name shrinks the candidate set dramatically. What I had never checked was what gets dropped along the way. So I measured both against a repository of 2,088 files.
One word, two very different answers
The corpus is 2,088 Markdown files across two languages, 34 MB in total. It has grown steadily over years of indie developer work, so it is a realistic size rather than a toy.
Searching for the single word "timeout":
| Method | Hits | Bytes if all opened | Time (mean of 5) |
|---|---|---|---|
| Partial filename match | 8 files | 128 KB | 5 ms |
| Full-text search (ripgrep) | 451 files | 8 MB | 15 ms |
The search itself is only 3x apart. Both finish instantly as far as a human is concerned.
The gap opens afterward. An agent narrows the candidates, then reads them. That reading cost differs by 67x. Hand it 451 files and 8 MB, and the context window fills, the bill climbs, and the wait stretches. Choosing a search method is not a question of search speed. It is a question of how many bytes get read next.
If ripgrep is unavailable, this premise shifts entirely. I measured that scenario separately in How Much Slower Search Gets When /codesearch Cannot Run ripgrep.
Filenames carry topics; bodies carry symptoms
So should you just lean on filename search? Not quite. Run the same comparison on error strings and syscall names, and the result inverts.
| Term | Filename hits | Body hits |
|---|---|---|
| ENOSPC | 0 | 13 |
| ECONNREFUSED | 0 | 9 |
| SIGKILL | 0 | 14 |
| flock | 0 | 18 |
| IPv6 | 0 | 6 |
| ETIMEDOUT | 0 | 9 |
| EADDRINUSE | 2 | 10 |
| FORBIDDEN | 2 | 9 |
| Total | 4 | 88 |
Four hits out of eighty-eight. That is 4.5%. Delegate to filename search alone and you miss 95% of the places those errors are discussed, while getting a confident "nothing found" in return.
Topic words behave better. Ollama matches 16 filenames against 121 bodies (13%), Stripe 26 against 249 (10%), AdMob 22 against 329 (7%). Still roughly one in ten. Filename search surfaces the articles where something is the subject, never the ones where it comes up in passing.
There is a practical reading of that table. Filenames answer "what is this file about," while bodies answer "what happened while writing it." Debugging questions are almost always the second kind. When I search my own notes it is nearly always because something failed and I half-remember writing the fix down — which is exactly the case filename search cannot serve.
The asymmetry is not an implementation quirk. A filename is a label the author wrote to summarize the subject. Symptoms and API names live only in the prose. However clever filename matching becomes, a string that was never written into the name will not appear.
Partial matching only sees contiguous runs
There is a second trap. Partial matching compares contiguous substrings, so a different word order simply misses.
Looking for files about MCP timeouts by name, in the same repository:
# As a contiguous substring
find content/articles -iname '*mcp-timeout*' # -> 2 files
find content/articles -iname '*timeout-mcp*' # -> 0 files
# Both words, order-independent
find content/articles -iname '*mcp*' -iname '*timeout*' # -> 4 filesThe actual filenames explain it:
antigravity-mcp-timeout-seconds-boundary-latency-sizing.mdx
antigravity-cli-mcp-unresponsive-timeout-per-operation-design.mdxThe second one has unresponsive sitting between mcp and timeout, so *mcp-timeout* never reaches it. Reverse the order and you get nothing at all.
I used to stop at "the name search found 2 files, so that is all of them." It was half. Chaining -iname twice gives you an AND, which is what multi-word lookups actually need. The same applies when you instruct an agent: ask for files containing both mcp and timeout, not files containing mcp-timeout.
Frontmatter was quietly ruining full-text search
Full-text search has its own Markdown-specific failure mode.
Every file here opens with YAML frontmatter, and keys like premium: false appear in all of them. That makes full-text search on those tokens meaningless.
# Full text, frontmatter included
rg -li premium content/articles -g '*.mdx' | wc -l # -> 2023
# Body only: everything after the second ---
for f in $(rg -li premium content/articles -g '*.mdx'); do
awk 'c==2{print} /^---$/{c++}' "$f" | grep -qiF premium && echo "$f"
done | wc -l # -> 1112,023 of 2,088 files match — 97%. Restricted to bodies, it is 111. Nearly a 20x inflation.
Search on any frontmatter key or metadata value (premium, category, level, tags) and almost everything comes back. From the agent's side this is worse than "no results," because it looks like a narrowed set while actually being the whole corpus. For a long time I blamed my query phrasing.
Since Antigravity 2.11.0, frontmatter renders as a formatted metadata card, so it no longer clutters the reading view. The search index still treats it as body text. Elements that disappear visually are exactly the ones that trip you later.
Three approaches, measured for recall as well as cost
With that in hand, I looked for "articles covering MCP timeouts" three ways, using the full-text AND as the baseline.
| Method | Hits | Recall | Time |
|---|---|---|---|
| A: full-text AND of MCP and timeout | 55 | 100% (baseline) | 36 ms |
| B: narrow filenames to mcp, then grep timeout | 18 | 33% | 12 ms |
| C: narrow by directory, then full-text AND | 28 | 51% | 15 ms |
# A: full-text AND (baseline)
rg -li timeout content/articles -g '*.mdx' | tr '\n' '\0' | xargs -0 rg -lFi 'MCP'
# B: narrow by filename, then search bodies
find content/articles -iname '*mcp*' -print0 | xargs -0 rg -lFi 'timeout'
# C: narrow by directory, then search bodies
rg -lFi 'MCP' content/articles/*/integrations -g '*.mdx' \
| tr '\n' '\0' | xargs -0 rg -lFi 'timeout'B is fast and finds a third of what exists. The 37 files it drops are not noise: they discuss MCP timeouts in passing without carrying mcp in the name. C narrows along a different axis and keeps half, because a directory groups files by subject area rather than by whichever words the author happened to put in the name. That is the general lesson — narrow on an axis that was assigned deliberately, not one that emerged from writing habits. All three land within tens of milliseconds of each other, which is noise in practice. I had assumed the tradeoff would be speed against thoroughness. It was not. Every method returns before you can notice, and the only variables that matter are how much you miss and how much the agent has to read.
So filename search is not something you pick for speed. Speed barely moves. What moves is recall, and how much text gets read afterward. Those numbers settled my own rules:
- When hunting an error string, symbol, or API name, skip filename search and go straight to full text. At a 4.5% hit rate, name matching is not narrowing — it is losing.
- When hunting a topic and one representative article is enough, filename search does the job. It is the wrong tool when coverage matters.
- When coverage does matter, narrow by directory rather than by name, then run full text. Recall goes from 33% to 51%, and reading cost stays at half of the exhaustive search.
Antigravity 2.12's partial matching improvement does not change cases 1 or 3. It helps case 2 — the moment when you already know which file you want to open. There, it genuinely got faster.
Measure your own naming conventions next
The 4.5% and 33% figures above are products of how I happen to name files. A repository that puts error codes into filenames would produce entirely different ratios.
Rather than carrying my numbers home, run the same three commands against your own tree. It takes about a minute and the answer is specific to you. Pick five error strings, compare filename hits with body hits, and look at the ratio. If it sits below ten percent, instructing an agent to search by name is premature.
For deciding the timeout values themselves, I left the measurements in I Measured Before Writing a Number: MCP Connect and Tool Calls Differed by 486x.
This has been a lot of counting, I know. But get the entry point of a search wrong and everything downstream — the reading, the reasoning, the decision — drifts with it.