# You Don't Need an LLM to Route Agent Context: Regex Beats Classifiers by 45 Points

> Source: <https://dev.to/jgravelle/you-dont-need-an-llm-to-route-agent-context-regex-beats-classifiers-by-45-points-1hb6>
> Published: 2026-07-08 18:35:19+00:00

LLM agents burn a ridiculous number of tokens on redundancy: opening the same files again and again, trying a patch, failing, then wandering back through the repo like they’ve never seen it before.

A July 2026 paper, *ContextSniper: AntTrail's Token-Efficient Code Memory for Repository-Level Program Repair*, puts real numbers behind that waste. In repository-level repair, agents keep dragging in irrelevant code and logs. ContextSniper tackles that with a context layer built around tiered memory and an **intention-aware context gate** that filters low-value regions before they ever reach the model.

That gate alone cut tokens by 51.5% on one host agent and 38.9% on Claude Code, while submitted-resolution rates stayed basically in the same neighborhood.

The gate is the interesting part, because it is not tied to that paper’s exact system. It is a more general idea, and it is starting to show up across agent architectures.

At heart, the gate is just a classifier. Given a request, it has to decide what kind of retrieval will answer the question cheapest: symbol lookup, semantic search, graph impact, mutation prep, or something else.

That leads to the practical question the paper does not really answer:

*Do you need another LLM call just to decide what context to retrieve?*

We tested that directly.

Before you can gate anything, you need a retrieval strategy. Most current systems fall into one of five rough families:

None of these is magic. Graphs are great for relationships, but they can drift away from source. RAG is useful, but fuzzy by design. Packers are simple, but expensive. Mutation runtimes are powerful, but they widen the blast radius.

The important point is that every approach still has to answer the same question:

*What should I fetch for this request?*

That decision is the gate.

An intention-aware gate looks at a request like:

`parse_config`

defined”Then it chooses the cheapest retrieval path that is likely to work.

That might be a symbol lookup. It might be semantic search. It might be a graph-impact query. It might be mutation prep.

ContextSniper uses a traceback / behavioral / stateful intent split, which is a useful framing. But it leaves an obvious engineering question for anyone building this kind of system:

*How heavy does the gate actually need to be?*

The default instinct is to reach for an LLM router, because “intent” sounds like a language-understanding problem.

We wanted to know whether that was true.

We used 140 hand-authored requests, balanced across seven dispatch classes:

The label space borrows from ContextSniper’s intent split. We ran five-fold stratified cross-validation and compared three cheap routing tiers:

| Tier | What | Accuracy | Macro-F1 |
|---|---|---|---|
| heuristic | ~40 lines of regex | 94.3% |
0.945 |
| centroid | TF-IDF nearest-class | 47.9% | 0.474 |
| logreg | TF-IDF linear | 48.6% | 0.484 |

The regex tier won by about 45 points.

The two learned models were not terrible for a seven-class problem, but they were nowhere close. Same corpus, same folds, same labels, and the dumb little ruleset walked off with the trophy.

That was surprising enough that we dug into why.

Bag-of-words models care about which words appear and how often. But for these requests, intent usually lives somewhere else. It lives in the shape of the request.

“Where is `X`

defined” and “how does caching work” do not share much useful vocabulary, but both are almost embarrassingly easy to classify from structure alone.

A `camelCase`

or `snake_case`

token usually means symbol lookup.

A leading “how does” or “why” usually means behavioral or semantic exploration.

“What breaks if I” usually means impact analysis.

“Change,” “rename,” or “set ... to” usually means mutation.

A quoted literal or bare number often means text search.

Regex sees those shapes directly.

TF-IDF mostly throws them away, then gets punished again by the tiny dataset. With roughly 16 examples per class, a sparse linear model does not have much signal left to recover.

In this experiment, the cheap learned tier was not merely unnecessary. It was worse than the rules.

Four of the 140 requests resisted both cheap tiers:

| Example Request | Why it resists cheap classification |
|---|---|
| what does the parse method look like | symbol lookup, but no definitional keyword |
| find where the timeout value 30000 appears | text search phrased like a location query |
| show me how caching is implemented | semantic vs symbol, genuinely ambiguous |
| what modules depend on the core package | graph question that reads structural |

These are not really rule failures. They are ambiguity.

And the fix for ambiguity is not always “ask a bigger model.” Often, the fix is to probe reality.

Try the cheapest grounded lookup first. If it misses, fall back to semantic search. That resolves the uncertainty by checking the code, not by paying a language model to make a better guess.

For an intention-aware gate, the order should be:

The expensive tier should be the last resort, not the front door.

That is the opposite of the usual reflex, which is to reach for an LLM router because the problem sounds like “understanding.” In practice, a lot of the signal is sitting right there in the punctuation, casing, verbs, and shape of the request.

Two points that really matter:

First, our corpus and rules share an author. So 94.3% is an in-distribution number. It proves that hand-written rules can separate hand-written requests, which is not exactly a thunderclap from Mount Science.

The number is less important than the shape of the result. Real validation needs real request logs. I would happily rerun this on a public trace.

Second, ContextSniper is convergent evidence, not an endorsement of any specific tool. It is a separate group arriving at the same architecture from the repair-agent direction: tiered memory plus an intent gate, large token savings, and resolution held roughly flat.

To be precise about “roughly,” their official validation reports 24.0% of issues resolved with the gate versus 26.0% for the baseline, which they describe as comparable while also noting a validation-error imbalance.

The important signal is that two independent lines of work are landing in the same place: context gates matter. The exact accuracy of one regex tier is not the point.

The gate sits above whatever retrieval family you use.

In our stack, it routes into a grounded read-only retriever, [jCodeMunch](https://github.com/jgravelle/jcodemunch-mcp), because byte-exact symbol source is often the cheapest correct answer to the most common kind of request.

But the routing lesson is not specific to jCodeMunch. It applies whether you retrieve by symbol, graph, vector, or whole-repo packing.

The thing deciding what to retrieve should be cheap first, deterministic second, shape-aware third, and “smart” only when it has no cheaper option left.

For the full map of the five families and where different tools fit, there is a running [field guide to code-context tools](https://jcodemunch.com/field-guide.php).

**Links:** [ContextSniper (arXiv 2607.01916)](https://arxiv.org/abs/2607.01916) · [field guide to code-context tools](https://jcodemunch.com/field-guide.php) · [jCodeMunch](https://github.com/jgravelle/jcodemunch-mcp)
