Semantic memory search for markdown knowledge bases
Project description
ย
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'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.mdfiles - โก 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 โ a drop-in example of agent memory built on memsearch
๐ฆ Installation
pip install memsearch
Optional embedding providers
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
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
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
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-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
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())
๐ฅ๏ธ CLI Usage
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
๐ 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 โ 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.
# 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
โ๏ธ Configuration
Settings are resolved in priority order (lowest โ highest):
- 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
๐ Embedding Providers
| Provider | Install | Default Model |
|---|---|---|
| OpenAI | memsearch (included) |
text-embedding-3-small |
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
๐๏ธ 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
๐ Links
- Documentation โ Getting Started, CLI Reference, Architecture
- Claude Code Plugin โ hook details, progressive disclosure, comparison with claude-mem
- OpenClaw โ the memory architecture that inspired memsearch
- Milvus โ the vector database powering memsearch
- Changelog โ release history
Contributing
Bug reports, feature requests, and pull requests are welcome on GitHub. For questions and discussions, join us on Discord.
๐ License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file memsearch-0.1.7.tar.gz.
File metadata
- Download URL: memsearch-0.1.7.tar.gz
- Upload date:
- Size: 2.8 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b5a8a82b01ff12e667128cd02eaf297d169c1872b0e0e8bfd22e20492bf6920e
|
|
| MD5 |
1258fb169887b7bf58cd8b2f3d78e585
|
|
| BLAKE2b-256 |
cd4a25b1ecffd943caa68ad40c20ee3df78dd631e034dbb2b0ff69290a882c72
|
Provenance
The following attestation bundles were made for memsearch-0.1.7.tar.gz:
Publisher:
release.yml on zilliztech/memsearch
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
memsearch-0.1.7.tar.gz -
Subject digest:
b5a8a82b01ff12e667128cd02eaf297d169c1872b0e0e8bfd22e20492bf6920e - Sigstore transparency entry: 947978552
- Sigstore integration time:
-
Permalink:
zilliztech/memsearch@ee7a39665975c5e046f1085c101d6e3f0fdea601 -
Branch / Tag:
refs/tags/v0.1.7 - Owner: https://github.com/zilliztech
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ee7a39665975c5e046f1085c101d6e3f0fdea601 -
Trigger Event:
push
-
Statement type:
File details
Details for the file memsearch-0.1.7-py3-none-any.whl.
File metadata
- Download URL: memsearch-0.1.7-py3-none-any.whl
- Upload date:
- Size: 34.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
faa41ecfe5ca9e1a242d9e6a22f37de1f48f6f3099dc4acf59412d12f6c552fe
|
|
| MD5 |
cf015cda86d70d78f29084bfea076016
|
|
| BLAKE2b-256 |
2137115b3c91fd23f20afb20cd9292c748fbdbdad18b3719eaab3051fcec755b
|
Provenance
The following attestation bundles were made for memsearch-0.1.7-py3-none-any.whl:
Publisher:
release.yml on zilliztech/memsearch
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
memsearch-0.1.7-py3-none-any.whl -
Subject digest:
faa41ecfe5ca9e1a242d9e6a22f37de1f48f6f3099dc4acf59412d12f6c552fe - Sigstore transparency entry: 947978608
- Sigstore integration time:
-
Permalink:
zilliztech/memsearch@ee7a39665975c5e046f1085c101d6e3f0fdea601 -
Branch / Tag:
refs/tags/v0.1.7 - Owner: https://github.com/zilliztech
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ee7a39665975c5e046f1085c101d6e3f0fdea601 -
Trigger Event:
push
-
Statement type: