Repository navigation
Description
Summary
Each codebase-memory-mcp cli <tool> process computes a SHA-256 of its own executable image before it contacts the daemon. For a ~300 MB binary that is the entire client-side cost of a query, and because it is CPU-bound it is the first thing starved when an index worker is saturating the cores. Hook/agent wrappers that run one cli process per query pay it on every call.
Where
src/main.c:3100—main()→main_build_identity(the later call atmain.c:1894inmain_local_cli_daemon_executereuses the cached result)src/mcp/index_supervisor.c:119-147—cbm_index_supervisor_capture_build_fingerprint(its own comment at :125: "computing the real fingerprint hashes the ENTIRE executable image")src/daemon/runtime.c:1009→runtime_process_image_reference_acquire→cbm_daemon_build_fingerprint_native_file(POSIX:src/daemon/service.c:358, SHA-256 loop over the image at :383)
Confirmed with lldb attached mid-run to an idle cli search_graph: the main thread is in sha256_transform ← cbm_daemon_build_fingerprint_native_file ← main_build_identity ← main at 0.8 s and 1.1 s into a 1.45 s call.
Measurements (Apple Silicon, 10 cores, 300 MB binary)
| time | |
|---|---|
cli search_graph idle, build before #2441 |
1.45 s real / 1.2 s user |
SHA-256 of the binary, sha256.c before #2441 |
1.18 s |
SHA-256 of the binary, sha256.c on main (ARMv8 SHA2, #2441) |
0.115 s |
8 parallel cli search_graph, idle |
median 1.95 s |
8 parallel cli search_graph, during a full index of a 64k-node repo |
median 3.7 s (user CPU per call unchanged at ~1.7 s) |
Per-call user CPU stays flat under load while wall time doubles, and querying the project being indexed vs. a different project makes no difference — i.e. this is CPU contention, not a lock. #2441 already cuts the hash ~10x on hardware with SHA extensions, but the cost is still O(binary size) per call and is paid in full on CPUs without them.
Field report this came from: on a ~100k-node monorepo, one-shot wrapper queries took 3–36 s (median ~13 s) during a session where the watcher was re-indexing almost continuously. The repro above confirms the mechanism but only reaches ~2x at 64k nodes; the extra amplification in the field (longer index runs, more concurrent agents, possible memory pressure) is not yet measured.
Proposed fix
A PR will follow for the contention half: run supervised index workers at background CPU priority, so interactive clients (and the user's editor/shell) win the CPU during long index runs. Nothing in src/ lowers worker priority today.
The per-call hash is already ~10x cheaper on hardware with SHA extensions after #2441. Removing it entirely touches cohort identity, so these options are left for maintainer input rather than included in the PR:
- Use the linker's build identity (Mach-O
LC_UUID, ELFNT_GNU_BUILD_ID, PE debug GUID) as the client-side cohort fingerprint — O(1), no cache file. Keep full-image hashing for the daemon-side peer checks (runtime_activation_peer_matches_claim, status/stop paths), so activation trust is unchanged. - Or cache the fingerprint in the cache dir keyed by the image's
(dev, inode, size, mtime_ns, ctime_ns); recompute only on a key miss.
Investigated and written by Claude Opus 5.5 (Anthropic) in Claude Code, at the request of @halindrome.
Activity
perf(index): run supervised index workers at below-normal CPU priority
DeusData commentedon Nov 2, 2026
The index-worker priority part of this landed on main in 7a9b1cb (#2838, thanks to @halindrome): supervised index workers now run at below-normal CPU priority. This issue stays open for the per-call executable-hash cost, which is a separate piece of work.