https://github.com/zilliztech/memsearch
A Markdown-first memory system, a standalone library for any AI agent. Inspired by OpenClaw.
https://github.com/zilliztech/memsearch
agent agent-memory claude-code claude-code-plugin clawdbot embeddings memory milvus openclaw progressive-disclosure rag semantic-search
Last synced: 1 day ago
JSON representation
A Markdown-first memory system, a standalone library for any AI agent. Inspired by OpenClaw.
- Host: GitHub
- URL: https://github.com/zilliztech/memsearch
- Owner: zilliztech
- License: mit
- Created: 2026-02-09T02:29:16.000Z (7 days ago)
- Default Branch: main
- Last Pushed: 2026-02-12T11:34:41.000Z (4 days ago)
- Last Synced: 2026-02-12T16:39:29.932Z (4 days ago)
- Topics: agent, agent-memory, claude-code, claude-code-plugin, clawdbot, embeddings, memory, milvus, openclaw, progressive-disclosure, rag, semantic-search
- Language: Python
- Homepage: https://zilliztech.github.io/memsearch/
- Size: 24.2 MB
- Stars: 127
- Watchers: 3
- Forks: 13
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Β
memsearch
OpenClaw's memory, everywhere.
https://github.com/user-attachments/assets/31de76cc-81a8-4462-a47d-bd9c394d33e3
> π‘ Give your AI agents persistent memory in a few lines of code. Write memories as markdown, search them semantically. Inspired by [OpenClaw](https://github.com/openclaw/openclaw)'s markdown-first memory architecture. Pluggable into any agent framework.
### β¨ Why memsearch?
- π **Markdown is the source of truth** β human-readable, `git`-friendly, zero vendor lock-in. Your memories are just `.md` files
- β‘ **Smart dedup** β SHA-256 content hashing means unchanged content is never re-embedded
- π **Live sync** β File watcher auto-indexes changes to the vector DB, deletes stale chunks when files are removed
- π§© **[Ready-made Claude Code plugin](ccplugin/README.md)** β a drop-in example of agent memory built on memsearch
## π¦ Installation
```bash
pip install memsearch
```
Optional embedding providers
```bash
pip install "memsearch[google]" # Google Gemini
pip install "memsearch[voyage]" # Voyage AI
pip install "memsearch[ollama]" # Ollama (local)
pip install "memsearch[local]" # sentence-transformers (local, no API key)
pip install "memsearch[all]" # Everything
```
## π Python API β Give Your Agent Memory
```python
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
print(results[0]["content"], results[0]["score"]) # content + similarity
```
π Full example β agent with memory (OpenAI) β click to expand
```python
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-4o-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())
```
π Anthropic Claude example β click to expand
```bash
pip install memsearch anthropic
```
```python
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-5-20250929",
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())
```
π¦ Ollama (fully local, no API key) β click to expand
```bash
pip install "memsearch[ollama]"
ollama pull nomic-embed-text # embedding model
ollama pull llama3.2 # chat model
```
```python
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())
```
## π₯οΈ CLI Usage
```bash
memsearch index ./memory/ # index markdown files
memsearch search "how to configure Redis caching" # semantic search
memsearch watch ./memory/ # auto-index on file changes
memsearch compact # LLM-powered memory summarization
memsearch config init # interactive config wizard
memsearch stats # show index statistics
```
> π Full command reference with all flags and examples β [CLI Reference](https://zilliztech.github.io/memsearch/cli/)
## π How It Works
**Markdown is the source of truth** β the vector store is just a derived index, rebuildable anytime.
```
ββββ Search ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β "how to configure Redis?" β
β β β
β βΌ β
β ββββββββββββ βββββββββββββββββββ ββββββββββββββββββββ β
β β Embed ββββββΆβ Cosine similarityββββββΆβ Top-K results β β
β β query β β (Milvus) β β with source info β β
β ββββββββββββ βββββββββββββββββββ ββββββββββββββββββββ β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββ Ingest ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β MEMORY.md β
β memory/2026-02-09.md ββββββββββββ ββββββββββββββββββ β
β memory/2026-02-08.md ββββΆβ Chunker ββββββΆβ Dedup β β
β β(heading, β β(chunk_hash PK) β β
β βparagraph)β βββββββββ¬βββββββββ β
β ββββββββββββ β β
β new chunks only β
β βΌ β
β ββββββββββββββββ β
β β Embed & β β
β β Milvus upsertβ β
β ββββββββββββββββ β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββ Watch βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β File watcher (1500ms debounce) βββΆ auto re-index / delete stale β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββ Compact ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Retrieve chunks βββΆ LLM summarize βββΆ write memory/YYYY-MM-DD.md β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
π The entire pipeline runs locally by default β your data never leaves your machine unless you choose a remote backend or a cloud embedding provider.
## π§© Claude Code Plugin
memsearch ships with a **[Claude Code plugin](ccplugin/README.md)** β a real-world example of agent memory in action. It gives Claude **automatic persistent memory** across sessions: every session is summarized to markdown, every prompt triggers a semantic search, and a background watcher keeps the index in sync. No commands to learn, no manual saving β just install and go.
```bash
# 1. Install the memsearch CLI
pip install memsearch
# 2. Set your embedding API key (OpenAI is the default provider)
export OPENAI_API_KEY="sk-..."
# 3. In Claude Code, add the marketplace and install the plugin
/plugin marketplace add zilliztech/memsearch
/plugin install memsearch
# 4. Restart Claude Code for the plugin to take effect, then start chatting!
claude
```
> π Architecture, hook details, and development mode β [Claude Code Plugin docs](https://zilliztech.github.io/memsearch/claude-plugin/)
## βοΈ Configuration
Settings are resolved in priority order (lowest β highest):
1. **Built-in defaults** β 2. **Global** `~/.memsearch/config.toml` β 3. **Project** `.memsearch.toml` β 4. **CLI flags**
API keys for embedding/LLM providers are read from standard environment variables (`OPENAI_API_KEY`, `GOOGLE_API_KEY`, `VOYAGE_API_KEY`, `ANTHROPIC_API_KEY`, etc.).
> π Config wizard, TOML examples, and all settings β [Getting Started β Configuration](https://zilliztech.github.io/memsearch/getting-started/#configuration)
## π Embedding Providers
| Provider | Install | Default Model |
|----------|---------|---------------|
| OpenAI | `memsearch` (included) | `text-embedding-3-small` |
| Google | `memsearch[google]` | `gemini-embedding-001` |
| Voyage | `memsearch[voyage]` | `voyage-3-lite` |
| Ollama | `memsearch[ollama]` | `nomic-embed-text` |
| Local | `memsearch[local]` | `all-MiniLM-L6-v2` |
> π Provider setup and env vars β [CLI Reference β Embedding Provider Reference](https://zilliztech.github.io/memsearch/cli/#embedding-provider-reference)
## ποΈ Milvus Backend
memsearch supports three deployment modes β just change `milvus_uri`:
| Mode | `milvus_uri` | Best for |
|------|-------------|----------|
| **Milvus Lite** (default) | `~/.memsearch/milvus.db` | Personal use, dev β zero config |
| **Milvus Server** | `http://localhost:19530` | Multi-agent, team environments |
| **Zilliz Cloud** | `https://in03-xxx.api.gcp-us-west1.zillizcloud.com` | Production, fully managed |
> π Code examples and setup details β [Getting Started β Milvus Backends](https://zilliztech.github.io/memsearch/getting-started/#milvus-backends)
## π Links
- [Documentation](https://zilliztech.github.io/memsearch/) β Getting Started, CLI Reference, Architecture
- [Claude Code Plugin](ccplugin/README.md) β hook details, progressive disclosure, comparison with claude-mem
- [OpenClaw](https://github.com/openclaw/openclaw) β the memory architecture that inspired memsearch
- [Milvus](https://milvus.io/) β the vector database powering memsearch
- [Changelog](https://github.com/zilliztech/memsearch/releases) β release history
## Contributing
Bug reports, feature requests, and pull requests are welcome on [GitHub](https://github.com/zilliztech/memsearch). For questions and discussions, join us on [Discord](https://discord.com/invite/FG6hMJStWu).
## π License
[MIT](LICENSE)