22 KiB
id, title, status, date, authors, tags
| id | title | status | date | authors | tags | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ADR-0001 | Optimize ruflo-agentdb — accurate surface, quantization opt-ins, controller-managed namespacing, smoke-as-contract | Proposed | 2026-05-04 |
|
|
Context
Today's ruflo-agentdb
ruflo-agentdb is a thin documentation wrapper around three MCP tool families exposed by @claude-flow/cli: agentdb_* (controller bridge), embeddings_* (RuVector ONNX engine), and ruvllm_hnsw_* (WASM-backed pattern router). The plugin ships six files:
.claude-plugin/plugin.json:2—name: "ruflo-agentdb",version: "0.2.0", keywordsagentdb, ruvector, hnsw, embeddings, vector-search.README.md:16— claims19 AgentDB controllers;README.md:49— calls out HNSW "150x-12,500x" speedup and "384-dim ONNX" embeddings.agents/agentdb-specialist.md:15— headerMCP Tools (19 Controllers)then enumerates eightagentdb_*tool prefixes plusembeddings_*andruvllm_hnsw_*as bullet groups.commands/agentdb.md:8— invokesagentdb_healthandagentdb_controllersand prints "all 19 controllers and their status".commands/embeddings.md:8— invokesembeddings_status/embeddings_init/embeddings_search. Mentions the model and dimension count but no quantization or HNSW tuning.skills/agentdb-query/SKILL.md:5—allowed-toolsenumerates 14agentdb_*tools (correct count);SKILL.md:26repeats the "19 Controllers" framing.skills/vector-search/SKILL.md:5—allowed-toolsenumerates sevenembeddings_*and threeruvllm_hnsw_*tools;SKILL.md:46–50is a performance table claimingHNSW (n=10,000) 12,500x faster.
There is no scripts/, no docs/ (the ADR file path is the first under that subtree), and no version pin against the underlying agentdb npm package or the CLI MCP surface.
What AgentDB / the CLI actually exposes
Counted directly from source on 2026-05-04 (HEAD of main):
| Surface | Plugin claim | Real count | Source |
|---|---|---|---|
agentdb_* MCP tools |
"19 controllers" → implies tools | 15 tools | v3/@claude-flow/cli/src/mcp-tools/agentdb-tools.ts:629–645 (agentdbTools export array) |
embeddings_* MCP tools |
7 enumerated in skill | 10 tools | v3/@claude-flow/cli/src/mcp-tools/embeddings-tools.ts:159, 260, 328, 418, 520, 717, 835, 910, 926, 970 |
ruvllm_hnsw_* MCP tools |
3 enumerated | 3 tools (correct) but capacity is ~11 patterns, not 10,000 | v3/@claude-flow/cli/src/mcp-tools/ruvllm-tools.ts:57–58 ("Max ~11 patterns (v2.0.1 limit)") |
Controllers in ControllerRegistry |
"19" | 29 names across 6 init levels: 13 AgentDB-layer + 16 CLI-layer | v3/@claude-flow/memory/src/controller-registry.ts:34–73 (type ControllerName) and :160–174 (INIT_LEVELS) |
| RaBitQ 1-bit quantization | Not documented | 32× compression, two-phase Hamming-prefilter + exact-rerank pipeline | embeddings_rabitq_build, _search, _status at embeddings-tools.ts:910, 926, 970; impl at v3/@claude-flow/cli/src/memory/rabitq-index.ts |
HNSW tuning (efSearch, efConstruction, M) |
Not surfaced in any skill | efSearch accepted as a constructor param on ruvllm_hnsw_create; efConstruction defaulted to 200 in the lite index; M not exposed via MCP |
ruvllm-tools.ts:64, v3/@claude-flow/memory/src/hnsw-index.ts:537 |
| Pattern-store fallback when ReasoningBank unavailable | Not documented | ADR-093 F4: when controller registry returns null, agentdb_pattern-store writes to memory_store with controller: 'memory-store-fallback' |
agentdb-tools.ts:138–161 |
| Native graph-node backend for causal edges | Not documented | ADR-087: agentdb_causal-edge tries graph-node first, falls back to bridge |
agentdb-tools.ts:267–290 |
agentdb npm dep version |
Not pinned in plugin | agentdb: ^3.0.0-alpha.11 in CLI's package.json:120; pnpm-lock.yaml resolves multiple versions (1.6.1, 2.0.0-alpha.3.4/3.7, 3.0.0-alpha.10/11) |
v3/@claude-flow/cli/package.json:120; v3/node_modules/.pnpm/ |
The "19 controllers" number appears to be a stale snapshot from before ADR-095 G7 closed five disabled-by-default controllers (gnnService, rvfOptimizer, mutationGuard, attestationLog, GuardedVectorBackend) and before ADR-053 added mmrDiversityRanker, contextSynthesizer, batchOperations, memoryConsolidation, hierarchicalMemory to the CLI-layer registry. The plugin README block on G7 (README.md:22–35) is accurate about the five activated controllers and about graphAdapter still being disabled — but the surrounding "19" framing is not.
What's missing entirely
Beyond the count drift, the plugin omits four substantive capabilities of the substrate it documents:
- Quantization.
embeddings_rabitq_*provides 32× memory reduction at index time. CLAUDE.md's V3 perf targets explicitly call out "Memory Reduction 50–75% with quantization" as Implemented; the plugin advertises HNSW speedup but never mentions quantization. - Index tunables.
efSearch/efConstruction/Mdirectly control the recall/latency tradeoff; the plugin presents HNSW as a binary "150–12,500×" claim with no operating points. - Namespacing convention. Every consumer plugin (
ruflo-browserdefinesbrowser-sessions / browser-selectors / browser-templates / browser-cookiesin its ADR-0001 §3;ruflo-rag-memoryreferencesclaude-memories / patterns / tasks / solutions;ruflo-intelligencewrites topattern) reinvents namespace naming. There is no contract fromruflo-agentdbabout how namespaces should be named, what they should contain, or how they are GC'd. Theagentdb_*tools mostly do not even take a namespace parameter — they route to controllers (reasoningBank,hierarchicalMemory,causalGraph) — but the CLI fallbackmemory_storeandembeddings_searchdo take namespace strings, so the surface is mixed and undocumented. - Token-efficiency path. The repo ships
getCompactContexton theTokenOptimizer(v3/@claude-flow/integration/src/token-optimizer.ts:109), andagentdb_context-synthesizeexists for the same goal at the MCP layer. Neither is surfaced by the plugin as a "use this when you want compact retrieved context for an LLM call" workflow.
Why now
ruflo-agentdb is the substrate plugin — ruflo-browser (ADR-0001) explicitly depends on AgentDB namespaces and controller-managed sessions; ruflo-rag-memory and ruflo-intelligence route through the same controllers; the whole "memory-as-substrate" story in CLAUDE.md rests on it. Documentation drift in this plugin is contagious — every downstream plugin inherits the wrong tool count, the wrong controller count, and the missing quantization story. We just fixed the same class of drift in ruflo-ruvector (ADR-0001 there); the same pattern applies here.
Decision
We propose six changes to ruflo-agentdb. None requires modifying AgentDB itself; all are plugin-local edits plus one new smoke script.
1. Replace "19 controllers" with the real registry, and pin its source
The plugin currently treats "19" as a magic number repeated across five files. Replace it with two explicit references to the real source:
- README.md swaps the blanket "19 AgentDB controllers" line for a table generated from
INIT_LEVELSatcontroller-registry.ts:160–174. Group by init level (0–6) so the dependency story is visible. Mark each row as one of:active by default,gated on dependency,disabled-pending-ADR. Cite the source file + line. - agents/agentdb-specialist.md drops the "19 Controllers" header and replaces the bullet groups with a one-line "controllers are listed at runtime via
agentdb_controllers; see registry source for the canonical list." - commands/agentdb.md drops the "all 19 controllers" string from step 2; the step now reads "list whatever the runtime reports".
- skills/agentdb-query/SKILL.md §"19 Controllers" becomes "Available controller groups" and lists only the four functional categories already in the skill (hierarchical, pattern, semantic, causal).
The point isn't to memorize the count — it's to stop hard-coding any count. The runtime tool agentdb_controllers is already the source of truth; documentation should defer to it.
2. Surface embeddings_rabitq_* as a first-class quantization workflow
Add a new section to skills/vector-search/SKILL.md titled "Quantized search (32× memory)" with:
- A 5-step recipe:
embeddings_init→embeddings_rabitq_build(one-time, after corpus is loaded) →embeddings_rabitq_search(Hamming-prefilter to top-N candidates) → optional rerank viaembeddings_search(exact, on the candidate set) →embeddings_rabitq_statusfor index health. - A "when to use" rule: corpora ≥ 5,000 vectors and/or memory-constrained environments. Below that, the rebuild cost outweighs the savings.
- The exact tool names added to the
allowed-toolsfrontmatter line. - A note: RaBitQ
_searchreturns candidate IDs only; the rerank step is the user's responsibility (mirrors the docstring atembeddings-tools.ts:911).
embeddings_neural (line 520) is the other undocumented embeddings_* tool. It is the substrate-level entry point and is implicitly covered by embeddings_init/_generate; we will add a one-line note to commands/embeddings.md acknowledging it exists, and stop there. We do not invent a second skill for it.
3. Expose HNSW tuning as a deliberate, documented choice
The plugin currently presents HNSW as a magic number (12,500x faster at vector-search/SKILL.md:50). That number is the published ceiling under specific parameters; without surfacing those parameters the claim is unfalsifiable.
skills/vector-search/SKILL.md gets a new "Tuning" section that documents three operating points and ties each to a tool call:
| Profile | efSearch |
M |
Use case |
|---|---|---|---|
recall-first |
200 | 32 | Pattern recall during planning, search quality matters more than ms |
balanced (default) |
64 | 16 | General-purpose semantic recall |
latency-first |
16 | 8 | Hot-path routing where p99 latency matters |
efSearch is passed via ruvllm_hnsw_create (ruvllm-tools.ts:64). M is not currently MCP-exposed; we document it as a registry-level setting with a forward reference: "raise as a follow-up ADR if M should be MCP-tunable."
We also fix the speed claim. The 12,500× number is for the embeddings/HNSW path inside @claude-flow/memory, not for the WASM ruvllm_hnsw_* tools — those are capped at ~11 patterns (ruvllm-tools.ts:58). The skill currently lumps them together. The new copy reads: "embeddings_search uses the @claude-flow/memory HNSW index (large-scale, 150–12,500×). ruvllm_hnsw_* is a separate WASM-backed router for ≤11 high-priority patterns — useful for hot routes, not for corpus search."
4. Define a namespace convention contract for downstream plugins
Add a new section to README.md titled "Namespace convention" that ruflo-agentdb owns and downstream plugins consume. The contract:
- Naming:
<plugin-stem>-<intent>kebab-case. Examples:browser-sessions,browser-selectors,browser-cookies(ruflo-browser),claude-memories(ruflo-rag-memory's bridge),pattern(ruflo-intelligence ReasoningBank fallback). - Three reserved namespaces owned by the AgentDB plugin itself, not to be shadowed:
pattern(ReasoningBank fallback writes here peragentdb-tools.ts:144),claude-memories(Claude Code auto-memory bridge target),default(memory_storedefault permemory-tools.ts:194). - Controller routing: tools in the
agentdb_hierarchical-*family route bytier(working|episodic|semantic) not by namespace; tools in theagentdb_pattern-*family route by ReasoningBank, again not by namespace. Document explicitly that namespace strings only apply tomemory_*andembeddings_searchpaths. This stops downstream plugins from passing anamespacearg toagentdb_pattern-storeand being silently confused when it's ignored. - GC posture: ruflo-agentdb does not GC namespaces. Consumer plugins that want lifecycle (e.g.,
browser-sessionsafterpurge) own their own deletion viamemory_delete+agentdb_consolidate. Document this so consumers don't expect cleanup we don't provide. - Naming guardrail: a namespace SHOULD NOT contain
:(collides with key-internal delimiters used in the bridge), MUST be ≤200 chars, and MUST passvalidateIdentifier(the same validator already used inagentdb-tools.ts:122).
This section is the load-bearing artifact for cross-plugin discipline. Without it, every plugin author re-invents.
5. Document the operational fallbacks that already exist
Three fallback paths exist in the bridge code and are invisible in the plugin's docs:
- Pattern-store fallback (
agentdb-tools.ts:138–161, ADR-093 F4): when ReasoningBank's controller registry is unavailable,agentdb_pattern-storereturnscontroller: 'memory-store-fallback'. Document this inagents/agentdb-specialist.mdso the agent does not interpret a fallback response as a soft failure. - Causal-edge graph-node backend (
agentdb-tools.ts:267–290, ADR-087):agentdb_causal-edgetries the native@ruvector/graph-nodebackend first, then the bridge. Document the_graphNodeBackend: truefield so consumers can branch on it. - Bridge unavailable (returned by every handler when
bridgeHealthCheckreturns null): the response is{ success: false, error: '...Use memory_store/memory_search instead.' }. Add one paragraph in the README enumerating whichmemory_*tool replaces whichagentdb_*tool when the bridge is unavailable.
6. Smoke test as the contract (mirrors ruvector ADR-0001 §5)
Add scripts/smoke.sh (file does not exist yet — first one in this plugin). It runs against any environment that has npx @claude-flow/cli@latest available with MCP enabled. Each check is a one-liner around mcp tool call ... --json + jq. The contract is "10 passed, 0 failed".
Numbered checks (this is the verifiable artifact, not the prose above):
agentdb_healthreturns{ available: true, ... }. The bridge is wired.agentdb_controllers.total >= 15andagentdb_controllers.active >= 10. The lower-bound assertions are deliberately loose — they verify "the registry initialized at all" without hard-coding the 29-nameControllerNameunion or the 15agentdb_*MCP tools (which are different counts). If a future ADR removes a default-active controller, raise the floor; do not raise the test to an exact match.- The 15 documented
agentdb_*tool names are all callable:agentdb_health, agentdb_controllers, agentdb_pattern-store, agentdb_pattern-search, agentdb_feedback, agentdb_causal-edge, agentdb_route, agentdb_session-start, agentdb_session-end, agentdb_hierarchical-store, agentdb_hierarchical-recall, agentdb_consolidate, agentdb_batch, agentdb_context-synthesize, agentdb_semantic-route. Each gets a smoke call with minimal args; non-error response = pass. - The 10 documented
embeddings_*tools are all callable:embeddings_init, embeddings_generate, embeddings_compare, embeddings_search, embeddings_neural, embeddings_hyperbolic, embeddings_status, embeddings_rabitq_build, embeddings_rabitq_search, embeddings_rabitq_status. - The 3 documented
ruvllm_hnsw_*tools are all callable:ruvllm_hnsw_create(dim=384, max=11),ruvllm_hnsw_add,ruvllm_hnsw_route. - RaBitQ build runs:
embeddings_rabitq_buildthenembeddings_rabitq_statusreportsavailable: true. - Pattern-store with the bridge intentionally unavailable returns
controller: 'memory-store-fallback'. Caveat — this check has a load-bearing unverified assumption: the env-var nameMEMORY_BRIDGE_DISABLE=1was inferred from the fallback code path, not confirmed against the actual gating mechanism inbridgeHealthCheck. Implementer must grepagentdb-tools.ts+memory-bridge.tsfor the real switch (it may instead key onAGENTDB_BRIDGE, on a missing AgentDB controller, or on no env var at all). If no clean runtime switch exists, downgrade this check to a code-path inspection (assert the fallback string literal is reachable in source) rather than a runtime assertion. agentdb_hierarchical-storerejects atiervalue not in{working, episodic, semantic}(regression onagentdb-tools.ts:426).agentdb_batchrejects a 501-element entries array (regression onMAX_BATCH_SIZE = 500atagentdb-tools.ts:20).- Namespace convention guardrails:
memory_store --namespace 'has:colon'is rejected;memory_store --namespace '<205 chars>'is rejected (tests the rule we just documented).
The script does NOT test the controller count exactly, does NOT depend on agentdb being a specific minor version, and does NOT exercise the disabled graphAdapter controller. Those are explicit non-goals.
7. Pinning posture
Following ruvector ADR-0001:
- Add a "Compatibility" subsection to README.md that states: "Plugin v0.3.x targets
@claude-flow/cliv3.6.x with bundledagentdb@^3.0.0-alpha.11. The plugin is documentation-only and does not pin via package.json; the smoke contract is the verification mechanism." - Bump
.claude-plugin/plugin.jsonto0.3.0when this ADR's changes land. Patch bumps thereafter for accuracy fixes; minor for new namespace-convention rules or new MCP tools surfaced. - Plugin pins the CLI's major+minor (
v3.6), not the npmagentdbpackage, because the CLI is the layer the plugin actually invokes. AgentDB internals (e.g., the alpha.11 → alpha.12 bump) are not the plugin's contract.
Consequences
Positive:
- Every count, tool name, and capability claim in the plugin matches a verifiable line in the source. The "19 controllers" myth is gone.
- RaBitQ goes from invisible to a documented quantization workflow — downstream plugins handling large corpora (
ruflo-rag-memory, futureruflo-knowledge-graphintegrations) get a 32× memory-reduction story by reference, not by re-discovery. - HNSW becomes tunable instead of a magic number. Consumer plugins choose an operating point.
- A namespace convention exists.
ruflo-browser's ADR §3 already implements it ad hoc; this ADR formalizes it so the next plugin author doesn't re-derive it. - Operational fallbacks (pattern-store fallback, graph-node backend) are now part of the contract; agents can branch on them deterministically.
scripts/smoke.shmakes plugin-level regressions catchable in CI.
Negative:
- Three downstream plugins reference "19 controllers" in their own docs (grep across
plugins/). Updating them is a separate, mechanical task — but if it's not done, the inconsistency moves rather than disappears. - The namespace convention is non-binding (we have no enforcement in the bridge). It documents intent. If a downstream plugin ignores it, the substrate still works — it just gets harder to reason about. Future enforcement would be a
validate-namespacehelper exposed via MCP, but that is out of scope here. - Smoke depends on the daemon being healthy and the embeddings backend being warm. Cold-start runs may flake on
embeddings_rabitq_buildif no vectors are loaded yet. Mitigation: smoke seeds 10 vectors viamemory_storebefore exercising the rabitq path. - We do not propose changing
agentdb-tools.tsitself. Some of the "19 controllers" claim is upstream framing in the AgentDB README too; we cannot unilaterally fix that, only stop propagating it from the plugin.
Neutral:
- Plugin version moves
0.2.0→0.3.0. Semver-minor because the namespace convention is a new contract for consumers, not a removal. - No new MCP tools are introduced. We are surfacing existing surface, not extending it.
- No change to the
.claude-plugin/plugin.jsonkeywords beyond optionally addingrabitqandquantization. Keywords are advisory only.
Verification
A future implementation must satisfy this smoke contract before the ADR moves from Proposed → Accepted:
bash plugins/ruflo-agentdb/scripts/smoke.sh
# Expected: "10 passed, 0 failed"
Plus three documentation invariants checked by a one-line grep each:
! grep -rn "19 AgentDB controllers\|all 19 controllers\|19 Controllers" plugins/ruflo-agentdb/— no occurrence remains.grep -q "embeddings_rabitq_build" plugins/ruflo-agentdb/skills/vector-search/SKILL.md— quantization workflow is documented.grep -q "Namespace convention" plugins/ruflo-agentdb/README.md— namespace contract section exists.
Related
plugins/ruflo-ruvector/docs/adrs/0001-pin-ruvector-0.2.25.md— pinning + smoke-as-contract precedent (this ADR mirrors §5 and §6).plugins/ruflo-browser/docs/adrs/0001-browser-skills-architecture.md—browser-*namespace family that motivated §4 (namespace convention contract).v3/docs/adr/ADR-053-...— controller activation pipeline (referenced by the bridge module docstring atmemory-bridge.ts:5).v3/docs/adr/ADR-087-graph-node-native-backend.md— graph-node backend used as the primaryagentdb_causal-edgepath.v3/docs/adr/ADR-093-mcp-audit-may-2026-remediation.md— F4 introduced thememory-store-fallbackcontroller string surfaced by §5.v3/docs/adr/ADR-095-architectural-gaps-from-april-audit.md— G7 closed five disabled controllers; the README blockREADME.md:22–35summarizes G7 correctly.v3/@claude-flow/cli/src/mcp-tools/agentdb-tools.ts— 15agentdb_*tool definitions (canonical surface for §6 check 3).v3/@claude-flow/cli/src/mcp-tools/embeddings-tools.ts— 10embeddings_*tool definitions including RaBitQ trio at:910–981.v3/@claude-flow/cli/src/mcp-tools/ruvllm-tools.ts— 3ruvllm_hnsw_*tools, ~11-pattern WASM cap at:58.v3/@claude-flow/memory/src/controller-registry.ts:34–73—ControllerNameunion (canonical 29-name list).v3/@claude-flow/memory/src/controller-registry.ts:160–174—INIT_LEVELS(canonical dependency-ordered grouping).v3/@claude-flow/cli/src/memory/rabitq-index.ts— RaBitQ implementation referenced by the quantization workflow in §2.v3/@claude-flow/integration/src/token-optimizer.ts:109—getCompactContexttoken-efficiency path (deferred: §6 coversagentdb_context-synthesizeonly; the integration-layer optimizer is a separate ADR if surfaced).