Back to Ruflo

Optimize ruflo-agentdb — accurate surface, quantization opt-ins, controller-managed namespacing, smoke-as-contract

plugins/ruflo-agentdb/docs/adrs/0001-agentdb-optimization.md

3.6.3021.8 KB
Original Source

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:2name: "ruflo-agentdb", version: "0.2.0", keywords agentdb, ruvector, hnsw, embeddings, vector-search.
  • README.md:16 — claims 19 AgentDB controllers; README.md:49 — calls out HNSW "150x-12,500x" speedup and "384-dim ONNX" embeddings.
  • agents/agentdb-specialist.md:15 — header MCP Tools (19 Controllers) then enumerates eight agentdb_* tool prefixes plus embeddings_* and ruvllm_hnsw_* as bullet groups.
  • commands/agentdb.md:8 — invokes agentdb_health and agentdb_controllers and prints "all 19 controllers and their status".
  • commands/embeddings.md:8 — invokes embeddings_status/embeddings_init/embeddings_search. Mentions the model and dimension count but no quantization or HNSW tuning.
  • skills/agentdb-query/SKILL.md:5allowed-tools enumerates 14 agentdb_* tools (correct count); SKILL.md:26 repeats the "19 Controllers" framing.
  • skills/vector-search/SKILL.md:5allowed-tools enumerates seven embeddings_* and three ruvllm_hnsw_* tools; SKILL.md:46–50 is a performance table claiming HNSW (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):

SurfacePlugin claimReal countSource
agentdb_* MCP tools"19 controllers" → implies tools15 toolsv3/@claude-flow/cli/src/mcp-tools/agentdb-tools.ts:629–645 (agentdbTools export array)
embeddings_* MCP tools7 enumerated in skill10 toolsv3/@claude-flow/cli/src/mcp-tools/embeddings-tools.ts:159, 260, 328, 418, 520, 717, 835, 910, 926, 970
ruvllm_hnsw_* MCP tools3 enumerated3 tools (correct) but capacity is ~11 patterns, not 10,000v3/@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-layerv3/@claude-flow/memory/src/controller-registry.ts:34–73 (type ControllerName) and :160–174 (INIT_LEVELS)
RaBitQ 1-bit quantizationNot documented32× compression, two-phase Hamming-prefilter + exact-rerank pipelineembeddings_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 skillefSearch accepted as a constructor param on ruvllm_hnsw_create; efConstruction defaulted to 200 in the lite index; M not exposed via MCPruvllm-tools.ts:64, v3/@claude-flow/memory/src/hnsw-index.ts:537
Pattern-store fallback when ReasoningBank unavailableNot documentedADR-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 edgesNot documentedADR-087: agentdb_causal-edge tries graph-node first, falls back to bridgeagentdb-tools.ts:267–290
agentdb npm dep versionNot pinned in pluginagentdb: ^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:

  1. 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.
  2. Index tunables. efSearch / efConstruction / M directly control the recall/latency tradeoff; the plugin presents HNSW as a binary "150–12,500×" claim with no operating points.
  3. Namespacing convention. Every consumer plugin (ruflo-browser defines browser-sessions / browser-selectors / browser-templates / browser-cookies in its ADR-0001 §3; ruflo-rag-memory references claude-memories / patterns / tasks / solutions; ruflo-intelligence writes to pattern) reinvents namespace naming. There is no contract from ruflo-agentdb about how namespaces should be named, what they should contain, or how they are GC'd. The agentdb_* tools mostly do not even take a namespace parameter — they route to controllers (reasoningBank, hierarchicalMemory, causalGraph) — but the CLI fallback memory_store and embeddings_search do take namespace strings, so the surface is mixed and undocumented.
  4. Token-efficiency path. The repo ships getCompactContext on the TokenOptimizer (v3/@claude-flow/integration/src/token-optimizer.ts:109), and agentdb_context-synthesize exists 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_LEVELS at controller-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_initembeddings_rabitq_build (one-time, after corpus is loaded) → embeddings_rabitq_search (Hamming-prefilter to top-N candidates) → optional rerank via embeddings_search (exact, on the candidate set) → embeddings_rabitq_status for 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-tools frontmatter line.
  • A note: RaBitQ _search returns candidate IDs only; the rerank step is the user's responsibility (mirrors the docstring at embeddings-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:

ProfileefSearchMUse case
recall-first20032Pattern recall during planning, search quality matters more than ms
balanced (default)6416General-purpose semantic recall
latency-first168Hot-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 per agentdb-tools.ts:144), claude-memories (Claude Code auto-memory bridge target), default (memory_store default per memory-tools.ts:194).
  • Controller routing: tools in the agentdb_hierarchical-* family route by tier (working|episodic|semantic) not by namespace; tools in the agentdb_pattern-* family route by ReasoningBank, again not by namespace. Document explicitly that namespace strings only apply to memory_* and embeddings_search paths. This stops downstream plugins from passing a namespace arg to agentdb_pattern-store and being silently confused when it's ignored.
  • GC posture: ruflo-agentdb does not GC namespaces. Consumer plugins that want lifecycle (e.g., browser-sessions after purge) own their own deletion via memory_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 pass validateIdentifier (the same validator already used in agentdb-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-store returns controller: 'memory-store-fallback'. Document this in agents/agentdb-specialist.md so 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-edge tries the native @ruvector/graph-node backend first, then the bridge. Document the _graphNodeBackend: true field so consumers can branch on it.
  • Bridge unavailable (returned by every handler when bridgeHealthCheck returns null): the response is { success: false, error: '...Use memory_store/memory_search instead.' }. Add one paragraph in the README enumerating which memory_* tool replaces which agentdb_* 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):

  1. agentdb_health returns { available: true, ... }. The bridge is wired.
  2. agentdb_controllers.total >= 15 and agentdb_controllers.active >= 10. The lower-bound assertions are deliberately loose — they verify "the registry initialized at all" without hard-coding the 29-name ControllerName union or the 15 agentdb_* 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.
  3. 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.
  4. 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.
  5. The 3 documented ruvllm_hnsw_* tools are all callable: ruvllm_hnsw_create (dim=384, max=11), ruvllm_hnsw_add, ruvllm_hnsw_route.
  6. RaBitQ build runs: embeddings_rabitq_build then embeddings_rabitq_status reports available: true.
  7. Pattern-store with the bridge intentionally unavailable returns controller: 'memory-store-fallback'. Caveat — this check has a load-bearing unverified assumption: the env-var name MEMORY_BRIDGE_DISABLE=1 was inferred from the fallback code path, not confirmed against the actual gating mechanism in bridgeHealthCheck. Implementer must grep agentdb-tools.ts + memory-bridge.ts for the real switch (it may instead key on AGENTDB_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.
  8. agentdb_hierarchical-store rejects a tier value not in {working, episodic, semantic} (regression on agentdb-tools.ts:426).
  9. agentdb_batch rejects a 501-element entries array (regression on MAX_BATCH_SIZE = 500 at agentdb-tools.ts:20).
  10. 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/cli v3.6.x with bundled agentdb@^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.json to 0.3.0 when 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 npm agentdb package, 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, future ruflo-knowledge-graph integrations) 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.sh makes 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-namespace helper 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_build if no vectors are loaded yet. Mitigation: smoke seeds 10 vectors via memory_store before exercising the rabitq path.
  • We do not propose changing agentdb-tools.ts itself. 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.00.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.json keywords beyond optionally adding rabitq and quantization. Keywords are advisory only.

Verification

A future implementation must satisfy this smoke contract before the ADR moves from Proposed → Accepted:

bash
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.
  • 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.mdbrowser-* namespace family that motivated §4 (namespace convention contract).
  • v3/docs/adr/ADR-053-... — controller activation pipeline (referenced by the bridge module docstring at memory-bridge.ts:5).
  • v3/docs/adr/ADR-087-graph-node-native-backend.md — graph-node backend used as the primary agentdb_causal-edge path.
  • v3/docs/adr/ADR-093-mcp-audit-may-2026-remediation.md — F4 introduced the memory-store-fallback controller string surfaced by §5.
  • v3/docs/adr/ADR-095-architectural-gaps-from-april-audit.md — G7 closed five disabled controllers; the README block README.md:22–35 summarizes G7 correctly.
  • v3/@claude-flow/cli/src/mcp-tools/agentdb-tools.ts — 15 agentdb_* tool definitions (canonical surface for §6 check 3).
  • v3/@claude-flow/cli/src/mcp-tools/embeddings-tools.ts — 10 embeddings_* tool definitions including RaBitQ trio at :910–981.
  • v3/@claude-flow/cli/src/mcp-tools/ruvllm-tools.ts — 3 ruvllm_hnsw_* tools, ~11-pattern WASM cap at :58.
  • v3/@claude-flow/memory/src/controller-registry.ts:34–73ControllerName union (canonical 29-name list).
  • v3/@claude-flow/memory/src/controller-registry.ts:160–174INIT_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:109getCompactContext token-efficiency path (deferred: §6 covers agentdb_context-synthesize only; the integration-layer optimizer is a separate ADR if surfaced).