Repository navigation
Description
Summary
AgentDB.initialize() builds its vector backend with only { dimensions, metric }. It passes no storage path and derives none from dbPath. The RuVector backend therefore opens the native VectorDb without a storagePath, so ruvector uses ./ruvector.db in the process working directory. The RVF fallback defaults to the relative path 'agentdb.rvf', also in the working directory. AgentDBConfig has no option to change either path. As a result, two AgentDB instances that share a working directory contend for one ./ruvector.db, even when their dbPaths are completely different. The second instance cannot acquire the lock, so it silently falls back to RVF and writes a second vector store, ./agentdb.rvf. The log line that explains the fallback says "Please install: npm install ruvector", which is not the cause. In ruflo this is the everyday case: the Claude Code and Codex MCP servers and the CLI memory commands all open AgentDB with the project root as their working directory. Each project then carries two unrelated vector files at its root, and which process uses which file depends on start order.
Environment
| Component | Version | Source of the value |
|---|---|---|
| macOS | 27.0 (build 26A428), kernel Darwin 27.0.0 | sw_vers, uname -r |
| Architecture | arm64 | uname -m |
| Node.js | v26.4.0 (mise-managed) | node --version |
| npm | 11.17.0 | npm --version |
| pnpm | 11.17.0 (mise-managed standalone binary) | pnpm --version |
| ruflo | 3.45.0 (npm latest 3.45.0) |
<npm-root-g>/ruflo/package.json; ruflo --version → ruflo v3.45.0 |
| @claude-flow/cli (bundled in ruflo) | 3.45.0 (npm latest 3.45.0) |
<npm-root-g>/ruflo/node_modules/@claude-flow/cli/package.json (not installed globally on its own) |
| @claude-flow/memory (bundled in ruflo) | 3.0.0-alpha.25 (npm latest 3.0.0-alpha.26) |
<npm-root-g>/ruflo/node_modules/@claude-flow/memory/package.json; nested copy under @claude-flow/cli is also 3.0.0-alpha.25 |
| agentdb (bundled in ruflo) | 3.0.0-alpha.20 (npm latest 3.0.0-alpha.20) |
<npm-root-g>/ruflo/node_modules/agentdb/package.json; nested copies under @claude-flow/cli and @claude-flow/memory are also 3.0.0-alpha.20 |
| agentdb (global standalone) | 3.0.0-alpha.17 | <npm-root-g>/agentdb/package.json; agentdb --version → agentdb v3.0.0-alpha.17 |
| ruvector (bundled in ruflo) | 0.2.41 | <npm-root-g>/ruflo/node_modules/ruvector/package.json (same version nested under @claude-flow/cli, @claude-flow/memory, agentdb) |
| ruvector (global) | 0.3.3 (npm latest 0.3.3) |
<npm-root-g>/ruvector/package.json; ruvector --version → 0.3.3 |
| agentic-qe | 3.14.3 (npm latest 3.14.3) |
<npm-root-g>/agentic-qe/package.json; aqe --version → 3.14.3 |
| ruvnet-brain plugin (Claude Code) | 4.3.28 (active, user scope, commit e89ea1ba167d) | ~/.claude/plugins/installed_plugins.json; ~/.claude/plugins/cache/ruvnet-brain/ruvnet-brain/4.3.28/.claude-plugin/plugin.json (older cache dirs 4.3.21 and 4.3.26 also present) |
| ruvnet-brain KB bundle | brainVersion 4.3.28 (releaseTag v4.3.28, builtUtc 2026-09-21T03:14:37.838Z) | ~/.cache/ruvnet-brain/kb/SOURCE.json |
| Claude Code | 2.1.283 (native installer) | claude --version; ~/.local/bin/claude → ~/.local/share/claude/versions/2.1.283 |
| codex-cli | 0.157.0 | codex --version; <npm-root-g>/@openai/codex/package.json |
| agentic-kit (global) | 4.0.0-alpha.55 | <npm-root-g>/@pacphi/agentic-kit/package.json; ak --version |
| agentic-kit (repo HEAD) | 9fcc06c34d9e (branch fix/audit-237-238-remediation; package.json 4.0.0-alpha.55) | git rev-parse HEAD |
<npm-root-g> = ~/.local/share/mise/installs/node/26.4.0/lib/node_modules (npm root -g). npm latest dist-tags read with npm view <pkg> dist-tags. Captured 2026-09-26.
The copy tested is the agentdb 3.0.0-alpha.20 bundled in ruflo 3.45.0. It uses the ruvector 0.2.41 nested under agentdb.
Steps to reproduce
A. AgentDB only (no ruflo)
Two plain Node processes run in one throwaway working directory, with a throwaway HOME and an empty environment. Each opens AgentDB with a different dbPath.
AGENTDB="$(npm root -g)/ruflo/node_modules/agentdb" # 3.0.0-alpha.20
T=$(mktemp -d); mkdir -p "$T/home" "$T/work"; cd "$T/work"
run() { env -i PATH="$PATH" HOME="$T/home" TERM=dumb "$@"; }
cat > open.mjs <<EOF
import fs from 'node:fs';
const [dbPath, holdMs] = process.argv.slice(2);
fs.mkdirSync(dbPath.split('/')[0], { recursive: true });
const { AgentDB } = await import('$AGENTDB/dist/src/index.js');
const db = new AgentDB({ dbPath });
await db.initialize();
console.log(\`RESULT pid=\${process.pid} dbPath=\${dbPath} vectorBackend=\${db.vectorBackend?.name}\`);
setTimeout(() => process.exit(0), Number(holdMs));
EOF
files() { ls -1 | grep -vE '^(open.mjs|a.log|b.log)$' | tr '\n' ' '; }
run node open.mjs store-a/agentdb.db 15000 > a.log 2>&1 & # process A stays open
until grep -q RESULT a.log; do sleep 0.5; done; grep RESULT a.log
echo "files in cwd after process A: $(files)"
run node open.mjs store-b/agentdb.db 0 > b.log 2>&1
grep -E 'RESULT|RuVector initialization failed|Reason:|Using RVF' b.log
echo "files in cwd after process B: $(files)"
echo "holder of ./ruvector.db: $(lsof -t -- ruvector.db)"Output:
RESULT pid=56918 dbPath=store-a/agentdb.db vectorBackend=ruvector
files in cwd after process A: ruvector.db store-a
[AgentDB] RuVector initialization failed, trying RVF backend
[AgentDB] Reason: RuVector initialization failed. Please install: npm install ruvector
[AgentDB] Using RVF backend (N-API fallback)
RESULT pid=57448 dbPath=store-b/agentdb.db vectorBackend=rvf
files in cwd after process B: agentdb.rvf agentdb.rvf.lock ruvector.db store-a store-b
holder of ./ruvector.db: 56918
The "Reason" line prints only the first line of the error. Constructing RuVectorBackend directly while process A still held the lock gave the full message: "RuVector initialization failed. Please install: npm install ruvector\nOr legacy packages: npm install @ruvector/core\nError: Failed to create database: Database error: Database already open. Cannot acquire lock.". The last line is thrown by the native VectorDb constructor, which is called at ruvector/dist/index.js:186.
B. The same thing through ruflo, two MCP servers in one project
This matches Claude Code and Codex each running ruflo mcp start in the same repository. It was run in a throwaway project after ruflo init and ruflo memory init, with the same empty environment. Any ruvector.db and agentdb.rvf* left in the project root by those two commands were deleted before the servers started, so the root begins empty. Each server received one memory_store call over stdio.
root files before: []
server A pid=69784 memory_store: {"success":true,"backend":"sqlite (bridge, brute-force cosine)"}
root files after A: ["ruvector.db"]
server B pid=69909 memory_store: {"success":true,"backend":"sqlite (bridge, brute-force cosine)"}
root files after B: ["agentdb.rvf","agentdb.rvf.lock","ruvector.db"]
agentdb.rvf: 162 bytes, held open by: B
agentdb.rvf.lock: 104 bytes, held open by: -
ruvector.db: 1589248 bytes, held open by: A
Both servers resolved their database to <project>/.swarm/agentdb-memory.db, but neither vector file is under .swarm. Server B printed nothing about the fallback, because ruflo's ControllerRegistry filters [AgentDB] log lines during initialize(). On a real repository on this machine, a long-running Claude Code ruflo mcp start process holds <repo>/agentdb.rvf. <repo>/ruvector.db exists next to it.
A process started from a subdirectory puts the file there. A ruflo CLI memory store --path <project>/.swarm/memory.db run with cwd=<project>/.swarm created <project>/.swarm/ruvector.db.
Expected vs actual
Expected: An AgentDB instance keeps its vector index next to its database, for example <dirname(dbPath)>/<basename>.ruvector or .rvf, or at a path given in AgentDBConfig. Two instances with different dbPaths never share a vector file. If a backend cannot open its store, the log names the real error.
Actual: The vector files always go to process.cwd(). Different databases in one working directory share ./ruvector.db. The second opener falls back to a different backend and file (./agentdb.rvf). The log blames a missing ruvector install.
Evidence
Installed agentdb 3.0.0-alpha.20 (<npm-root-g>/ruflo/node_modules/agentdb/dist/src/):
core/AgentDB.js:47-50:createBackend(this.config.vectorBackend || 'auto', { dimensions: vectorDimension, metric: 'cosine' }). No storage path is passed, and none is derived fromdbPath(:33).core/AgentDB.d.ts:3-13:AgentDBConfighasdbPath,vectorBackend,vectorDimensionand a few unrelated options (namespace,enableAttention,attentionConfig,forceWasm), but no vector storage path.backends/ruvector/RuVectorBackend.js:254-260:new VectorDB({ dimensions, metric, maxElements, efConstruction, m })withoutstoragePath.ruvector0.2.41dist/index.js:166-186forwardsstoragePath: undefinedto the nativeVectorDb, which then uses./ruvector.db.backends/ruvector/RuVectorBackend.js:271-283: every non-path error is rewritten as "RuVector initialization failed. Please install: npm install ruvector".backends/factory.js:190-212: auto mode tries RuVector first. On failure it logs only the first line of that message (:203-204), then falls back tocreateRvfBackend(config)with the same config (:206).backends/rvf/RvfBackend.js:60:this.storagePath = config.storagePath ?? 'agentdb.rvf';, a path relative to the working directory.
Upstream ruvnet/agentdb main at 6cdefe4 (release 3.0.0-alpha.20, current HEAD):
src/core/AgentDB.ts:71-73src/backends/ruvector/RuVectorBackend.ts:336src/backends/factory.ts:247-250src/backends/rvf/RvfBackend.ts:127
A RuvNet Brain search (search_ruvnet) did not route to these files, so the upstream paths above come from the GitHub tree.
Consumer side (ruflo 3.45.0, @claude-flow/memory 3.0.0-alpha.25 dist/controller-registry.js):
:338:new AgentDBClass({ dbPath }). There is no other way to pass a vector path.:340-356:[AgentDB]console lines are suppressed duringinitialize().
Impact
- Split vector state. Which process indexes into
ruvector.dband which intoagentdb.rvfdepends on start order. The same project's reflexion, skill and causal-graph vectors end up in two stores, and each process sees only its own. - Stray files in repositories.
ruvector.db(about 1.5 MB when empty),agentdb.rvf,agentdb.rvf.lockandagentdb.rvf.idmap.jsonappear at the root of every project where a tool opens AgentDB. They also appear in whatever subdirectory a tool happens to run from, such as.swarm/. Neither agentdb norruflo initadds them to.gitignore. - Misleading diagnosis. "Please install: npm install ruvector" sends users to reinstall a package that is already installed.
- Cross-database contention. Unrelated AgentDB databases block each other whenever they share a working directory.
Suggested direction
- Derive the vector store path from
dbPathby default, for examplepath.join(dirname(dbPath), basename(dbPath, ext) + '.ruvector.db')and... + '.rvf'. Keep:memory:in memory. Pass it asstoragePathto bothRuVectorBackendandRvfBackend, and haveRuVectorBackendforward it tonew VectorDB(...). TodayRuVectorBackend.jsnever referencesstoragePath. - Add
vectorStoragePath(orvectorBackendConfig) toAgentDBConfigso embedders such as ruflo can place it explicitly. - Keep the original native error in the fallback log, and treat a lock conflict as "busy" rather than "not installed".
- Consider whether a second process should fall back to a different on-disk backend at all, rather than opening read-only or failing loudly. The fallback is what turns a lock conflict into split state.
Related
- ruvnet/ruflo PR #2230 (open): fixes the same class in ruflo's own
@claude-flow/cliruvector/vector-db.ts. It saysnew VectorDBClass({ dimensions })with nostoragePath"defaulted toagentdb.rvfin CWD, which running daemons hold exclusively". The installed 3.45.0 already has that change (vector-db.js:141-152,os.tmpdir()/ruvector-<pid>-<uuid>.rvf). The AgentDB-internal backends reported here are a separate path it does not touch. - v3.10.31:
ruflo memory storewrites toruvector.dbbutstats/list/searchread from empty sql.js — three contradictory persistence surfaces (parallel to #2245) ruflo#2259 (open):ruflo memory storewrites toruvector.dbwhilestats,listandsearchread elsewhere. It shows the same root-levelruvector.dbfrom the consumer side. - new AgentDB() aborts the process on Windows x64: "memory allocation of 4436141952 bytes failed" (3.0.0-alpha.20) #22 (closed): an unrelated Windows allocation abort, which lists
ruvector.dbamong the files involved. - Duplicate search (open and closed, 2026-09-26): all 16 issues and 9 PRs in ruvnet/agentdb were read.
gh searchran in ruvnet/agentdb foragentdb.rvf,storagePath,ruvector.db,working directory,RuVector initialization failed,lock,vector backend working directoryandrvf storagePath, and for PRs onstoragePath. It also ran in ruvnet/ruflo foragentdb.rvf,ruvector.db,Cannot acquire lockandRuVector initialization failed, plus PRs onagentdb.rvf, and in ruvnet/RuVector forruvector.db current directory. No existing report for AgentDB's own backends.
Activity