You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ruflo doctor opens the memory database with a native better-sqlite3 WAL
connection and exits without checkpointing, leaving a 0-bytememory.db-wal
and a memory.db-shm on disk. The #2735 safety gate treats the mere presence
of those sidecars as proof of a live native writer, so every later ruflo memory store in that project is refused — permanently, until the
sidecars are removed by hand.
The gate's own docstring states the assumption it relies on:
sidecars ... removed only on the last connection's clean close
doctor violates that assumption. The sidecars are orphans, not evidence of a
live holder, so the heuristic misfires and the CLI reports a condition that is
not true.
Environment
ruflo
3.38.20
Node
v24.20.0
npm
11.19.0
OS
Windows 11, 10.0.26200, win32 x64
Install
local (npm install ruflo@3.38.20); also reproduces via npx ruflo@latest
Reproduces with the background daemon stopped, so the daemon is not involved.
Reproduction
# 0. start from a checkpointed database (no sidecars)
rm -f .swarm/memory.db-wal .swarm/memory.db-shm
# 1. a write succeeds
ruflo memory store --namespace repro --key antes --value v
# -> [OK] Data stored successfully# 2. run doctor
ruflo doctor >/dev/null 2>&1# -> leaves wal=0 bytes, shm=32768 bytes# 3. the identical write now fails
ruflo memory store --namespace repro --key depois --value v
Step 3 output:
[ERROR] memory database has an active native WAL connection (found -wal/-shm
sidecar files) — refusing an unsafe sql.js whole-image write. Retry once the
native writer completes, or restore the native better-sqlite3 bridge.
Bridge unavailable: AgentDB native bridge disabled on Windows after #3024;
set CLAUDE_FLOW_ENABLE_NATIVE_BRIDGE_ON_WINDOWS=1 to opt in
Deleting the two sidecars restores writes immediately. No other command in the
CLI surface leaves them behind: bisecting doctor, config list, status, mcp status, daemon status, agent list, swarm status, session list and hooks list against a cleaned database, only doctor does.
Evidence that no writer is actually live
A wal_checkpoint(TRUNCATE) against the same database, at the moment the write
is being refused, reports no contention and removes both sidecars:
{"busy":0,"log":0,"checkpointed":0}
busy: 0 is SQLite reporting that no other connection holds the WAL. The
0-byte -wal says the same thing: there are no pending frames to recover.
The gate is presence-based, not liveness-based. It cannot distinguish a
live native holder from an orphan left by an unclean close, so any command that
leaks sidecars bricks the write path for the whole project directory.
Impact
memory store — and every feature built on it — fails for the rest of the
project's life until a user manually deletes internal database files.
The error message misdirects: it blames a live writer and the missing Windows
native bridge, so users chase CLAUDE_FLOW_ENABLE_NATIVE_BRIDGE_ON_WINDOWS=1,
which does not address the cause. Whether that variable "works" only reflects
whether sidecars happen to be present, making the failure look intermittent.
ruflo doctor, the command users are told to run when something is wrong, is
what breaks it.
Suggested fixes
Make doctor close cleanly. Run PRAGMA wal_checkpoint(TRUNCATE) and
close every connection it opens. This alone fixes the reported symptom.
Improve the message. When the -wal is 0 bytes and a checkpoint reports busy: 0, say the sidecars are stale and name the recovery, instead of
pointing at a native writer that does not exist.
Workaround for users
Checkpoint and close before writing; this is safe because a real writer makes busy !== 0 and nothing is removed:
constDatabase=require('better-sqlite3');constdb=newDatabase('.swarm/memory.db');constr=db.pragma('wal_checkpoint(TRUNCATE)')[0];db.close();if(r.busy!==0)thrownewError('a live writer holds the WAL — do not delete sidecars');
ruflo doctorleaves an orphaned WAL sidecar that blocks all subsequent memory writesPackage:
ruflo@3.38.20(@claude-flow/cli@3.38.20)Repo: https://github.com/ruvnet/claude-flow — file an issue at https://github.com/ruvnet/claude-flow/issues
Related: #2735 (the WAL-sidecar safety gate), #3024 (native bridge disabled on Windows)
Summary
ruflo doctoropens the memory database with a native better-sqlite3 WALconnection and exits without checkpointing, leaving a 0-byte
memory.db-waland a
memory.db-shmon disk. The #2735 safety gate treats the mere presenceof those sidecars as proof of a live native writer, so every later
ruflo memory storein that project is refused — permanently, until thesidecars are removed by hand.
The gate's own docstring states the assumption it relies on:
doctorviolates that assumption. The sidecars are orphans, not evidence of alive holder, so the heuristic misfires and the CLI reports a condition that is
not true.
Environment
npm install ruflo@3.38.20); also reproduces vianpx ruflo@latestReproduces with the background daemon stopped, so the daemon is not involved.
Reproduction
Step 3 output:
Deleting the two sidecars restores writes immediately. No other command in the
CLI surface leaves them behind: bisecting
doctor,config list,status,mcp status,daemon status,agent list,swarm status,session listandhooks listagainst a cleaned database, onlydoctordoes.Evidence that no writer is actually live
A
wal_checkpoint(TRUNCATE)against the same database, at the moment the writeis being refused, reports no contention and removes both sidecars:
busy: 0is SQLite reporting that no other connection holds the WAL. The0-byte
-walsays the same thing: there are no pending frames to recover.Root cause
node_modules/@claude-flow/cli/dist/src/memory/memory-initializer.js:78The gate is presence-based, not liveness-based. It cannot distinguish a
live native holder from an orphan left by an unclean close, so any command that
leaks sidecars bricks the write path for the whole project directory.
Impact
memory store— and every feature built on it — fails for the rest of theproject's life until a user manually deletes internal database files.
native bridge, so users chase
CLAUDE_FLOW_ENABLE_NATIVE_BRIDGE_ON_WINDOWS=1,which does not address the cause. Whether that variable "works" only reflects
whether sidecars happen to be present, making the failure look intermittent.
ruflo doctor, the command users are told to run when something is wrong, iswhat breaks it.
Suggested fixes
doctorclose cleanly. RunPRAGMA wal_checkpoint(TRUNCATE)andclose every connection it opens. This alone fixes the reported symptom.
wal_checkpoint(TRUNCATE)andtreat
busy === 0as "no live holder, safe to proceed" — the sidecars arealso removed as a side effect. This keeps memory CRUD silently degrades to a sql.js whole-image rename-over that can corrupt WAL databases under concurrent native writers #2735's guarantee (a real holder
still returns
busy !== 0and the write is still refused) while removing thefalse positive, with no platform-specific process scanning.
-walis 0 bytes and a checkpoint reportsbusy: 0, say the sidecars are stale and name the recovery, instead ofpointing at a native writer that does not exist.
Workaround for users
Checkpoint and close before writing; this is safe because a real writer makes
busy !== 0and nothing is removed: