CodeDB Pro v0.2.14: the 50 ms wait that made fast search look slow

Rach Pradhan · 9 min read

You know the pause where a search has obviously finished, but the command still takes a beat to return? In one CodeDB Pro path, that feeling was literal. The useful work took under a millisecond; cleanup could then wait on a 50 ms polling sleep.

v0.2.14 replaces that poll with a signal. The measured direct pipe search fell from 54.3 ms to 0.68 ms at p50: 79.5× faster. The release also removes redundant machinery from MCP batches, improves known-up-front agent traversal by 1.70–2.15× in the final local saved-binary A/B, and makes the tool schema 38.7% smaller.

79.5×

direct search p50

54.3 ms → 0.68 ms

2.15×

four-file map

saved-binary median A/B

1.70×

fan-out traversal

8 ops across 3 RPCs

−38.7%

tool schema

about 2,510 fewer tokens

The important scope

79.5× belongs to the direct pipe search benchmark, not every MCP operation. The agent traversal numbers measure the real persistent MCP daemon but exclude model reasoning and token generation. Both improvements matter; they describe different layers.

The search was finished. The watchdog was not.

Every search has a 30-second safety budget. A watchdog thread enforces it so a pathological directory walk cannot keep an agent hanging forever. Before v0.2.14, that thread checked the clock, checked an atomic cancellation flag, and slept for 50 ms before checking again.

Imagine a receptionist who checks the front door only once every 50 seconds. Setting the flag was like arriving just after they looked away: the result was ready, but the search handler still had to join a sleeping watchdog. The search was not slow. Its shutdown protocol was.

Before — poll

1search completes
2cancel flag set
3sleep finishes ≤50 ms later
4watchdog joins

fast work, fixed tail

v0.2.14 — signal

1search completes
2done event signaled
3timed wait wakes now
4watchdog joins

fast work, no polling tail

The watchdog now waits on an interruptible timed event. If the budget expires, it sets the same cancellation flag. If the search finishes first, the handler signals the event and the waiter wakes immediately. The timeout remains; the polling tail disappears.

direct pipe search latency — lower is better

before v0.2.14
median (p50)79.5× faster
before
54.3 ms
after
0.68 ms
tail (p95)41× faster
before
56.9 ms
after
1.38 ms

The v0.2.14 bars have a 4% visual floor so sub-millisecond values remain visible. Labels show exact measurements.

Those figures come from 150 alternating ReleaseFast samples of the same directory query. Median latency moved from 54.3 ms to 0.68 ms, and p95 from 56.9 ms to 1.38 ms. Output was byte-identical. Alternating the builds helps distribute background load, but this is still a local microbenchmark, not a promise that every repository and machine will produce the same absolute values.

The fixed tail was specific to direct pipe search cleanup. A persistent MCP session does not pay that exact 50 ms join on every tool call, which is why we measured MCP traversal separately.

Batch was doing cheap work expensively

An agent often knows several independent questions at once: outline these four files, search for these three symbols, then inspect the two most likely modules. Batching turns those questions into fewer MCP round trips. But a batch only helps if coordinating the work costs less than the work itself.

The old MCP route normalized each operation's arguments twice. It captured the batch response through an operating-system pipe and a dedicated drainer thread. It also spawned a fresh thread for every independent operation, including bounded outline and range reads that could finish before the thread had fully started.

Before

flatten argsflatten args againopen OS pipespawn drainerspawn cheap reads

v0.2.14

flatten oncewrite response to memoryrun bounded reads inlineparallelize heavier work

v0.2.14 gives the shared dispatcher one normalization pass and a memory-backed response target. It also uses deliberately narrow adaptive scheduling: batches of at most 16 bounded reads, touching at most 1 MiB of source in total, run inline. Larger reads, searches, edits, and mixed or heavier batches keep their parallel execution.

This is not a blanket switch to serial work. It is a crossover decision. Below the measured threshold, thread startup costs more than the read; above it, parallelism can pay for itself. Existing conflict detection still serializes same-file writes safely.

Does it translate to better agentic traversal?

Yes, when the agent can identify independent work before it starts. A traversal is not one search; it is a small graph of outlines, symbol reads, searches, and follow-up reads. The parts of that graph known up front are exactly where a cheaper batch path removes round trips and coordination overhead.

We added a deterministic harness that drives the real persistent CodeDB Pro MCP daemon over JSON-RPC and reads fixtures from the checkout. It disables telemetry and invokes no model or network service. That isolates the local tool layer: transport, dispatch, file work, and response assembly.

v0.2.13 → v0.2.14 saved-binary A/B — median latency

scenariov0.2.13v0.2.14speedup
four-file mapping batchknown up front842.5 µs391.3 µs2.15×
eight-op fan-out / 3 RPCsknown up front2,266.5 µs1,332.4 µs1.70×
five-step dependent chainresult dependent1,124.7 µs995.6 µs1.13×

The table is the final median comparison between a saved v0.2.13 binary and the released v0.2.14 binary on the same machine. The changelog retains an earlier development run—1.70× for the map and 1.56× for the fan-out traversal. Absolute microsecond values moved with the run; both comparisons showed the same direction.

Batch what is known. Sequence what is discovered.

The five-step dependent traversal improved only 1.13×. That is expected: when one response tells the agent which symbol or file to request next, the calls cannot be safely collapsed in advance. v0.2.14 now says this directly in the MCP instructions instead of encouraging indiscriminate batching.

This is evidence of a faster traversal substrate, not a claim that a complete agent task will finish 2.15× faster. Model latency, reasoning quality, cache state, repository layout, and how well the client batches independent calls still dominate many end-to-end runs.

Agent speed is also context size

Before an MCP client can call a tool, it has to understand the tool schema. That payload competes with repository context, conversation history, and the user's request. Repeating the same idea in several descriptions wastes the model's attention even when it adds almost no wall-clock time.

MCP tools/list payload

−10,042 bytes · −38.7%

v0.2.13

25,946 bytes

v0.2.14

15,904 bytes

About 2,510 fewer input tokens by the transparent bytes ÷ 4 estimate.

We tightened descriptions while keeping every tool, property, enum, default, and safety control. The tools/list response fell from 25,946 to 15,904 bytes: 10,042 bytes removed. Dividing bytes by four gives the deliberately rough estimate of about 2,510 fewer input tokens; the exact count depends on the model tokenizer and on whether a host caches tool definitions between turns.

One schema correction came with the cleanup. replace accepts either a single path or an array of paths. The implementation already supported both, but the old schema incorrectly required the singular form. Schema-validating agents can now use multi-path replacement without inventing a dummy field.

Fast is not enough if a fresh install feels broken

Performance work exposed a more basic first-run problem: a new user should be able to ask what a CLI is and which version was installed before activating a license. Every core CLI now allows --help and --version pre-activation. Operations that inspect or mutate working data remain behind the offline license gate.

One source contract

scripts/source-check.sh check reproduces the build, test, fresh-install, help/version, and MCP smoke checks used by CI.

One pinned Zig bootstrap

scripts/install-zig.sh verifies checksums and can use the durable community mirror when a pinned development snapshot leaves the primary index.

The released binaries cover Apple Silicon, Intel macOS, and Linux x86_64. The macOS artifacts are signed and notarized. None of these changes add a cloud round-trip to search, traversal, licensing, or the benchmark.

Reproduce the traversal benchmark locally

The harness is part of the repository. Run the source contract first, then drive the release binary for more samples. Pass a saved binary to repeat the same version-to-version comparison.

local, deterministic, zero-egress benchmark
$ ./scripts/source-check.sh check
$ cd codedbpro
$ zig build bench-traversal -Doptimize=ReleaseFast -- --iters 300
$ zig build bench-traversal -Doptimize=ReleaseFast -- --iters 300 --binary /path/to/codedb-pro-0.2.13

The benchmark sets CODEDBPRO_TELEMETRY=0 in its child environment, so the run performs no network egress. It reports p50, p95, response bytes, and RPC counts for sequential, batched, fan-out, and dependency-bound scenarios.

Releasedv0.2.14

Upgrade to CodeDB Pro v0.2.14

The biggest direct-search delay is gone, MCP fan-out is cheaper, and every session starts with a leaner tool contract. Existing installations update in place.

update
$ codedb-pro update
$ codedb-pro --version
$ codedb-pro --changelog