OpenClaw's macOS Memory Fix Restores the Part of Agent Memory That Actually Makes Retrieval Useful
Agent memory has a product problem disguised as an infrastructure problem: users judge the assistant by what it recalls, but the quality of recall depends on native database flags most users will never see. PR #90323 is one of those fixes that looks like dependency plumbing until you follow the failure all the way up the stack. On affected macOS builds, OpenClaw's memory system could not load sqlite-vec, leaving embedding arrays empty and disabling vector similarity search. The agent still had keyword search. It did not have the part of memory that makes recall feel like recall.
The root cause is blunt. Node's built-in node:sqlite on macOS is compiled with OMIT_LOAD_EXTENSION=1. That compile-time flag prevents extension loading, so sqlite-vec cannot come online even when the application asks for it. Issue #66977 showed the symptom clearly: openclaw memory status returning Vector: unknown, warnings around sqlite-vec, and rows from SELECT id, embedding FROM chunks LIMIT 3; ending in empty arrays. Full-text search still worked through FTS5. Semantic vector search did not.
That distinction matters. FTS5 can find the exact phrase you used before. Vector search is how an agent connects "that deployment policy we discussed" with a note that said "gateway restart approval rules," or maps "the user's preferred newsletter voice" to a memory that never used the word preference. Without embeddings, persistent memory regresses toward grep with a nicer prompt. The assistant may seem forgetful, inconsistent, or oddly literal when the real problem is that the retrieval backend never loaded.
Macs are where local-agent bugs become product opinions
The macOS angle is not incidental. Local and open coding agents are disproportionately developed, tested, and demoed on Macs. If vector memory silently fails there, builders do not necessarily file a database bug. They conclude that agent memory is overpromised, that retrieval is weak, or that the framework's continuity story is mostly vibes. That is an expensive misdiagnosis because the fix is not better prompting. It is making sure the native extension actually loads and then exposing that state as a health check humans can understand.
PR #90323 replaces OpenClaw's memory subsystem use of node:sqlite with better-sqlite3. The patch introduces MemoryDb and MemoryStatement abstractions, adds requireBetterSqlite3(), and removes the old enableLoadExtension(true) call from loadSqliteVecExtension(). With better-sqlite3, the extension-loading path uses the library's bundled SQLite behavior. The verification quoted in the research is the line operators want to see: on macOS arm64 with Node v25.9.0, sqlite-vec loaded OK via better-sqlite3, with vec_version: v0.1.9.
The patch is not tiny. It touches 22 files across packages/memory-host-sdk, extensions/memory-core, src/infra/sqlite-wal.ts, the workspace files, and the lockfile. It also changes the dependency graph, which triggered guard comments and security review. Good. A native database dependency is not a clerical update in an agent framework. These systems already have broad supply-chain surface area: plugins, skills, MCP servers, browser automation, messaging channels, provider SDKs, sandbox tools, and local binaries. Restoring vector memory is worth the dependency, but it should land with explicit review rather than a shrug.
The test evidence is stronger than the average infrastructure patch. The memory-core suite passed 53 files and 607 tests. The memory host SDK passed 3 files and 8 tests. src/infra/sqlite-wal.test.ts passed 3 tests. One unrelated date-hardcoded dreaming test failed because the test expected the day to be 2026-05-18, which is the kind of failure worth separating from the behavior under review. The important proof is platform-specific: the extension loads on the affected macOS path and vector status can become real rather than unknown.
For operators, the immediate action is boring and necessary. After upgrading, run memory status. Do not settle for "the agent starts." Verify that vector support is present and that existing memory chunks have embeddings. If chunks were persisted while vector support was broken, they may need re-embedding; otherwise the backend can be healthy while the historical corpus remains semantically empty. That is the kind of half-fixed state that creates the worst support tickets: everything appears green, but recall still feels wrong.
For framework builders, this is a reminder to promote retrieval health into product health. Extension-loaded state, embedding coverage, vector index freshness, and fallback mode should be visible. If semantic search is unavailable, say so in the UI and logs. If the system is falling back to keyword-only retrieval, make that explicit. Users can forgive degraded mode if it is honest. They cannot debug invisible memory amnesia from chat behavior alone.
There is also a design lesson about abstraction boundaries. Depending on node:sqlite sounded attractive because it reduces external dependencies. But agent memory is not just a database convenience; it is a platform capability that depends on extension support. If the supposedly simpler dependency cannot provide the required primitive on a major developer platform, simplicity has become false economy. The correct dependency is the one that preserves the product invariant with clear operational evidence.
The story here is not a SQLite library swap. It is that persistent agents are only as reliable as the retrieval stack beneath them. If vector search is off, the assistant is remembering with one eye closed. OpenClaw's PR #90323 restores the eye that matters.
Sources: OpenClaw PR #90323, OpenClaw issue #66977, sqlite-vec, better-sqlite3