Current-generation LLMs can already explore and edit code with files, search, and shell. Any proposed workflow improvement must beat that baseline before it earns another interface.
This article started with a Sunday meditation from Pi:
Good morning from Vienna People of Pi 🌞
— Pi (@pidotdev) August 16, 2026
Sunday meditations from @badlogicgames and @mitsuhiko
- On memory: code is the truth
- Bash is all you need
- Build context efficient tools pic.twitter.com/yZQe6KtWgh
The video's three points reinforce each other. The repository is the memory:
code is the evolving ground truth, while a semantic memory is another system to
maintain. Models can infer structure and style from a few files and rg
results. They also speak shell and can compose their own workflow. In the
video's Sentry example, a skill downloads 52 results as JSON, puts only three in
context, and leaves the rest available through jq. The goal is not Bash for
its own sake, but composability within a deliberate context budget.
Current models make general-purpose primitives unusually powerful because they write the glue themselves. Every extra index, protocol, or specialist must therefore prove an end-to-end gain at equal quality—not merely a cleaner query or smaller tool response. I tested that standard against semantic navigation.
Testing the strongest case
gopls is the strongest case for giving an agent more
than grep. The official Go language server powers completion, diagnostics,
rename, Go to Definition, and Find All References. It also exposes a CLI:
gopls definition path/to/file.go:#offset
gopls references path/to/file.go:#offset
gopls implementation path/to/file.go:#offset
gopls call_hierarchy path/to/file.go:#offset
Unlike ripgrep, gopls resolves symbols. Its
navigation queries distinguish
same-named methods, follow cross-package references, and find concrete types
that implicitly implement an interface. But its
CLI is officially experimental and mainly
intended for debugging; one-shot use can pay startup costs unless it connects to
a daemon. Precision brings a server, project model, source positions, and a new
interface.
I'm writing Go again (for what, you'll see later...). `go doc` and `gopls` are like agent superpowers and its shocking how productive agents are out of the box at writing [good] Go code versus other languages I've used (including the JS ecosystem). Also, Go + Zig is a good mix.…
— Mitchell Hashimoto (@mitchellh) April 20, 2026
That trade starts asymmetrically. Work usually begins with a bug report,
behavior, or name—not an exact source position. Models already turn those clues
into rg queries, targeted reads, and follow-up searches. Semantic navigation
can return a more precise intermediate answer without simplifying the whole
task. In my experience, Go agents remain just as effective with ripgrep; I have
not run a controlled gopls-versus-ripgrep benchmark, so this is an
observation, not a quantitative claim.
TypeScript goes native
On July 8, 2026, Microsoft released TypeScript 7.0, the native Go port of its compiler and tools. Microsoft reported typical full-build speedups of 8Ă— to 12Ă—, lower memory use, and a much faster LSP-based language server. Because the compiler, project system, and language service now coexist as Go packages, a fork can link them into a standalone binary. That made semantics cheap enough to package as a shell tool and test fairly.
Building tspls
I built tspls, a gopls-style CLI for
one-shot TypeScript queries:
tspls definition src/app.ts:12:8
tspls references -d src/app.ts:12:8
tspls call_hierarchy src/app.ts:12:8
tspls implementation src/app.ts:12:8
tspls check src/app.ts
tspls runs TypeScript 7's native project and language-service packages
in-process. It uses no LSP server, JSON-RPC connection, daemon, child tsgo
process, or persistent index. Each invocation discovers the workspace's
tsconfig.json files, opens its projects in one session, prints stable file
spans for one query, and exits.
GPT-5.6 Sol built the initial implementation in about 40 minutes at high reasoning. This gave semantics every architectural advantage while preserving its real costs: another interface and exact source positions. The benchmark asked whether its cleaner answers justified those costs.
The benchmark
I ran three benchmarks on Listenbox. Two asked agents to find every consumer of a distinctive name. The third used a common name with unrelated textual matches: the case most favorable to semantic navigation.
Each task had two arms. One agent could use the tspls skill; the other had only
ripgrep and ordinary file reads. Both ran
GPT-5.6 Luna at
max reasoning with fixed prompts and sandbox. Answers were graded blind
against a static oracle. Every included answer scored 100/100, leaving
efficiency as the difference. Output-token counts include reasoning tokens.
| Three-task aggregate | tspls | ripgrep | Observed difference |
|---|---|---|---|
| Correctness | 300/300 | 300/300 | Same answer quality |
| Total input tokens | 1,116,125 | 1,078,545 | ripgrep used 37,580 fewer (3.4%) |
| Cached input tokens | 999,424 | 930,688 | tspls used 68,736 more cached |
| Uncached input tokens | 116,701 | 147,857 | tspls used 31,156 fewer (21.1%) |
| Output tokens (reasoning included) | 35,117 | 32,300 | ripgrep used 2,817 fewer (8.0%) |
| Estimated API cost | $0.08547 | $0.08695 | Only $0.00148 apart (1.7%) |
| Tool calls | 35 | 40 | tspls made five fewer (12.5%) |
| Files opened | 14 | 54 | tspls opened 40 fewer (74.1%) |
| Tool output | 148,545 bytes | 244,275 bytes | tspls emitted 95,730 fewer bytes (39.2%) |
| Wall time | 687.830 s | 649.971 s | ripgrep finished 37.859 s sooner (5.5%) |
For the collision-heavy task, I averaged two clean repeats. I rounded its token and tool-call averages to whole units before computing the aggregate.
tspls reduced repository reads, tool calls, and tool output. Ripgrep still
used fewer total input and output tokens and finished 5.5% sooner, with equal
answers. Estimated cost was effectively tied because tspls traded 31,156
uncached tokens for 68,736 cached ones. At GPT-5.6 Luna's standard
rates—$0.20
per million uncached input tokens, $0.02 per million cached input
tokens, and $1.20 per million output tokens—the estimates are $0.08547 and
$0.08695.
Reasoning is already included in output. The run data cannot reconstruct
cache-write or long-context surcharges precisely, so the $0.00148
gap is not a cost win.
The collision-heavy task did favor tspls: seven fewer calls, 38 fewer files,
75 KB less tool output, and about 40 seconds less wall time. On the two
low-collision tasks, however, ripgrep needed only a literal search and a few
reads. tspls still had to discover projects, initialize the compiler, locate a
source position, and decide when to use an unfamiliar tool. Its best case did
not overcome ripgrep's aggregate speed and token advantage.
Three tasks in one repository cannot prove that ripgrep always wins. They do
show why hypothetical edge cases are weak grounds for agent tooling: even with a
collision-heavy case chosen to favor semantics, both stacks were correct and
teaching tspls did not improve the aggregate workflow. Broader, independent
benchmarks should test whether that result generalizes.
What other benchmarks show
I found no direct agent-level gopls-versus-ripgrep benchmark measuring both
task success and billed token cost.
The closest gopls-specific comparison is
agent-lsp's token-savings experiment.
It reports 5Ă— less context on a 15,000-line Go repository and 34Ă— less on
Consul. But it scripts both workflows, estimates one token per four bytes,
excludes language-server startup, and does not establish equal task success.
That measures payloads, not what an agent spends to finish a task.
A more relevant 2026 preprint,
Does a Language Server Save Tokens for Coding Agents?,
runs real grep and LSP agent loops on Python and TypeScript—not Go or gopls.
For symbol-named localization, LSP cost strong models 6–118% more tokens. For
reference-finding it improved precision but still cost capable models more. On
the collision-heavy Hono codebase, however, it was both more accurate and 12%
cheaper.
That pilot is small and harness-dependent, but its mixed result is useful: compare complete tool stacks across representative tasks, equal correctness, successful-task cost, and wall time. Query-level precision alone cannot choose an agent toolkit.
Complexity needs task-level evidence
ast-grep matches Tree-sitter syntax,
which is useful for structural search, lint rules, and codemods.
code-review-graph builds a
persistent graph of functions, imports, calls, inheritance, and tests. Both can
do work text search cannot; neither gets an end-to-end win for free.
code-review-graph's headline token reduction compares graph answers with
reading an entire repository—an upper bound no competent grep-driven agent pays.
A sound comparison needs the same model, tasks, correctness threshold, API
usage, and time to successful completion. It must count cold indexing, warm
queries, maintenance, failed searches, and verification.
A persistent graph also becomes a second representation of the repository. In my use, it is least reliable across language boundaries: a Go route, TypeScript client, OpenAPI operation, SQL column, and config key can describe one feature without sharing a graph edge.
The worst offender is Probe. Its LSP
mode can auto-start a daemon that discovers workspaces, pools language servers,
indexes projects, and maintains memory and disk caches. Its documentation calls
this “zero startup time” because startup moved into the background. In my
TypeScript 7 test, Probe with the tsgo LSP needed a custom Node.js wrapper to
work. A daemon starting language servers through a wrapper, all to avoid rg,
needs measured benefit—not assumed benefit.
Other tools promising token efficiency
rtk, the Rust Token Killer, installs a binary
and hook that intercept shell commands and replaces their output with a
compressed dialect. That adds installation, command rewriting, compatibility
risk, and recovery behavior. It is a shitty trade unless complete tasks become
cheaper or faster.
An independent JetBrains paired benchmark tested shipped RTK on 86 SkillsBench tasks. Quality was unchanged. At low reasoning effort, median task cost rose 7.6% and turns rose 13.8%; at high effort, cost was effectively flat. RTK's counter claimed 96.2 million tokens saved during the low-effort run while the measured bill increased.
The independent LogDx-CI benchmark compared 11 log-reduction methods, including three RTK modes, across 35 real CI failures. Hybrid grep-and-tail routers dominated its cost-quality frontier. Models often recovered from weak initial context, but needed two to four times more tool calls.
Smaller tests reinforce the method. JetBrains measured the Caveman skill's claimed 65% saving at 8.5% of output tokens and roughly 10% of cost at best when activation was forced. A separate Codex comparison of Caveman and RTK kept correctness at 100% across 60 runs, but found frequent RTK overhead on the smaller fixture and mixed results on the larger one. The study is too small for a universal verdict—which is exactly why efficiency claims need independent replication.
Benchmark the whole task
Humans need not prescribe when agents search twice, narrow a pattern, or choose a fallback. They need to choose the toolkit that minimizes wall time and actual cost per successful task at equal correctness.
That requires paired benchmarks of LSPs, indexes, graphs, and context
compressors that include setup, startup, retries, cache pricing, verification,
and failures—not just tool-output bytes. Current evidence favors ripgrep and
simple shell pipelines: tspls did not improve this aggregate workflow,
agent-level LSP results are mixed and usually costlier for strong models, and
RTK loses despite impressive self-reported compression. This is the evidence
now, not a permanent law.
Shoutout to Jesse Wilson, who wrote a decade ago that case mapping breaks search. Coding tools change; greppable code keeps winning. Never break grep.