Skip to content

CLI: skill/reflexion ignore --db and save it as record data; stats --db opens './--db' #27

Open

Description

@pacphi

Summary

init, status, doctor and import all accept --db <path>, but the skill, reflexion, causal, recall, learner, db, sync, query, store-pattern, train and optimize-memory commands do not. They choose their database only from AGENTDB_PATH, falling back to ./agentdb.db in the working directory. Their handlers read arguments by position, so a --db <path> pair is not rejected. It becomes record data instead. reflexion store … --db X saves an episode whose input is --db and whose output is X. skill create n d --db X saves a skill whose code is --db. Both land in ./agentdb.db, and X is never touched. stats takes only a positional path, so stats --db X opens ./--db instead of X. With native better-sqlite3 that creates files literally named --db, --db-shm and --db-wal in the working directory. None of these cases produces a warning.

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, whose CLI file is byte-identical to the published tarball's. It loads native better-sqlite3 12.11.1 from its nested node_modules. That copy was placed there by a local native-dependency repair step in agentic-kit, not by ruflo or npm. The skill and reflexion misrouting does not depend on the backend: the standalone 3.0.0-alpha.17 behaves the same way. It runs on sql.js because its tree has no better-sqlite3: the dependency is optional, and require.resolve('better-sqlite3') from its directory fails with MODULE_NOT_FOUND.

Steps to reproduce

The commands run in a fresh mktemp -d directory, with HOME pointed at a temporary directory and XDG_* and AGENTDB_PATH unset. AGENTDB_DISABLE_TRANSFORMERS=1 only prevents a model download and does not affect the defect. These are the exact commands run on 2026-09-26:

CLI="$(npm root -g)/ruflo/node_modules/agentdb/dist/src/cli/agentdb-cli.js"   # agentdb 3.0.0-alpha.20
T=$(mktemp -d); mkdir -p "$T/home" "$T/work"; cd "$T/work"
ad() { env -u XDG_CONFIG_HOME -u XDG_DATA_HOME -u XDG_CACHE_HOME -u XDG_STATE_HOME -u AGENTDB_PATH \
         HOME="$T/home" AGENTDB_DISABLE_TRANSFORMERS=1 node "$CLI" "$@"; }

ad init --db "$T/target.db" >/dev/null 2>&1; echo "init exit=$?"
ad reflexion store s1 task-a 0.9 true "worked" --db "$T/target.db" >/dev/null 2>&1; echo "reflexion store exit=$?"
ad skill create jwt_auth "Generate JWT" --db "$T/target.db" >/dev/null 2>&1; echo "skill create exit=$?"
ad skill search jwt 5 --db "$T/target.db" >/dev/null 2>&1; echo "skill search exit=$?"
ad skill consolidate --db "$T/target.db" 2>&1 | grep -m1 "Min Attempts"
ad stats --db "$T/target.db" 2>&1 | grep -m1 "Getting statistics"

ls -1A "$T/work"
sqlite3 "$T/target.db"      "select 'target.db episodes', count(*) from episodes; select 'target.db skills', count(*) from skills;"
sqlite3 "$T/work/agentdb.db" "select 'agentdb.db episode', session_id, task, input, output from episodes; select 'agentdb.db skill', name, code from skills;"

# control: the environment variable is honored
env -u XDG_CONFIG_HOME -u XDG_DATA_HOME -u XDG_CACHE_HOME -u XDG_STATE_HOME HOME="$T/home" \
  AGENTDB_DISABLE_TRANSFORMERS=1 AGENTDB_PATH="$T/target.db" \
  node "$CLI" reflexion store s2 task-b 0.9 true "worked" >/dev/null 2>&1; echo "AGENTDB_PATH reflexion store exit=$?"
sqlite3 "$T/target.db" "select 'target.db episodes after AGENTDB_PATH', count(*) from episodes;"

Output (temp path shown as $T, ANSI colours stripped):

init exit=0
reflexion store exit=1
skill create exit=1
skill search exit=0
ℹ Min Attempts: 3
ℹ Getting statistics for: --db
--db
--db-shm
--db-wal
agentdb.db
agentdb.db-shm
agentdb.db-wal
target.db episodes|0
target.db skills|0
agentdb.db episode|s1|task-a|--db|$T/target.db
agentdb.db skill|jwt_auth|--db
AGENTDB_PATH reflexion store exit=1
target.db episodes after AGENTDB_PATH|1

The exit=1 results come from a separate defect, reported in the companion issue #26 ("CLI write commands exit 1 after committing: this.db.save is not a function"). Write commands throw this.db.save is not a function on native better-sqlite3 after the row has been committed. The misrouting shown here does not depend on that defect. skill search exits 0 and silently searches ./agentdb.db. skill consolidate --db X reads --db as the positional min-attempts: parseInt('--db') gives NaN, which falls back to 3, as the Min Attempts: 3 line shows. It then runs against ./agentdb.db.

Against the global standalone agentdb 3.0.0-alpha.17 (sql.js), reflexion store and skill create exit 0 and misroute the same way. These are the exact commands run, in the same sandbox and without init:

CLI="$(npm root -g)/agentdb/dist/src/cli/agentdb-cli.js"   # agentdb 3.0.0-alpha.17
T=$(mktemp -d); mkdir -p "$T/home" "$T/work"; cd "$T/work"
ad() { env -u XDG_CONFIG_HOME -u XDG_DATA_HOME -u XDG_CACHE_HOME -u XDG_STATE_HOME -u AGENTDB_PATH \
         HOME="$T/home" AGENTDB_DISABLE_TRANSFORMERS=1 node "$CLI" "$@"; }
ad reflexion store s1 task-a 0.9 true "worked" --db "$T/target.db" 2>&1 | grep -E "native|sql.js|WASM|Stored|❌" | head -3; echo "reflexion store exit=${PIPESTATUS[0]}"
ad skill create jwt_auth "Generate JWT" --db "$T/target.db" 2>&1 | grep -E "Created|❌"; echo "skill create exit=${PIPESTATUS[0]}"
ls -1A "$T/work"; ls "$T/target.db" 2>&1 | sed "s#$T#\$T#"
sqlite3 "$T/work/agentdb.db" "select 'agentdb.db episode', session_id, task, input, output from episodes; select 'agentdb.db skill', name, code from skills;" | sed "s#$T#\$T#"

Output (ANSI colours stripped):

✅ Using sql.js (WASM SQLite, no build tools required)
✅ Stored episode #1
reflexion store exit=0
✅ Created skill #1
skill create exit=0
agentdb.db
ls: $T/target.db: No such file or directory
agentdb.db episode|s1|task-a|--db|$T/target.db
agentdb.db skill|jwt_auth|--db

On sql.js (alpha.17, or alpha.20 with AGENTDB_FORCE_SQLJS=1), stats --db X still prints Getting statistics for: --db and reports on that path instead of X, but it leaves no --db* files in the working directory.

Expected vs actual

Expected: Every command that opens a database honors --db <path>, as init, status, doctor and import already do. A command that does not support the flag rejects it and exits non-zero rather than treating it as data. stats --db X reports on X.

Actual:

Command What happens
reflexion store … --db X Writes to ./agentdb.db; --db and X become the episode's input and output
skill create … --db X Writes to ./agentdb.db; --db becomes the skill's code
skill search … --db X Searches ./agentdb.db and exits 0
skill consolidate --db X Runs against ./agentdb.db with --db parsed as min-attempts
stats --db X Reports on ./--db instead of X; with native better-sqlite3 it also creates ./--db, ./--db-shm and ./--db-wal
X itself Stays empty (0 episodes, 0 skills); in the alpha.17 run, which skips init, it is never created

Evidence

Installed package: agentdb 3.0.0-alpha.20 (bundled in ruflo 3.45.0), <npm-root-g>/ruflo/node_modules/agentdb/dist/src/cli/agentdb-cli.js:

  • :1592: const dbPath = process.env.AGENTDB_PATH || './agentdb.db'; is the only path source for everything dispatched at :1596-1628 (causal, recall, learner, reflexion, skill, db, sync, query, store-pattern, train, optimize-memory).
  • --db is parsed only by init (:1389-1391), status (:1404-1406), doctor (:1466-1468) and import (handleImportCommand, :2611-2612).
  • :2683 (handleStatsCommand): const dbPath = args[0] || './agentdb.db'; takes the first token, so --db becomes the path.
  • Positional handlers with no flag rejection:
    • reflexion store :1863-1874, where input: args[5] and output: args[6]
    • skill create :1955-1960, where code: args[2]
    • skill search :1962-1966
    • skill consolidate :1968-1974, where minAttempts: args[0] ? parseInt(args[0]) : undefined
  • The help documents --db for init, status, doctor and import (:2754, :2757, :2761, :2826), a positional path for stats (:2830, agentdb stats [db-path]), and AGENTDB_PATH under ENVIRONMENT (:3027). No text says skill and reflexion accept only the environment variable.
  • The standalone agentdb 3.0.0-alpha.17 has the same lines (:1592, :2683).

Upstream source, ruvnet/agentdb main at 6cdefe4 (release 3.0.0-alpha.20, still HEAD on 2026-09-26), src/cli/agentdb-cli.ts:

  • :1948: the AGENTDB_PATH fallback
  • :1742, :1757, :1815, :2966: --db in init, status, doctor and import
  • :3058: stats args[0]
  • :2226: reflexion store input: args[5]
  • :2307: skill create code: args[2]
  • :2316: skill consolidate minAttempts: args[0]
  • :3410: the help's ENVIRONMENT block

A RuvNet Brain search (search_ruvnet) returned only agentdb and agentic-flow documentation for this query, not the CLI source, so the upstream paths above come from the GitHub tree.

Impact

  • Silent misrouting. Episodes and skills go to a ./agentdb.db that depends on the caller's working directory, while the database the caller named stays empty. A wrapper that passes --db to every subcommand, as the help suggests for init and status, splits its data across stores without noticing.
  • Data corruption. Flag tokens and file paths are persisted into input, output and code fields, and later retrievals and searches return them. The episode's output (here, the path) is also part of the text ReflexionMemory.buildEpisodeText() embeds.
  • Stray files. With native better-sqlite3, stats --db X leaves --db* files in the working directory, which must be removed with rm -- --db*.

Suggested direction

  • Parse --db <path> (and --db=<path>) once in main() before dispatch. Apply the precedence --db > AGENTDB_PATH > ./agentdb.db and remove the pair from the arguments passed to handlers.
  • Let stats (and export) accept --db as well as the positional path.
  • Make the positional handlers reject unknown -- options with a non-zero exit instead of storing them.
  • Document the precedence in --help.

Related

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