I spent five months building a context engine on a premise I never checked.
The premise seemed too obvious to test. An AI coding agent given a task starts by looking around: it greps for a symbol, opens whatever the grep turned up, then greps again with a better guess. Each of those searches reads from disk, which costs very little when a single agent is doing it. I run fleets, so ten agents rediscover the same codebase ten times over and discard all ten results when their sessions end. Navegador was my answer to that. It parses a codebase into a graph once, holds the graph in memory, and lets every agent query the same index rather than deriving its own. The name is Spanish for navigator.
Last week I instrumented it for the first time, and the data disagreed with the premise.
Session telemetry
I pulled 151 agent sessions from 25 projects, about two months of my own work and roughly 58,000 tool calls, then counted the operations instead of assuming them. Filesystem reads came to 0.45 per minute of active work, which is about 35 reads in a session averaging fifty-four minutes. An agent working at that rate looks something up occasionally rather than thrashing a disk. The scoping numbers were worse for my premise: 96.5% of searches named a file, listed several files, or restricted themselves to a single subdirectory, leaving 3.4% that swept an entire tree.
I had also built a contention benchmark, and it is sound work. Throughput pins at 3.3 sweeps per second once two agents run concurrently, so any agent added past that point buys no additional work and pays for the attempt in latency. What that benchmark measures is the 3.4% case. I had spent five months building against a behaviour I never confirmed was expensive, for the straightforward reason that it was the behaviour I already knew how to measure.
Sharing and traversal
Sharing came out of the audit intact. Nine codebases on this machine compress to roughly 119 MiB of graph. Ten thousand agents each holding a private copy would need 1.19 TB, while sharing one keeps it at 119 MiB and the ten-thousandth agent costs a socket. Grep’s speed has no bearing on that arithmetic. It follows from N agents needing the same facts, which is a property of the fleet rather than of the search tool, and it gets stronger as the fleet grows.
Traversal also survived, and it is the part of the original idea I would defend hardest. Asking Navegador for the files reachable from a symbol returns 2 out of 264, because it follows calls and imports rather than matching characters. A text index knows which files contain the word “token”. A graph knows which files connect to the one being changed.
The gap there is wider than a latency comparison makes it look. Grep answers a lexical question, which bytes appear where, while the question in front of you when you change code is structural, about what calls this and what breaks if it moves. The lexical answer usually stands in for the structural one well enough, which is why grep has lasted forty years and why I still reach for it first. The two come apart where being wrong costs the most. Searching for a function named run returns forty files, thirty-eight of which define some other run. Searching for a symbol reached through dynamic dispatch or a re-export can return nothing at all, and an empty result reads the same whether the symbol is genuinely unused or simply unreachable by string match. Grep fails silently rather than slowly, and an agent reading its output has no way to separate a real absence from a missed one. Traversal along the edges a compiler would follow does not fail in that direction, because it answers the question that was actually asked.
So the tool has value. The value is not the one I designed for, and that difference decides what gets built next.
Maturing the premise
Something has to be the cost if disk is not, and the same telemetry identifies it. Sessions run a median of 206 tool calls, and thirteen of those pass before the agent touches the file it ultimately edits. Of all file reads, 32% reopen a file already read in the same session, which is an agent losing its place and paying a second time to recover it. Those turns cost inference latency and context window rather than IOPS, and inference is the expensive resource in the system. The constraint was never the storage subsystem but the number of round trips an agent needs before it knows where to look.
That changes the job. Navegador should not answer questions about code, because an answer is something an agent has to trust and has no way to verify. It should report where to look and leave the reading to grep. Version 1.6 does that with three tools that return ranked locations along with the reason each one surfaced, and that refuse to synthesise a conclusion from them.
Whether it helps is still unknown. The re-measurement reads fourteen turns against a baseline of thirteen, which is not a result: the tools shipped hours before the measurement and no agent had used them yet. Treating that number as a win would repeat the error I had just spent the release fixing.
Maturing the experiment
The instrument is the part I am most confident about, because it can come back negative. When a targeting call hands an agent a set of locations, the measurable question is whether the file the agent then edits appears in that set. The call, the result and the edit all sit in one transcript, so the question resolves directly, with no control group and no second population to compare against. A tool that is not helping will show up in that number without any cooperation from me.
The bugs are why I now care more about the instrument than about any reading it will produce. Almost every serious defect this cycle had a single shape, which is that the tool reported success while disagreeing with the code on disk. Export and import dropped every edge and returned success. Incremental ingest never removed deleted files, so impact queries cited functions that had been gone for weeks. One graph turned out to be 99.98% gitignored build output, indexed faithfully, every path resolving. No exception was raised and no warning printed. An exception at least identifies its own location, whereas a wrong answer returned with confidence propagates into whatever the agent does next.
The tests contributed to this. The export defect survived for months because the tests mocked the storage layer, where a fake write always succeeds, so the test encoded the bug rather than catching it. Coverage read 94% throughout, and all of those defects shipped inside covered lines, because coverage records that a line executed and not whether anything checked its effect.
The lesson generalises past graphs. Measure the claim rather than the convenient proxy, and leave the measurement free to come back negative. Mine came back negative, and the tool improved for it, aimed now at a cost I can demonstrate instead of one I assumed, and carrying an instrument that remains able to contradict me.
Navegador is open source at github.com/ConflictHQ/navegador under the MIT license, with docs at navegador.dev. Built by CONFLICT.