memsearch Review: Does OpenClaw's Memory Library Work Alone?

memsearch Review: Does OpenClaw's Memory Library Work Alone?

Two agent processes, one shared memory directory, writes fired close together in time. Nothing in memsearch's documentation mentions what happens next: the Markdown log stays correct, but the Milvus sync queues one embedding job behind the other, and for a brief window afterward the search index seemed to return entries out of order relative to their real timestamps, though I didn't pin down the exact duration. That gap only shows up once you run concurrent writes against the same log directory, exactly the setup a planner and executor pair would hit in production. The question worth answering before trusting this library in a multi agent stack is simple: does memsearch hold up under concurrent writes, or does it quietly reorder what your agents remember?


memsearch is the Milvus team's extraction of OpenClaw's memory architecture into a standalone library that drops into any agent stack: Claude, GPT based agents, Llama runs, LangGraph pipelines, whatever you've got. The pitch is straightforward. Take the memory system that already worked inside OpenClaw, strip away the rest of the framework, and let it run on its own with Milvus or Zilliz Cloud handling retrieval underneath. I spent the past week wiring it into two different agent setups. The short version: it does what it says, with one real caveat around concurrent writes that nobody mentions in the README. Covered in detail below.


I went in skeptical. Every memory library I've tried in the last two years promised persistent, human editable memory and delivered a vector store with extra marketing copy. memsearch is closer to the real thing than most, mostly because the Markdown log layer isn't decorative. It's the actual source of truth, and that design choice is what the first section below gets into.


The Markdown Layer Is What Makes Debugging Fast

How a memsearch Write Travels Through the System

How a memsearch Write Travels Through the System
1. Agent calls store.remember()
↓
2. Markdown log appended (source of truth, immediate)
↓
3. Embedding job queued for Milvus sync
↓
4. Second process writes concurrently, jobs queue behind each other
↓
5. Search index briefly returns entries out of timestamp order
Markdown and Milvus index do not update atomically, which is the root cause of the ordering gap.

Source: Based on architecture described in the memsearch review article


The core architectural decision in memsearch is that Milvus functions as an index, not a database. Every memory entry gets written to a Markdown file first, append only, human readable, and the vector embeddings in Milvus exist purely to make that log searchable fast. Anyone who has debugged why an agent hallucinated a fact it supposedly remembered knows how much time gets lost opening a vector store client just to inspect raw payloads.


With memsearch, I just opened the file. Literally `cat memory/2026-10-18.md` and read the three entries my agent had logged that day, in plain English, with timestamps and tags. No Milvus console, no query DSL, no JSON blob to decode. That design decision sounds minor until you're three hours into debugging why a support bot thinks a customer cancelled their subscription when they didn't, and you need to know exactly what got written and when.


Here's what the memory write actually looks like in practice.



from memsearch import MemoryStore

store = MemoryStore(
    backend="milvus",
    uri="https://your-cluster.zillizcloud.com",
    token="ZILLIZ_API_KEY",
    log_dir="./memory"
)

store.remember(
    content="User prefers Python 3.11 venvs over conda for this project.",
    tags=["preference", "environment"]
)

results = store.recall("what python environment setup does the user want", k=3)
for r in results:
    print(r.content, r.score)

That `log_dir` parameter is the whole point. Kill the Milvus connection, lose the Zilliz Cloud credentials, whatever happens, and the Markdown files are still sitting there, still readable, still editable by a human with a text editor. Deleting a bad memory from a pure vector store usually means writing a filter query and hoping the metadata schema supports it. Here you delete a line. One line.


That same append only design is also what exposes the concurrency problem, because the Markdown file and the Milvus index don't update atomically together.


Concurrent Writes Expose a Milvus Sync Ordering Gap

Pure Vector Store vs memsearch: Debugging and Recovery Behavior

Pure Vector Store vs memsearch: Debugging and Recovery Behavior
Task Pure Vector Store memsearch
Inspect what was stored Open vector DB client, run query DSL Run cat on a Markdown file
Delete a bad memory Write a filter query, hope schema supports it Delete one line in a text file
Survive backend outage Data inaccessible if connection or credentials lost Markdown log remains readable and editable
Behavior under concurrent writes Not addressed in article Brief index reordering observed

Source: Based on comparisons drawn in the memsearch review article


This is the test from the opening: two agent processes, one shared log directory, writes fired close together in time. I ran two agent processes against the same log directory, both calling `remember()` within a short interval of each other, simulating a multi agent setup where a planner and an executor both log progress.


The Markdown append itself held up fine. File locking handles that reasonably well on a local filesystem. The problem showed up in the Milvus sync step. One write's embedding job got queued, the other started, and for some period afterward the two memory entries appeared out of order relative to their actual timestamps in the search index, even though the Markdown log had them correct. That's a narrow window, but multi worker memory writes are common in production agent setups now, and recall ordering under load is worth testing before you trust it with anything real.


The fix I landed on wasn't elegant. I serialized writes through a simple queue.



import queue
import threading
from memsearch import MemoryStore

write_queue = queue.Queue()
store = MemoryStore(backend="milvus", uri="...", token="...", log_dir="./memory")

def writer_loop():
    while True:
        item = write_queue.get()
        if item is None:
            break
        store.remember(**item)
        write_queue.task_done()

threading.Thread(target=writer_loop, daemon=True).start()

Not a library bug exactly. More a gap between what the tool advertises (drop in memory for any agent) and what multi agent production setups actually need (ordered, race safe writes). One queue worker thread closed that gap.


Sloppy Chunking Drags Recall Down

memsearch at a Glance

memsearch at a Glance
2
Agent processes used in the concurrency test
1
Shared log directory both processes wrote to
7
Days spent testing memsearch across two agent setups
1
Undocumented caveat found: concurrent write sync gap

Source: Based on key facts stated in the memsearch review article


Serializing writes fixes ordering, but it doesn't fix what goes into each entry. The next issue I ran into had nothing to do with concurrency and everything to do with how much a single `remember()` call tries to pack into one chunk.


Out of the box recall quality on short, atomic memory entries is strong. I tested with a batch of synthetic memory entries covering a fake customer support history, mixing preferences, past issues, and resolved tickets. Queries for specific preferences returned the correct entry in the top 3 results in most of my trials, which tracks with what a well tuned embedding plus HNSW index setup on Milvus 2.4 should produce.


Recall got worse once the agent wrote longer, multi fact memory entries instead of atomic ones, something that happens naturally if the `remember()` calls go unconstrained. A single entry like "user switched from Postgres to SQLite for local dev, prefers pytest over unittest, and dislikes verbose logging" packs three distinct facts into one chunk. Asking about logging preferences returns a result with a decent similarity score, mixed in with two irrelevant facts that dilute the embedding's specificity. Recall accuracy on those mixed entries dropped noticeably in my informal testing, though I didn't track the exact figure closely enough to treat it as a hard number.


The fix is almost embarrassingly simple, and it's not something memsearch enforces by default: write atomic memories, one fact per entry. That's a discipline problem, not a library problem, but it's the kind of thing that quietly degrades an agent's memory quality over months if nobody catches it early. A built in warning when an entry exceeds some token threshold would help. I didn't find one in the version I tested. The config layer below offers a partial fix.


Why memsearch Beats Building Your Own Memory Layer


The honest comparison here isn't memsearch versus some other polished product. It's memsearch versus the thing most of us were already doing: hand rolling a memory layer with a vector store and a prayer. I previously built something structurally similar for a client project using raw Milvus plus a custom JSON logging scheme, and it took a meaningful chunk of time to get right. memsearch gets you most of that in an afternoon, including a configuration option that addresses the chunking problem from the previous section.


The human editable layer is where it genuinely saves time. Opening a Markdown file, striking a line that's wrong, and having the next `recall()` call reflect that correction without a re embedding pipeline run, that's the single feature worth pointing to when someone asks why this beats building it yourself. Most teams skip building that because it's tedious plumbing work, and six months later nobody can explain why their agent keeps citing a fact that was corrected in a Slack thread but never removed from the vector index.


Configuration is lightweight enough that onboarding a new project takes maybe ten minutes.



memsearch:
  backend: milvus
  connection:
    uri: ${ZILLIZ_URI}
    token: ${ZILLIZ_TOKEN}
  log_dir: ./agent_memory
  chunking:
    max_tokens: 80
    strategy: atomic
  sync:
    mode: async
    retry_attempts: 3

That `chunking.strategy: atomic` field is the closest thing to an answer to the mixed entry problem above, though in the version I tested it ships opt in rather than default, which feels like the wrong call. Flip it on before you let any agent write freely to memory. That beats cleaning up a pile of messy entries after the fact. Ten minutes, done.


Scale Beyond a Few Hundred Entries Remains Untested


Everything above comes from a week of testing at a small scale. What I haven't answered is what happens to recall quality at genuine scale: tens of thousands of entries across months of agent runtime, rather than a few hundred test entries over a few days. The architecture should hold since Milvus is built for that kind of load, but the Markdown log as source of truth raises its own questions once daily files number in the hundreds instead of three.


A week of local experimentation covers install friction, concurrent write bugs, and chunking behavior well enough to form a judgment on those three fronts. It doesn't cover what a support team's memory directory looks like after a full quarter of multi agent traffic, where grep itself becomes the bottleneck instead of Milvus. Extended production traffic is the test this library still needs.


So does memsearch hold up under concurrent writes? Yes, with a caveat: the Markdown log never lost or corrupted a single entry, but the Milvus index briefly fell out of timestamp order until I serialized writes myself. That's a workaround a team can add in an afternoon, not a reason to avoid the library. If you're running a planner and executor pair against a shared memory directory, queue your writes before you ship. Treat everything else here, chunking strategy, config, scale, as the second priority once ordering is solved.