A coding agent only sees the files its search turns up. Grep finds them when your request uses the words in the code, and an index finds them by meaning, so each one misses the requests the other catches.
Engineer's view. This is the site search that returns nothing for "refund" because the code says "reverse charge". A coding agent searches your repo the same way. Grep needs the exact word, and each miss costs the agent another turn. An embedding index matches by meaning, so it catches the plain-English requests grep misses.
TL;DR. Your coding agent finds code by guessing words, and plain-English requests make it guess wrong more often. Give it the names your code uses, or a second search that matches by meaning.
Explain Like I'm 5
You ask a helper to fetch a book from a huge library. The helper can only read the words on the spines. So they guess a word and pull every book with that word on it.
If your word is on the spine, they find it fast. If you said "the one about sad dogs" and the spine says "Old Yeller", they guess again, and again. Each guess is another trip down the aisles.
A second helper has read every book. They walk straight to the one that is about what you meant. Sometimes they bring a book that only sounds right, so the best team uses both.
The Problem
You have shipped this bug before, in a system with no model in it.
Your store's search box returned nothing for "refund". The page existed. It was titled "Reverse a charge", because that is what the billing team called it. The search worked exactly as written. It matched words, and your customers did not use your words. You fixed it with a list of synonyms.
A coding agent searching your repo is that search box, run by a model. You type "refunding twice when the customer retries". Most terminal coding agents search with grep, the command that lists files containing a word. So the model has to guess a word that is in the file. If your code says reverse_charge, its first guess misses. It tries another word, and gets back 40 files that mention payments. It narrows, and tries again.
Every one of those guesses is a search round: one search, then the model reads the result. Each round resends the whole conversation, so a search that takes four rounds costs four times the reading. The worse case is quiet: the agent stops at a file that looks right, edits it, and you review the wrong change.
I replayed 400 real Django commits as requests to a scripted grep searcher. When the request named the code, grep found the file within three rounds 75% of the time. When it was plain English, 45%.
The fix: give the agent the names your code uses, and give it a second search that matches by meaning, then measure how many search rounds it spends before its first edit.
Read the full post on The AI Commit
How a Coding Agent Finds Code: Grep Versus an Embedding Index carries the rest: the fix and why it works, the code to change for each role, how to tell it worked, when it is the wrong tool, and an interactive model you can play with.
Originally published at theaicommit.com, a daily AI engineering lab for software engineers. The original has an interactive version you can play with, and the full runnable code is on GitHub.
Top comments (2)
The 400-commit replay raises an interesting question about what counts as finding the right file. A commit can touch implementation, tests, and documentation together. Returning the test file is useful, but it is a different result from locating the implementation that actually needs changing.
I would keep those file roles separate when reporting the 75% versus 45% split, then track the first implementation edit as well as search rounds. Otherwise a searcher can improve its apparent hit rate by finding easy, descriptively named tests while still leaving the agent to locate the production behavior.
Where embedding indexes bite coding agents in production is symbol precision. A vector index is great at mapping 'where do we process checkout refunds' to the payments service directory. But once the agent needs to find every caller of process_chargeback(), cosine similarity treats five different payment helper methods as near-identical matches.
In my own harnesses, the split that holds up is two-phase: let semantic search or a flat file map narrow the candidate directory, then hand ripgrep to the agent for exact symbol definitions and call sites. Trying to make an embedding index replace regex search usually ends with the agent modifying the wrong function because the vector distance looked close enough.