memsearch
A persistent, unified memory layer for all your AI agents (e.g. Claude Code, Codex), backed by Markdown and Milvus.
Loading plugin...
A persistent, unified memory layer for all your AI agents (e.g. Claude Code, Codex), backed by Markdown and Milvus.
PROJECT.md and USER.md notes current across sessions. See Advanced Memory Maintenance..md files โ human-readable, editable, version-controllable. Milvus is a "shadow index": a derived, rebuildable cachePick your platform, install the plugin, and you're done. Each plugin captures conversations automatically and provides semantic recall with zero configuration.
# Install
/plugin marketplace add zilliztech/memsearch
/plugin install memsearch
# Restart Claude Code to activate the plugin
After restarting, just chat with Claude Code as usual. The plugin captures every conversation turn automatically.
Verify it's working โ after a few conversations, check your memory files:
ls .memsearch/memory/ # you should see daily .md files
cat .memsearch/memory/$(date +%Y-%m-%d).md
Recall memories โ two ways to trigger:
/memory-recall what did we discuss about Redis?
Or just ask naturally โ Claude auto-invokes the skill when it senses the question needs history:
We discussed Redis caching before, what was the TTL we chose?
# Install
git clone --depth 1 https://github.com/zilliztech/memsearch.git
bash memsearch/plugins/codex/scripts/install.sh
codex --yolo # needed for ONNX model network access
After installing, chat as usual. Hooks capture and summarize each turn.
Verify it's working:
ls .memsearch/memory/
Recall memories โ use the skill:
$memory-recall what did we discuss about deployment?
# Install from ClawHub
openclaw plugins install --force clawhub:memsearch
openclaw config set plugins.entries.memsearch.hooks.allowConversationAccess true
openclaw config set plugins.entries.memsearch.hooks.allowPromptInjection true
openclaw gateway restart
After installing, chat in TUI as usual. The plugin captures each turn automatically.
Verify it's working โ memory files are stored in your agent's workspace:
# For the main agent:
ls ~/.openclaw/workspace/.memsearch/memory/
# For other agents (e.g. work):
ls ~/.openclaw/workspace-work/.memsearch/memory/
Recall memories โ two ways to trigger:
/memory-recall what was the batch size limit we set?
Or just ask naturally โ the LLM auto-invokes memory tools when it senses the question needs history:
We discussed batch size limits before, what did we decide?
// In ~/.config/opencode/opencode.json
{ "plugin": ["@zilliz/memsearch-opencode"] }
After installing, chat in TUI as usual. A background daemon captures conversations.
Verify it's working:
ls .memsearch/memory/ # daily .md files appear after a few conversations
Recall memories โ two ways to trigger:
/memory-recall what did we discuss about authentication?
Or just ask naturally โ the LLM auto-invokes memory tools when it senses the question needs history:
We discussed the authentication flow before, what was the approach?
๐ OpenCode Plugin docs
All plugins share the same memsearch backend. Configure once, works everywhere.
Defaults to ONNX bge-m3 โ runs locally on CPU, no API key, no cost. On first launch the model (~558 MB) is downloaded from HuggingFace Hub.
memsearch config set embedding.provider onnx # default โ local, free
memsearch config set embedding.provider openai # needs OPENAI_API_KEY
memsearch config set embedding.provider ollama # local, any model
All providers and models: Configuration โ Embedding Provider
Just change milvus_uri (and optionally milvus_token) to switch between deployment modes:
Milvus Lite (default) โ zero config, single file. Great for getting started:
# Works out of the box, no setup needed
memsearch config get milvus.uri # โ ~/.memsearch/milvus.db
โญ Zilliz Cloud (recommended) โ fully managed, free tier available โ sign up ๐:
memsearch config set milvus.uri "https://in03-xxx.api.gcp-us-west1.zillizcloud.com"
memsearch config set milvus.token "your-api-key"
You can sign up on Zilliz Cloud to get a free cluster and API key.

For multi-user or team environments with a dedicated Milvus instance. Requires Docker. See the official installation guide.
memsearch config set milvus.uri http://localhost:19530
๐ Full configuration guide: Configuration ยท Platform comparison
Each plugin keeps its native capture summarizer unless you override it explicitly:
memsearch config set plugins.codex.summarize.model gpt-5.1-codex-mini
memsearch config set plugins.opencode.summarize.model anthropic/claude-haiku
Advanced users can route plugin summarization through a memsearch-managed API provider:
memsearch config set llm.providers.openai.type openai
memsearch config set llm.providers.openai.model gpt-5-mini
memsearch config set llm.providers.openai.api_key env:OPENAI_API_KEY
memsearch config set plugins.codex.summarize.provider openai
Leave plugins.<platform>.summarize.provider empty or set it to native to preserve the default behavior. Plugin-specific summarize settings do not fall back to llm.model.
You can also disable automatic capture globally for a platform while keeping the plugin installed:
memsearch config set plugins.codex.summarize.enabled false
Your agent can keep two higher-level notes current in the background: PROJECT.md โ durable project state (active threads, decisions, risks, next steps) โ and USER.md โ your reusable preferences, working style, and recurring goals. They refresh after a session only when the journals changed and a minimum interval has passed, and they are off by default.
Turn them on by asking your agent โ "enable MemSearch's PROJECT.md and USER.md maintenance" โ and it configures them through the memory-config skill, which can also choose the model/provider, the interval, and custom prompts, or diagnose the current setup. Prefer editing files? The settings live under [plugins.<agent>.project_review] and [plugins.<agent>.user_profile] in your MemSearch config (both read .memsearch/memory and write .memsearch/PROJECT.md / .memsearch/USER.md by default).
If a background maintenance task seems silent, check .memsearch/.maintenance-state.json or ask the memory-config skill to inspect it; failed runs record last_error and retry on the next due run because failed input digests are not marked successful.
Beyond the episodic journals and the semantic PROJECT.md / USER.md notes, MemSearch grows a third memory layer โ procedural memory: your agent turns the workflows you repeat into reusable, installable skills. You drive it entirely through your agent, in natural language โ nothing to memorize:
/-command.Under the hood, candidates live in a git-tracked .memsearch/skill-candidates/ store โ diffable and revertible, and inert until you install one (that step is always yours). An optional background pass can also mine recurring workflows from your history on its own. Distilled skills follow the Agent Skills open standard, so one capture is portable across Claude Code, Codex, OpenCode, and others.
Turning it on is also just a sentence: ask your agent "enable MemSearch skill distillation" (or "make it more eager") and it configures things through the memory-config skill โ it's off by default. Prefer editing files? The same settings live under [plugins.<agent>.memory_to_skill] in your MemSearch config. Full guide: Skills from Memory.
Beyond ready-to-use plugins, memsearch provides a complete CLI and Python API for building memory into your own agents. Whether you're adding persistent context to a custom agent, building a memory-augmented RAG pipeline, or doing harness engineering โ the same core engine that powers the plugins is available as a library.
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๐งโ๐ป For Agent Users (Plugins) โ
โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโ โโโโโโโโ โ
โ โ Claude โ โ OpenClaw โ โ OpenCode โ โ Codex โ โ Your โ โ
โ โ Code โ โ Plugin โ โ Plugin โ โ Plugin โ โ App โ โ
โ โโโโโโฌโโโโโโ โโโโโโฌโโโโโโ โโโโโโฌโโโโโโ โโโโโฌโโโโโ โโโโฌโโโโ โ
โ โโโโโโโโโโโโโโโดโโโโโโโโโโโโโดโโโโโโโโโโโโดโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ ๐ ๏ธ For Agent Developers โ Build your own with โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ memsearch CLI / Python API โ โ
โ โ index ยท search ยท expand ยท watch ยท compact โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Core: Chunker โ Embedder โ Milvus โ โ
โ โ Hybrid Search (BM25 + Dense + RRF) โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ ๐ Markdown Files (Source of Truth) โ
โ memory/2026-03-27.md ยท memory/2026-03-26.md ยท ... โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Plugins sit on top of the CLI/API layer. The API handles indexing, searching, and Milvus sync. Markdown files are always the source of truth โ Milvus is a rebuildable shadow index. Everything below the plugin layer is what you use as an agent developer.
Capture โ after each conversation turn:
User asks question โ Agent responds โ Stop hook fires
โ
โโโโโโโโโโโโโโโโโโโโโโ
โผ
Parse last turn
โ
โผ
LLM summarizes (haiku)
"- User asked about X."
"- Claude did Y."
โ
โผ
Append to memory/2026-03-27.md
with <!-- session:UUID --> anchor
โ
โผ
memsearch index โ Milvus
Recall โ 3-layer progressive search:
User: "What did we discuss about batch size?"
โ
โผ
L1 memsearch search "batch size" โ ranked chunks
โ (need more?)
โผ
L2 memsearch expand <chunk_hash> โ full .md section
โ (need original?)
โผ
L3 parse-transcript <session.jsonl> โ raw dialogue
Plugins append โโโ .md files โโโ human editable
โ
โผ
memsearch watch (live watcher)
โ
detects file change
โ
โผ
re-chunk changed .md
โ
hash each chunk (SHA-256)
โ
โโโโโโโโโโโโโดโโโโโโโโโโโโ
โผ โผ
hash unchanged? hash is new/changed?
โ skip (no API call) โ embed โ upsert to Milvus
โ โ
โโโโโโโโโโโโโฌโโโโโโโโโโโโ
โผ
โโโโโโโโโโโโโโโโโโโโ
โ Milvus (shadow) โ
โ always in sync โ
โ rebuildable โ
โโโโโโโโโโโโโโโโโโโโ
# Install as a global CLI tool โ recommended when you mainly use the
# `memsearch` command or any of the agent plugins (Claude Code, Codex,
# OpenClaw, OpenCode), which all shell out to the CLI.
uv tool install memsearch # via uv
pipx install memsearch # via pipx
pip install memsearch # plain pip
# Install as a project dependency โ use this if you want to import
# `memsearch` from your own Python code (e.g. via the MemSearch class).
uv add memsearch # via uv, adds to pyproject.toml
pip install memsearch # into an activated venv
# As a CLI tool (recommended โ local ONNX, no API key)
uv tool install "memsearch[onnx]"
pipx install "memsearch[onnx]"
pip install "memsearch[onnx]"
# As a project dependency
uv add "memsearch[onnx]"
# Other options: [openai], [google], [voyage], [jina], [mistral], [ollama], [local], [all]
from memsearch import MemSearch
mem = MemSearch(paths=["./memory"])
await mem.index() # index markdown files
results = await mem.search("Redis config", top_k=3) # semantic search
scoped = await mem.search("pricing", top_k=3, source_prefix="./memory/product")
print(results[0]["content"], results[0]["score"]) # content + similarity
import asyncio
from datetime import date
from pathlib import Path
from openai import OpenAI
from memsearch import MemSearch
MEMORY_DIR = "./memory"
llm = OpenAI() # your LLM client
mem = MemSearch(paths=[MEMORY_DIR]) # memsearch handles the rest
def save_memory(content: str):
"""Append a note to today's memory log (OpenClaw-style daily markdown)."""
p = Path(MEMORY_DIR) / f"{date.today()}.md"
p.parent.mkdir(parents=True, exist_ok=True)
with open(p, "a") as f:
f.write(f"\n{content}\n")
async def agent_chat(user_input: str) -> str:
# 1. Recall โ search past memories for relevant context
memories = await mem.search(user_input, top_k=3)
context = "\n".join(f"- {m['content'][:200]}" for m in memories)
# 2. Think โ call LLM with memory context
resp = llm.chat.completions.create(
model="gpt-5-mini",
messages=[
{"role": "system", "content": f"You have these memories:\n{context}"},
{"role": "user", "content": user_input},
],
)
answer = resp.choices[0].message.content
# 3. Remember โ save this exchange and index it
save_memory(f"## {user_input}\n{answer}")
await mem.index()
return answer
async def main():
# Seed some knowledge
save_memory("## Team\n- Alice: frontend lead\n- Bob: backend lead")
save_memory("## Decision\nWe chose Redis for caching over Memcached.")
await mem.index() # or mem.watch() to auto-index in the background
# Agent can now recall those memories
print(await agent_chat("Who is our frontend lead?"))
print(await agent_chat("What caching solution did we pick?"))
asyncio.run(main())
pip install memsearch anthropic
import asyncio
from datetime import date
from pathlib import Path
from anthropic import Anthropic
from memsearch import MemSearch
MEMORY_DIR = "./memory"
llm = Anthropic()
mem = MemSearch(paths=[MEMORY_DIR])
def save_memory(content: str):
p = Path(MEMORY_DIR) / f"{date.today()}.md"
p.parent.mkdir(parents=True, exist_ok=True)
with open(p, "a") as f:
f.write(f"\n{content}\n")
async def agent_chat(user_input: str) -> str:
# 1. Recall
memories = await mem.search(user_input, top_k=3)
context = "\n".join(f"- {m['content'][:200]}" for m in memories)
# 2. Think โ call Claude with memory context
resp = llm.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system=f"You have these memories:\n{context}",
messages=[{"role": "user", "content": user_input}],
)
answer = resp.content[0].text
# 3. Remember
save_memory(f"## {user_input}\n{answer}")
await mem.index()
return answer
async def main():
save_memory("## Team\n- Alice: frontend lead\n- Bob: backend lead")
await mem.index()
print(await agent_chat("Who is our frontend lead?"))
asyncio.run(main())
pip install "memsearch[ollama]"
ollama pull nomic-embed-text # embedding model
ollama pull llama3.2 # chat model
import asyncio
from datetime import date
from pathlib import Path
from ollama import chat
from memsearch import MemSearch
MEMORY_DIR = "./memory"
mem = MemSearch(paths=[MEMORY_DIR], embedding_provider="ollama")
def save_memory(content: str):
p = Path(MEMORY_DIR) / f"{date.today()}.md"
p.parent.mkdir(parents=True, exist_ok=True)
with open(p, "a") as f:
f.write(f"\n{content}\n")
async def agent_chat(user_input: str) -> str:
# 1. Recall
memories = await mem.search(user_input, top_k=3)
context = "\n".join(f"- {m['content'][:200]}" for m in memories)
# 2. Think โ call Ollama locally
resp = chat(
model="llama3.2",
messages=[
{"role": "system", "content": f"You have these memories:\n{context}"},
{"role": "user", "content": user_input},
],
)
answer = resp.message.content
# 3. Remember
save_memory(f"## {user_input}\n{answer}")
await mem.index()
return answer
async def main():
save_memory("## Team\n- Alice: frontend lead\n- Bob: backend lead")
await mem.index()
print(await agent_chat("Who is our frontend lead?"))
asyncio.run(main())
๐ Full Python API reference: Python API docs
Setup:
memsearch config init # interactive setup wizard
memsearch config set embedding.provider onnx # switch embedding provider
memsearch config set milvus.uri http://localhost:19530 # switch Milvus backend
Index & Search:
memsearch index ./memory/ # index markdown files
memsearch index ./memory/ ./notes/ --force # re-embed everything
memsearch index . --ignore-file .gitignore # opt in to repository ignore rules
memsearch search "Redis caching" # hybrid search (BM25 + vector)
memsearch search "auth flow" --top-k 10 --json-output # JSON for scripting
memsearch expand <chunk_hash> # show full section around a chunk
Live Sync & Maintenance:
memsearch watch ./memory/ # live file watcher (auto-index on change)
memsearch compact # LLM-powered chunk summarization
memsearch stats # show indexed chunk count
memsearch reset --yes # drop all indexed data and rebuild
๐ Full CLI reference with all flags: CLI docs
Embedding and Milvus backend settings โ Configuration (all platforms)
Settings priority: Built-in defaults โ ~/.memsearch/config.toml โ .memsearch.toml โ CLI flags.
๐ Full config guide: Configuration
Bug reports, feature requests, and pull requests are welcome! See the Contributing Guide for development setup, testing, and plugin development instructions. For questions and discussions, join us on Discord.
.claude-plugin/
marketplace.json
.gitattributes
.github/
ISSUE_TEMPLATE/
bug_report.yml
config.yml
feature_request.yml
release-drafter.yml
workflows/
docs.yml
lint.yml
release-drafter.yml
release.yml
stale.yml
test.yml
.gitignore
.pre-commit-config.yaml
AGENT.md
assets/
logo-banner-alt.jpg
logo-banner.jpg
logo-icon.jpg
MemSearch.mp4
CLAUDE.md
CONTRIBUTING.md
docs/
architecture.md
assets/
logo-icon.jpg
cli.md
design-philosophy.md
faq.md
getting-started.md
home/
comparison.md
configuration.md
embedding-evaluation.md
for-developers.md
for-users.md
skills-from-memory.md
why.md
index.md
integrations.md
platforms/
claude-code/
how-it-works.md
index.md
installation.md
memory-recall.md
troubleshooting.md
codex/
how-it-works.md
index.md
installation.md
memory-recall.md
index.md
openclaw/
how-it-works.md
index.md
installation.md
memory-tools.md
opencode/
how-it-works.md
index.md
installation.md
memory-tools.md
python-api.md
stylesheets/
terminal.css
testfile
troubleshooting.md
evaluation/
README.md
LICENSE
MEMORY.md
mkdocs.yml
plugins/
_shared/
prompts/
memory_to_skill.txt
project_review.txt
summarize.txt
user_profile.txt
scripts/
maintenance-runner.py
claude-code/
.claude-plugin/
plugin.json
hooks/
common.sh
hooks.json
parse-transcript.sh
session-end.sh
session-start.sh
stop.sh
user-prompt-submit.sh
prompts/
memory_to_skill.txt
project_review.txt
summarize.txt
user_profile.txt
README.md
scripts/
derive-collection.sh
maintenance-runner.py
skills/
memory-config/
SKILL.md
memory-recall/
SKILL.md
memory-to-skill/
SKILL.md
transcript.py
codex/
hooks/
common.sh
session-start.sh
stop.sh
user-prompt-submit.sh
prompts/
memory_to_skill.txt
project_review.txt
summarize.txt
user_profile.txt
README.md
scripts/
derive-collection.sh
install.sh
maintenance-runner.py
parse-rollout.sh
skills/
memory-config/
SKILL.md
memory-recall/
SKILL.md
memory-to-skill/
SKILL.md
openclaw/
index.js
index.ts
install.sh
openclaw.plugin.json
package.json
prompts/
memory_to_skill.txt
project_review.txt
summarize.txt
user_profile.txt
README.md
scripts/
derive-collection.sh
maintenance-runner.py
parse-transcript.sh
skills/
memory-config/
SKILL.md
memory-recall/
SKILL.md
memory-to-skill/
SKILL.md
opencode/
.gitignore
context.ts
index.test.ts
index.ts
install.sh
package.json
prompts/
memory_to_skill.txt
project_review.txt
summarize.txt
user_profile.txt
README.md
scripts/
capture-daemon.py
derive-collection.sh
maintenance-runner.py
opencode_turns.py
parse-transcript.py
skills/
memory-config/
SKILL.md
memory-recall/
SKILL.md
memory-to-skill/
SKILL.md
pyproject.toml
README.md
scripts/
sync-prompts.sh
src/
memsearch/
__init__.py
__main__.py
chunker.py
cli.py
compact.py
config.py
core.py
embeddings/
__init__.py
google.py
jina.py
local.py
mistral.py
ollama.py
onnx.py
openai.py
utils.py
voyage.py
index_report.py
index_state.py
io.py
maintenance.py
prompts/
__init__.py
memory_to_skill.txt
project_review.txt
user_profile.txt
reranker.py
scanner.py
skills.py
store.py
transcript.py
watcher.py
tests/
__init__.py
test_chunk_id_format.py
test_chunker.py
test_claude_hooks.py
test_claude_parse_transcript.py
test_cli_config_helpers.py
test_cli_error_handling.py
test_cli_help.py
test_codex_parse_rollout.py
test_codex_stop_hook_utf8.py
test_compact_cli.py
test_compact.py
test_config.py
test_core_encoding.py
test_core.py
test_embed_batching.py
test_embeddings_google.py
test_embeddings_onnx_inputs.py
test_embeddings_openai.py
test_index_cleanup.py
test_index_state.py
test_maintenance_runner.py
test_maintenance.py
test_opencode_parse_transcript.py
test_opencode_turns.py
test_scanner.py
test_skills.py
test_store.py
test_transcript_parser.py
test_transcript.py
test_watcher.py
uv.lockยฉ 2026 Flowy ยท Free and open source
Built for Claude Code ยท Not affiliated with Anthropic