Skip to content

v0.9.1-rc.1

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 30 Jul 03:15
Immutable release. Only release title and notes can be modified.
ee9833d

codebase-memory-mcp v0.9.1-rc.1

A milestone release since v0.9.0 — cbm's backend has been rearchitected around a shared coordination daemon, tool output was rebuilt into a compact tree format (~99% fewer output tokens on large results), the long-standing Windows memory ratchet is fixed and verified, and a new coverage system makes the graph's blind spots visible — introducing cbm's 15th tool, check_index_coverage, and a missed-code skeleton rendered right beside the code galaxy in the graph UI. Add three new community-contributed language surfaces and a broad community-driven correctness batch across the query engine, store, and extractors.

438 commits · ~90 merged PRs · 25+ contributors · 30+ community-reported issues fixed (v0.9.0…v0.9.1-rc.1)

Why this one is a release candidate

This release changes cbm at a deeper level than a normal point release: the backend now runs through a coordination daemon (a fundamental shift in how every session, CLI call, and hook executes) and the memory/allocator layer was reworked on Windows. Both are extensively tested — the full CI gate, cross-platform soak legs, and benchmark verification all ran green on this exact build — but changes of this nature earn real-world mileage before a final tag.

Please run the RC in your day-to-day workflows and report anything that feels off — especially in multi-agent setups: several agents or editors hitting the same projects concurrently, long-running agent loops, parallel indexing, daemon start/stop cycles. Those concurrency paths are exactly what the new backend exists for, and field reports from them are the most valuable input for the final release. Nothing is too small to file.

A second ask: send us your coverage summaries. The new coverage system makes the gap between your code and the graph measurable — help us shrink it. Ask your agent to run check_index_coverage across your repositories (or click the missed skeleton's report-an-edge-case callout in the UI) and paste the resulting summary into a GitHub issue or discussion: miss classes, affected languages and file kinds, counts. That's aggregate numbers, not source code — everything stays on your machine unless you choose to paste it. Every real-world coverage summary points us at a concrete parser edge case, resolver gap, or language quirk we can fix, and each one fixed makes graph analysis more precise for everyone — your repos are the test corpus we can't clone. This is the single highest-leverage thing an RC user can send us.

And an apology on timing. We previewed this RC in discussion #1144 targeting mid-July, and it took clearly longer than we said. The reason is the nature of what's in it: the daemon was a genuine architecture shift, not a feature, and the memory work had to be verified rather than assumed — both had to be done right rather than quickly, and for a stretch they consumed nearly all capacity, which also slowed PR reviews and issue responses. A third, less visible reason: recurring antivirus false positives on release artifacts blocked several otherwise-green release runs in the final stretch. They never shipped — our gate requires zero detections — and this release scans clean; the full story is in Antivirus false positives on release binaries below. To everyone who contributed, reported, and waited (and nudged us — deservedly): thank you for the patience. The full explanation lives in that discussion thread.

Highlights

  • The coordination daemon — a backend milestone. Until now every cbm session was an island: each MCP server, CLI call, and hook opened the store on its own and knew nothing about its neighbors. As of this release, all of them coordinate through a per-user daemon — build/version conflict handshakes, indexing admission control, and a shared graph UI. New daemon start|stop|status CLI; a warm daemon removes per-command startup cost — measured 40–58% faster CLI commands on an 8.5M-node graph (~2.6 s saved per call). Beyond the immediate wins, this is the foundation the next releases build on: centralized controls for multi-agent workflows (scheduling, budgets, priorities across concurrent agents) and local-only reporting/observability infrastructure — everything stays on your machine; nothing is sent anywhere.
  • Tree-format tool output — TOON-compact, prefix-grouped rows with exactly-once pagination, real detect_changes impact reporting, and graph cycle detection. Measured ~99% fewer output tokens vs v0.9.0 on large query results — the difference between a result that fits in an agent's context and one that doesn't.
  • Windows memory ratchet fixed (#581) — the allocator override silently compiled out under MinGW, so the CRT kept freed pages committed and long-lived daemons ratcheted memory for months. mimalloc now genuinely owns Windows allocations (link-time wrap + static-CRT override), thread heaps release at thread exit, and an out-loud ownership audit makes any future regression announce itself at startup. Verified on release artifacts: a 10-minute pure-query soak that measured 53× committed-heap growth on v0.9.0-era builds now measures 1.06×, cross-checked green on macOS/Linux/Windows.
  • One install, 43 coding agents — the installer now automatically (or conditionally, where a client's documented markers are present) configures 43 agent and client surfaces — Claude Code, Codex CLI, Gemini CLI, Cursor, Zed, VS Code, Windsurf, Cline, Aider, Goose, Amp, Copilot CLI, Sourcegraph Cody, and 30 more — so cbm drops into whatever agent stack you already run. Alongside it, experimental tool profiles (--tool-profile=analysis|scout) expose restricted inspection surfaces so lightweight scout agents get a smaller, cheaper tool set (the first slice of the evidence-tier work previewed in #1144).
  • Honest coverage — the missed graph — what did not make it into the graph is now first-class, headlined by check_index_coverage — the 15th cbm tool and the first new tool since the core surface stabilized: parse-coverage signals per file, deliberately-ignored files reported as a by-design class, coverage folded into index_status with notes on get_code_snippet, and a queryable miss graph persisted in the store. In the UI, the missed code renders as a skeleton beside the code galaxy — click-to-focus to inspect exactly which files and regions the index couldn't fully parse, with a report-an-edge-case callout to send them our way. Agents (and you) can now see the boundary of what the graph knows — and every edge case you report makes it smaller.
  • New language surfaces — Perl LSP-tier semantic resolution, InterSystems IRIS ObjectScript support, and Mojo wiring — all three community-contributed.
  • Query engine robustnesscoalesce() and multi-arg scalar functions in WHERE, correct var-length path semantics with an advertised depth clamp (no more fabricated 100-hop paths from a self-loop), DISTINCT-before-LIMIT, composite/escaped property returns, a wall-clock execution deadline for runaway queries, and tools/list pagination for non-paginating clients.
  • Store & artifact integrity — a four-report series from one community member exposed torn WAL-mode exports, swallowed SQLITE_CORRUPT, stale WAL replay over fresh DBs, and invalid JSON on async edges; all four are fixed, plus atomic cache publish on the writer.
  • CI, completely wrapped up — the entire test infrastructure was unified: local CI, PR CI, dry runs, and releases now all execute the same canonical leg scripts, enforced by a venue-parity contract that turns any drift into a red build. Parallel per-suite test execution with a zero-loss gate, release-gating soak legs, and artifact attestation included. For users this means one thing: faster, more confident iteration — fixes and features can move from patch to verified release-shaped build much quicker from here on.

What's changed

Coordination daemon & concurrency

This is the largest backend change since the project began: cbm's execution model moved from independent per-session processes to a coordinated per-user backend. Concurrent sessions coordinate through the daemon (daemon start|stop|status, permanent or session-managed) with authenticated IPC, build-fingerprint/version/cache-root conflict detection, physical-job admission control for parallel indexing, and the graph UI served from the daemon. Because a per-user daemon is a security boundary, its IPC was hardened accordingly — on Windows, pipe clients are validated by process identity rather than impersonation (and the daemon reads a client's first frame before ever impersonating it), private-namespace objects are owner-stamped with the token user's SID, and DACLs are strictly validated; on POSIX, socket identity is checked against inode-pinned records. Everything remains strictly local. It is deliberately conservative in this RC — coordination, admission control, and lifecycle — but it is the substrate for centralized multi-agent controls and local-only observability going forward.

Preparation for worktree-native multi-agent workflows. The daemon is also the groundwork for how multi-agent setups actually run today: one agent per git worktree. Right now each worktree has to be indexed as if it were a separate repository — a full reindex of what is largely the same code. With the centralized daemon layer in place, upcoming releases will rework exactly this: worktrees become children of the main repository's graph, sharing everything unchanged and indexing only what differs — making the agent-per-worktree pattern dramatically cheaper in time and disk. This lands once the daemon has proven itself in the field, which is another reason your RC reports from worktree-heavy workflows matter. Release paths and verification were hardened after review, TSan-sized wait budgets keep the daemon test suite honest, and a second-index crash (TLS parsers destroyed at allocator-epoch boundaries) is fixed.

Tool output & MCP surface

TOON compact output across the query surface (~10× smaller) and then the tree format on top (prefix-grouped rows, exactly-once pagination cursors, real change-impact in detect_changes, SCC cycle detection) for a combined ~99% output-token reduction vs v0.9.0 on large results. Structured compact results for MCP clients; resources/prompts discovery answered with empty lists instead of -32601 errors; guaranteed valid UTF-8 in tree output and honest totals/complete counts after review polish. The coverage system makes the graph's boundary visible: the new check_index_coverage tool (cbm's 15th) answers "what does the index not know about this repository?" directly; parse-coverage signals per file, deliberately-ignored files reported as a by-design class, a persisted + queryable miss graph, coverage folded into index_status with a note on get_code_snippet, and the UI's missed skeleton with click-to-focus and a report-an-edge-case callout.

Windows & memory safety

The #581 chain: route ordinary Windows allocations through mimalloc (--wrap + static-CRT override — mimalloc's own override is _MSC_VER-gated and never applied under clang/MinGW), release thread heaps from a TLS detach callback, drop an SQLite page-cache slab that faulted on arm64, and audit allocator ownership per size class out loud at startup so "the tuning is decoration" can never happen silently again. Also: wide-path canonicalization (no ANSI _access/_fullpath), wide-safe graph-DB opens for non-ASCII cache paths, UTF-8 reads for search_code temp files, non-ASCII UserProfile dump-phase fix, a CJK repo_path crash regression fix, and Windows hook scripts installed in .cmd form.

Windows now ships a single binary — and updates run from install.ps1

Windows previously shipped two executables: a small permanent launcher plus the product binary behind it. It now ships one binary, exactly like Linux and macOS.

The launcher existed so the product could update itself in place: on Windows a running executable cannot replace its own image, so a second resident binary had to perform the swap. That small helper reliably trips antivirus heuristics, and we could not keep it without shipping something that gets flagged — so the update step moved out of the running process and into install.ps1, which runs while codebase-memory-mcp is not running.

What changes for you: on Windows, codebase-memory-mcp update no longer updates in place. It prints the exact command to run instead:

powershell -ExecutionPolicy Bypass -File "<install-dir>\install.ps1"

install.ps1 is idempotent, so re-running it is the update: it stops the daemon, retires the running binary, installs the new one, and cleans up. (If PowerShell refuses to run the script because it was downloaded from the internet, Unblock-File it first.) Installing through npm or pip is unaffected — update with your package manager as before.

Alongside the smaller install, every daemon start, CLI call, and hook fire now skips a process spawn, a named-pipe handshake, and an stdio relay.

Languages & extraction accuracy

Perl LSP-tier semantic resolution; InterSystems ObjectScript language support (plus identifier node types and a MinHash gate fix); Mojo wiring. Correctness: native fetch() classified as HTTP_CALLS; CommonJS require() bindings no longer shadow call resolution; aliased-import direct hits keep call suffixes (fixing a django-scale CALLS/TESTS edge regression); Python aliased-import call resolution; C/C++ #include resolved to header targets by stem; C/C++ definitions recovered from #ifdef-split brace ERROR regions and remapped to original lines; PHP self-using and alias-colliding trait recursion OOMs fixed (two independent reports); Laravel Route::prefix()->group() routes and facade-style routes minted with composed prefixes; JAX-RS class+method @Path composition; env-access CONFIGURES guards; File-node QNs keep full filenames so sibling files can't collide; .env.* sibling variants no longer collide on qualified name; JSX-via-alias CALLS edges restored in the parallel pipeline; docstring truncation snaps to UTF-8 codepoint boundaries; GLR stack-merge recursion bounded against stack overflow; in-body function-like macro calls no longer flagged as parse gaps.

Query engine (Cypher)

coalesce() and multi-arg scalar functions in WHERE; coalesce(var.prop, literal); var-length path semantics fixed (edge reuse + repeated node variables unified — a self-loop can no longer fabricate 100-hop paths) with an advertised depth clamp; DISTINCT applied before RETURN limits; whole-value returns for composite and escaped properties; a wall-clock execution deadline aborts runaway queries; tools/list default pagination.

Store, artifacts & lifecycle

Atomic cache publish in the SQLite writer; snapshot exports made consistent and corrupt imports refused; destination WAL/SHM sidecars removed before installing a fresh DB; SQLITE_CORRUPT surfaced from row scans instead of silently truncating results; WAL bounded via journal_size_limit with checkpoint-starvation warnings; valid JSON for sequential-path service edges and Route nodes; watcher reindexes dirty repos once per distinct state (no more write amplification); projects with ::missed shadow rows stay visible; project args resolve by unique name tail; relative repo_path canonicalization no longer corrupts and auto-deletes project DBs.

Agents, clients & installer

Agent integration coverage expanded to 43 automatic/conditional client surfaces, each changed only when its documented platform, marker, or existing config path is present — plus coverage-aware integrations and tiered-agent smoke coverage; manual/UI-boundary clients are documented rather than touched. The Windows install path was security-hardened end to end: install transactions staged under a per-user root with private security descriptors, token-user SID stamped as owner on staged files and private-namespace objects, DACL validation that accepts the OWNER RIGHTS ACE and standard/elevated profile ACLs, the first-touch antivirus scan window absorbed on staged-copy opens, MSYS-form profile paths resolved, installer filesystem races eliminated, and legacy Windows hook scripts migrated safely to .cmd form. Also: unknown tool flags rejected with a nearest-flag suggestion (no more silently ignored --max-depth); install --dry-run always states dry-run mode; Aider gets CLI-form instructions; hook-augment deadline raised and env-configurable with a breadcrumb when it fires; discovery grows its walk stack instead of failing very wide repositories; npm/PyPI packages gain the CBM_VARIANT=ui opt-in UI build; FreeBSD physical-memory detection via HW_PHYSMEM; CBM_MEM_BUDGET_MB strict parse/clamp resolver; issue labeler fixed ((?i) unsupported in JS RegExp).

CI & test infrastructure

This release wraps up a complete overhaul of how cbm is tested and shipped. Every venue — local CI on a developer machine, PR CI, the pre-release dry run, and the release pipeline itself — now runs the same canonical leg scripts, with a venue-parity contract (run as step zero of every test leg) that turns any inline harness logic or bypassed wrapper into a red build. On top of that foundation: parallel test execution with per-suite processes and a zero-loss gate contract (~2.5× faster suites, same gates); widened ThreadSanitizer coverage plus native ARM64 Windows UBSan; release-artifact attestation; deterministic QA gates; and the release-gating soak sequence (churn plus a query-leak leg that turns any RSS growth into a hard signal) running identically everywhere. Supply-chain hardening rode along: release artifacts are attested in the build workflow, SLSA provenance scope is documented, CI container base images and package downloads are pinned by hash, and the test VM setup no longer embeds credentials. This is infrastructure work users never see directly — but it is what should make future iterations noticeably quicker: a fix verified locally is now verified in the exact shape the release gate demands.

Known issues (RC)

  • Small Windows-only memory growth under sustained query load (~4.5 KB/query; neither macOS nor Linux shows it). This is not the #581 ratchet — ownership audits pass and the 53× failure mode is gone — but it is tracked with a follow-up investigation before final.
  • Warm re-index at very large scale is slower than v0.9.0-era (kernel-scale cache-hit ~17 s → ~33 s). Cold indexing is at or faster than all baselines. Tracked.
  • Multi-threaded edge-count jitter: node counts are byte-stable across runs; edge totals can vary by ~0.01–1.3% run-to-run on resolution-heavy languages (worst case TypeScript). Tracked as an open determinism investigation.
  • On macOS/Linux a startup line mem.allocator.not_owned may appear in logs — on those platforms this is the designed configuration (the allocator serves the bound sqlite/tree-sitter populations; ordinary malloc stays with the system allocator) and is harmless. It is the Windows tripwire for the #581 class.

Antivirus false positives on release binaries

This release ships with 0 detections across all 20 artifacts — every binary, both install scripts, and the notices files, each scanned by 46–68 engines. That is the only condition under which we publish, and it is why this release took as long as it did.

During the final stretch, some builds intermittently tripped one machine-learning heuristic on VirusTotal — Microsoft's engine reporting Trojan:Script/Wacatac.B!ml — while the other 60+ engines reported clean. Those builds were never published. We are documenting the episode anyway, because the policy it exercised is permanent and you should know what it guarantees.

What it is. !ml verdicts are machine-learned heuristics, not signature matches — a statistical model scoring file features, with our large binaries (they embed 159 parser grammars and the graph UI) sitting close to its decision boundary. This is a well-known pattern that regularly hits Go, PyInstaller, Nim, and rclone releases. A close-to-home example: opencode, one of the most widely used open-source coding agents, shipped release after release while Defender's ML repeatedly flagged its artifacts with the very same Wacatac heuristic family (opencode#3415, opencode#7919) — with no compromise ever found — until they closed the class out by code-signing their releases (opencode#12897), the same path we describe below. The pattern is also demonstrably unstable: across our own release attempts the flag appeared and disappeared between builds of near-identical code, on different platforms each time.

Our policy: zero detections. Permanently. Any detection, by any engine, on any artifact is a hard release blocker — including demonstrably false ones. This is not a bar we set for this release and it is not one we intend to relax later: if it does not scan 0/N, it does not ship. The Security Verification section below is generated only after that gate passes, so a published cbm release always means every artifact scanned clean.

We deliberately rejected the two shortcuts available to us. We did not add a tolerance for "just one engine" or "only heuristic verdicts" — a tolerance is how a real detection eventually walks through the gate. And we did not quietly rebuild until the badge looked clean, which would have been the easiest option and the least honest, since a rebuild only changes the hash the scanner is judging. When a false positive blocks us, we verify the exact bytes against an up-to-date Microsoft Defender endpoint (the shipping product, current signatures, real-time protection on), submit a false-positive report to Microsoft for those hashes, and wait. That costs days per incident. We accept that cost, and this release paid it.

Why chasing it from the build side did not work. This was one of the major reasons the release slipped. We spent several cycles attacking it as if it were a code problem — fully stripping symbol tables, removing the in-binary downloader and self-update machinery, eliminating the Windows launcher stub, rebuilding with different metadata — and each change appeared to work until a later build flipped the verdict again. The decisive evidence arrived late: one identical file, same SHA-256, went from 0/62 clean to flagged within about an hour. No source change can explain that, which means part of the verdict lives in the scanner's own state rather than in our bytes. We should have concluded earlier that code signing is the durable fix and that an ML decision boundary is not something you engineer your way around. Signing is more bureaucratic than technical (identity validation, certificates, platform enrollment); it is underway and realistically a few more weeks out.

What we did fix, because it deserved fixing anyway. The investigation turned up real defects, and those we corrected on their own merits rather than as antivirus appeasement — each is now asserted against the shipped binary by a release gate, so it cannot silently regress:

  • Every Linux binary we had ever shipped requested an executable stack. One assembly file in the build was missing a .note.GNU-stack annotation, which makes the linker assume the worst for the entire link.
  • A test-only probe that forks a SIGTERM-ignoring child was compiled into production builds. It is now compiled out, and test seams are opt-in so forgetting the flag yields a clean binary rather than a leaky one.
  • The daemon spawned curl against the GitHub releases API on the first eligible session of every run, purely to report that a newer version existed. Removed: cbm now makes no network request of its own accord, and the archives carry no download URLs at all.
  • An in-memory archive extractor with no production caller, and SQLite's loadable-extension machinery we never use, are compiled out rather than merely unreachable.
  • Temp-file and repository-scan hardening: private exclusive creation, and symlinked directories can no longer lead a scan outside the project root.
  • Build timestamps removed, so identical source can produce identical bytes.

Until signing lands, the zero-detection gate above, published hashes, build provenance attestation, and source you can always build yourself are the trust anchors for this project.

Thanks to our contributors

This release is substantially community work — features, fixes, and the reports that made the fixes possible. Merged contributions:

@halindrome (Perl LSP-tier resolution, #461/#459) · @isc-tdyar (ObjectScript support #467, extractor fixes #1060) · @aaiyer (Mojo wiring #939) · @WarGloom (atomic cache publish #940, structured compact results #1043) · @harshitaajoshi (Cypher coalesce() #991, UTF-8 docstring boundary #1094) · @dpersek (TSan CI target #890, tools/list pagination #980) · @blankanswer (C++ line remap #949, CLI docs/tests #947/#948) · @pcristin (Cypher DISTINCT #906) · @muba00 (PHP trait OOM #920) · @apappas1129 (native fetch() HTTP_CALLS #927) · @yangsec888 (memory-budget resolver #954) · @Cosm1cAC (Windows UTF-8 temp files #956) · @LA-10 (aliased import resolution #979) · @Dhruvy0804 (CONFIGURES guards #982) · @Sinjan-Debnath (C/C++ include resolution #983) · @ShiroKSH (ADR clear on delete #985) · @spde (incremental File naming #995) · @CharlesQueiroz (JAX-RS route composition #1007) · @metehanulusoy (shadow-row project resolution #1046) · @tmonestudio (test cache isolation #1067) · @PR9000 (FreeBSD memory detection #1093) · @JhohanBustamante (Cypher composite properties #1098) · @alex-plosceac (.gitattributes ordering #916)

And the reporters whose precise, reproducible issues drove this release's correctness work:

@kriswill (the store-integrity series #895#898) · @KasaharaDefries (#765) · @tmstack-io (#951) · @ericsonjulio1 (#773) · @Phantom-Star829 (#794) · @aitoroses (#797) · @rockywang101 (#856) · @zihaozhaoo (#858) · @trinhan2106 (#871) · @rudi193-cmd (#874) · @bsahafian (#929) · @wymfly (#937) · @paolo-blocklabs (#952) · @ARZF (#958) · @Zeermil (#964) · @squall-cyber (#973) · @LA-10 (#988) · @meszkee (#996) · @KnifeOfLife (#1025) · @mostafnamazy (#1032) · @metehanulusoy (#1044) · @rehanazher (#1077) · @itayost (#1085) · @lg320531124 (#764)

…and everyone else who filed, discussed, and re-tested. Dependency updates via Dependabot.

Full changelog: v0.9.0...v0.9.1-rc.1

Security Verification

All release binaries scanned with 70+ antivirus engines — 0 detections.

Binary SHA-256 VirusTotal
darwin-amd64 661bd7320b4b3ec9b681... 0 detections ✅
darwin-arm64 e4fe1cf4f764308f19a6... 0 detections ✅
linux-amd64 2fd0687c69d8b47d63d0... 0 detections ✅
linux-amd64-portable 744395fa9623dd3368cf... 0 detections ✅
linux-arm64 c1cd4eb660be91c99fcc... 0 detections ✅
linux-arm64-portable 0e3e7b2499158314c4cc... 0 detections ✅
ui-darwin-amd64 c2095fdc559d19c7aad5... 0 detections ✅
ui-darwin-arm64 9f2c23c75ed64b01b852... 0 detections ✅
ui-linux-amd64 82667bbfc72a46b8200d... 0 detections ✅
ui-linux-amd64-portable 34c1fbf018f741bda2ea... 0 detections ✅
ui-linux-arm64 7346f618a46cb766fbd1... 0 detections ✅
ui-linux-arm64-portable a6e84602845ed38f7e2d... 0 detections ✅
ui-windows-amd64 b8bb796a1327956a5aaa... 0 detections ✅
ui-windows-arm64 391e34ca40d594b47f48... 0 detections ✅
windows-amd64 7d82ca2faedce72113b1... 0 detections ✅
windows-arm64 af0e9c551e9d418273b7... 0 detections ✅