Killing Mem0: Why I Ripped Out My OpenClaw Memory Plugin and What I Replaced It With

It started, as most Friday night rabbit holes do, with one thing that wasn’t working quite right.

I’d been running Mem0 as my OpenClaw memory plugin for a few weeks. The pitch is good: persistent memory across sessions, semantic recall, seamless context. In practice? My agent didn’t seem to remember things the way I expected. Recalls felt shallow. Sometimes they didn’t happen at all. I chalked it up to the usual AI flakiness — until I started actually reading the source code.

What I found was not great.

## The Mem0 Bug Stack

The official `@mem0/openclaw-mem0` plugin (v0.1.2) has several issues that make it particularly painful for self-hosted setups. None of them are obvious from the README.

**Bug #1: The SDK Thunderdome**

At startup, the plugin eagerly imports 17 provider SDKs. Not lazily — eagerly, all at once. If any of those SDKs aren’t installed in your environment, the whole thing crashes. On a lean self-hosted setup, you probably don’t have all 17 packages sitting around. Result: cryptic startup errors that have nothing to do with your actual configuration.

**Bug #2: The Silent Discard Problem**

Auto-recall is supposed to silently inject relevant memories into every conversation. Except it wasn’t injecting anything — because of a wrong property name in the hook return value. Memories were being retrieved, evaluated, and then quietly dropped. You’d never know unless you were reading the source. (Filed upstream: [mem0ai/mem0#4037](https://github.com/mem0ai/mem0/issues/4037))

**Bug #3: Local Embeddings? Not Really.**

I’m running Ollama locally for embeddings — to keep everything on-device and avoid API costs. The Mem0 plugin claims to support a configurable `baseURL`. In practice, it ignores it. Every embedding call goes to `api.openai.com` regardless of your config. If you’re air-gapped or just don’t want surprise outbound calls, this is a problem. (Filed: [mem0ai/mem0#4040](https://github.com/mem0ai/mem0/issues/4040))

**Bug #4: The macOS Arm64 SQLite Situation**

Native binding resolution for SQLite/jiti fails on macOS arm64 with Node v25. Not strictly Mem0’s fault — it’s a known ecosystem issue — but it means the plugin doesn’t work out of the box on modern Apple Silicon Macs with a current Node version.

**Bug #5: The Memory Monopoly**

The Mem0 plugin claims the exclusive global memory slot in OpenClaw. Installing it automatically disables whatever memory system you were already running — for all agents, not just the ones you configure. It’s an undocumented footgun that silently wiped out my existing setup.

There’s a community fork from tensakulabs ([github.com/tensakulabs/openclaw-mem0](https://github.com/tensakulabs/openclaw-mem0)) that patches several of these, but you’re still working against the upstream design. And if you’re on Mem0’s cloud tier, costs add up: I’ve seen reports of embedding overhead reaching seven cents per message at scale.

I decided to pull it.

## The Removal Process (And Why It’s Messier Than It Should Be)

Here’s something OpenClaw doesn’t have yet: `openclaw plugins uninstall`. No clean removal command. You’re doing this manually.

The steps:

1. **Back up your config file before touching anything.** Do this first, not second.
2. Open your `openclaw.json` and remove the Mem0 block from `plugins.entries`.
3. Remove the corresponding block from `plugins.installs`.
4. Delete the plugin directory from your extensions folder.
5. **Validate your JSON after every edit.**

That last point tripped me up more than once. JSON doesn’t tolerate trailing commas. One stray comma after removing a block and your entire config fails to parse on restart. I learned to run a validation pass after every edit:

“`bash
python3 -c “import json; json.load(open(‘openclaw.json’))”
“`

No output means clean. An error means fix the syntax before you restart anything.

I also discovered that `openclaw config unset` commands exist and are much safer for removing individual keys than hand-editing JSON. Use the CLI when it exists. Lesson learned the hard way.

## Installing QMD: A Node Version Horror Story

Once Mem0 was out, I wanted to bring in QMD — Query Markup Documents — as the retrieval layer. QMD is a local hybrid search sidecar built by Tobi Lütke (Shopify CEO). MIT licensed, 16k+ GitHub stars, runs on Metal GPU. Installation is via Bun, not npm.

Here’s where the Friday night got interesting.

**The dual-account problem.** My Mac Mini runs OpenClaw under a dedicated service account. Admin tools (Homebrew, npm global packages) live under a separate admin account. Bun was installed via Homebrew under the admin account — which means running `bun install -g @tobilu/qmd` under the service account required a bit of coordination. Not complicated, but if you hit permission errors, this is usually why.

**The Node version mismatch.** My gateway runs Node v25.6.1 via a LaunchAgent. My interactive shell uses Node v22.22.0. These are not the same. The `better-sqlite3` native binding that QMD depends on is compiled against a specific Node version — and it needs to match the version that will actually *run* it, which is the gateway version, not your shell version.

The fix: rebuild with the target version explicitly:

“`bash
npx node-gyp rebuild –target=25.6.1
“`

Make sure you’re using the correct Node binary path when you do this. Then I needed a small wrapper script to make the QMD CLI invoke Node v25 instead of whatever `node` resolves to in my shell. Not a huge deal once you know what’s happening, but it took an embarrassing amount of time to diagnose.

**The node-llama-cpp trust issue.** Bun sandboxes postinstall scripts by default. `node-llama-cpp` — which QMD uses for its GGUF models — has a postinstall that downloads model files. Bun blocked it. Fix:

“`bash
bun pm -g trust node-llama-cpp
“`

Then reinstall. After that, the three GGUF models (~2GB total) downloaded cleanly.

**LanceDB going missing.** At some point during the chaos, the LanceDB module disappeared from OpenClaw’s node_modules. This is one of those dependency collisions that happens when you’re pulling things apart and putting them back together. The fix was a clean reinstall via the admin account. If you see LanceDB-related import errors after a plugin overhaul, this is likely why.

The moral: when you’re doing major surgery on an OpenClaw installation, know which account owns which layer. Admin account owns Homebrew and npm globals. Service account runs the gateway. Keep those boundaries clear or expect friction.

## The Replacement Stack: QMD + LanceDB

After all that, here’s what’s actually running:

**LanceDB** handles the write layer — continuous capture of decisions, conversation events, and key facts. It runs fully local using Ollama’s nomic-embed-text model (768-dimension embeddings). Think of it as the append-only journal: always writing, never interrupting.

**QMD** handles retrieval. It runs three small GGUF models in parallel:
– `embedding-gemma-300M` — fast embedding
– `Qwen3-Reranker-0.6B` — relevance reranking
– `qmd-query-expansion-1.7B` — query expansion for better semantic recall

All three run locally on Metal GPU. Indexing a large workspace full of markdown files took under 30 seconds on an M4 Pro. First search result: 88% relevance on notes written weeks earlier. That’s the recall I was trying to get from Mem0 and never did.

**The mental model:**

– **Markdown files** → human-readable source of truth. Curated, intentional.
– **LanceDB** → write layer. Continuous capture, queryable via vector search.
– **QMD** → retrieval layer. What you query when you need to find something across your full workspace history.

Mem0 was trying to do all three in one plugin and doing none of them reliably. Breaking it into layers means each component does one thing, runs locally, and can be replaced independently.

Zero cloud dependency. Zero API cost for memory. Everything private.

## Was It Worth It?

Two and a half hours on a Friday night to rip out a plugin, survive a Node version mismatch, and stand up two separate systems. Not exactly how I planned to spend it.

But a memory system that silently drops recalls isn’t a memory system. It’s a false sense of context. I’d rather have a stack I understand and can debug than a black box that occasionally does the right thing.

If you’re running OpenClaw self-hosted and you’ve been fighting Mem0, the bugs above are real and documented. The tensakulabs fork helps but doesn’t close everything. QMD + LanceDB is working cleanly.

**Links:** [github.com/tobi/qmd](https://github.com/tobi/qmd) · [github.com/tensakulabs/openclaw-mem0](https://github.com/tensakulabs/openclaw-mem0)

*Hardware: Mac Mini M4 Pro, 24GB unified memory | QMD v2.0.1 | LanceDB with nomic-embed-text 768d | Bun 1.3.11*


Related Posts

2 thoughts on “Killing Mem0: Why I Ripped Out My OpenClaw Memory Plugin and What I Replaced It With”

  1. Pingback: OpenClaw Cron Migration: Moving 18 Automated Jobs from Cloud to Local in One Night – The AI Field Notes

  2. Pingback: Supercharging OpenClaw with Tavily and Exa: Two Search APIs Worth Installing – The AI Field Notes

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top