Skip to content

AgentDB creates ruvector.db and agentdb.rvf in the process cwd instead of beside dbPath #28

Open

Description

@pacphi

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 from dbPath (:33).
  • core/AgentDB.d.ts:3-13: AgentDBConfig has dbPath, vectorBackend, vectorDimension and 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 }) without storagePath. ruvector 0.2.41 dist/index.js:166-186 forwards storagePath: undefined to the native VectorDb, 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 to createRvfBackend(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-73
  • src/backends/ruvector/RuVectorBackend.ts:336
  • src/backends/factory.ts:247-250
  • src/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 during initialize().

Impact

  • Split vector state. Which process indexes into ruvector.db and which into agentdb.rvf depends 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.lock and agentdb.rvf.idmap.json appear 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 nor ruflo init adds 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 dbPath by default, for example path.join(dirname(dbPath), basename(dbPath, ext) + '.ruvector.db') and ... + '.rvf'. Keep :memory: in memory. Pass it as storagePath to both RuVectorBackend and RvfBackend, and have RuVectorBackend forward it to new VectorDB(...). Today RuVectorBackend.js never references storagePath.
  • Add vectorStoragePath (or vectorBackendConfig) to AgentDBConfig so 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/cli ruvector/vector-db.ts. It says new VectorDBClass({ dimensions }) with no storagePath "defaulted to agentdb.rvf in 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 store writes to ruvector.db but stats/list/search read from empty sql.js — three contradictory persistence surfaces (parallel to #2245) ruflo#2259 (open): ruflo memory store writes to ruvector.db while stats, list and search read elsewhere. It shows the same root-level ruvector.db from 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.db among the files involved.
  • Duplicate search (open and closed, 2026-09-26): all 16 issues and 9 PRs in ruvnet/agentdb were read. gh search ran in ruvnet/agentdb for agentdb.rvf, storagePath, ruvector.db, working directory, RuVector initialization failed, lock, vector backend working directory and rvf storagePath, and for PRs on storagePath. It also ran in ruvnet/ruflo for agentdb.rvf, ruvector.db, Cannot acquire lock and RuVector initialization failed, plus PRs on agentdb.rvf, and in ruvnet/RuVector for ruvector.db current directory. No existing report for AgentDB's own backends.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions