Memory Operating System for LLM Agents — persistent, smart, local-first memory
Project description
MemOS — Memory Operating System for AI Agents
Persistent, structured, self-maintaining memory for any LLM agent. Local-first. Framework-agnostic. Connects via MCP to Claude Code, OpenClaw, Cursor, or any HTTP client.
What's new in v2.3.10
- Lean Docker image — the official image omits the optional local embedding stack that pulled Torch/CUDA wheels into runtime builds
- Faster Docker CI — dependency wheels are cached before project source is copied, PRs run a real smoke image, and Buildx cache uses a trusted scope
- Smaller runtime context —
.dockerignorekeeps repository-only files out of Docker builds while preserving the non-root/data/.memosruntime contract - Validation — lint, Python 3.11/3.12/3.13 tests, and Docker build checks are green
See CHANGELOG.md for full history.
Installation
pip install memos-os
With local semantic recall (no external services):
pip install "memos-os[local]" # sentence-transformers, backend="local"
With vector backend (recommended for production):
pip install "memos-os[chroma]" # ChromaDB + Ollama embeddings
pip install "memos-os[qdrant]" # Qdrant
pip install "memos-os[chroma,qdrant,pinecone,parquet,server]" # full stack
Quick start
# Store a memory
memos learn "FastAPI is better than Flask for async workloads" --tags python,backend
# Search semantically
memos recall "which web framework should I use?"
# Start the REST API + dashboard
memos serve --port 8100
# → http://localhost:8100/dashboard
Golden path
The full lifecycle from storing a memory to maintaining it over time.
from memos import MemOS
from memos.context import ContextStack
from memos.kg_bridge import KGBridge
mem = MemOS(backend="chroma", embed_host="http://localhost:11434")
cs = ContextStack(mem)
bridge = KGBridge(mem)
# 1. Learn — store memories with tags and importance
mem.learn("User prefers dark mode in all apps", tags=["preference", "ui"], importance=0.8)
mem.learn("Deploy with Docker on ARM64 homelab", tags=["devops", "docker"], importance=0.6)
mem.learn("Alice leads the backend team", tags=["team", "people"], importance=0.7)
# 2. Recall — semantic search
results = mem.recall("who handles the server side?", top=3)
for r in results:
print(f"[{r.score:.2f}] {r.item.content}")
# [0.91] Alice leads the backend team (tags: team, people)
# 3. context_for — targeted context for a specific LLM call
ctx = cs.context_for("how should I deploy this app?", max_chars=1500, top=5)
# Returns a string with identity + relevant memories:
# === RELEVANT MEMORIES (2 results for: 'how should I deploy this app?') ===
# [0.87] Deploy with Docker on ARM64 homelab (tags: devops, docker)
# 4. wake_up — inject at session start
prompt_fragment = cs.wake_up(max_chars=2000, l1_top=15, include_stats=True)
# Returns L0 identity + L1 top-importance memories as a string
# ready to paste into a system prompt
# 5. Reinforce and decay — keep memories healthy over time
# Reinforce useful memories via the public CLI / MCP surface
# and prune stale ones via the public maintenance API.
preview = mem.prune(threshold=0.1, dry_run=True)
print(f"{len(preview)} memories would be pruned")
# When ready: apply the cleanup
removed = mem.prune(threshold=0.1)
print(f"Pruned {len(removed)} stale memories")
Python SDK
from memos import MemOS
# In-memory (zero dependencies, great for testing)
mem = MemOS()
# JSON persistence
mem = MemOS(backend="json", persist_path="~/.memos/store.json")
# Local-first semantic recall, no Ollama/Chroma required
mem = MemOS(backend="local", persist_path="~/.memos/store.json")
# ChromaDB with local Ollama embeddings
mem = MemOS(backend="chroma", embed_host="http://localhost:11434")
# Qdrant
mem = MemOS(backend="qdrant", qdrant_path="/data/memos")
# Store
mem.learn("User prefers dark mode", tags=["preference", "ui"], importance=0.8)
# Recall
results = mem.recall("what does the user like?", top=5)
for r in results:
print(f"[{r.score:.2f}] {r.item.content}")
# Forget
mem.forget("memory-id") # by id
mem.delete_tag("old-project") # remove this tag from all memories
mem.forget_tag("old-project") # delete all memories carrying this tag
mem.prune(threshold=0.2) # decay-based cleanup
# Stats
s = mem.stats()
# MemoryStats(total_memories=142, avg_relevance=0.71, decay_candidates=8)
Which recall API should I use?
| Function | Best for | Returns | When NOT to use |
|---|---|---|---|
mem.recall() |
General search, browsing results | list[RecallResult] with scores |
You need a ready-made prompt string |
memory_search (MCP) |
Same as recall(), but over MCP |
JSON via MCP protocol | You're using the Python SDK directly |
context_for() |
Augmenting a single LLM call | str (identity + top results) |
You need structured data to process |
recall_enriched() |
Answers needing entity context | dict with memories + KG facts |
No KG data exists or entity resolution isn't needed |
from memos.context import ContextStack
from memos.kg_bridge import KGBridge
cs = ContextStack(mem)
bridge = KGBridge(mem)
# recall() — structured results you iterate over
results = mem.recall("docker deployment", top=5)
for r in results:
print(r.item.content, r.score)
# context_for() — one string, ready for a system prompt
ctx = cs.context_for("docker deployment", max_chars=1000, top=5)
# recall_enriched() — memories + knowledge graph facts in one dict
enriched = bridge.recall_enriched("who is Alice?", top=5, min_score=0.3)
print(enriched["facts"]) # KG triples about Alice
print(enriched["memory_count"])
MCP — connect any agent
MemOS exposes a universal MCP endpoint. Any agent that speaks MCP can use it without any code changes.
HTTP (recommended)
Claude Code — add to ~/.claude.json:
{
"mcpServers": {
"memos": { "type": "http", "url": "http://localhost:8100/mcp" }
}
}
OpenClaw — add to ~/.openclaw/openclaw.json:
{
"mcp": {
"servers": {
"memos": { "type": "http", "url": "http://localhost:8100/mcp" }
}
}
}
Any MCP client — POST http://localhost:8100/mcp with JSON-RPC 2.0 body.
Discovery: GET http://localhost:8100/.well-known/mcp.json
Stdio (Claude Code local)
{
"mcpServers": {
"memos": { "command": "memos", "args": ["mcp-stdio"] }
}
}
Or run standalone: memos mcp-serve --port 8200
Available MCP tools
| Tool | Description |
|---|---|
memory_search |
Semantic search — query, top_k, tags |
memory_save |
Store a memory — content, tags, importance |
memory_forget |
Delete by id or tag |
memory_stats |
Counts, avg importance, decay candidates |
memory_wake_up |
Identity + top memories ready to inject at session start |
memory_context_for |
Context optimised for a specific query |
memory_decay |
Run decay cycle (dry-run by default) |
memory_reinforce |
Boost a memory's importance score |
kg_add_fact |
Add a temporal triple to the Knowledge Graph |
kg_query_entity |
All active facts for an entity |
kg_timeline |
Chronological fact history for an entity |
memory_recall_enriched |
Memories + KG facts in one call |
REST API
Start the server: memos serve --port 8100
Interactive docs: http://localhost:8100/docs
POST /api/v1/learn Store a memory
POST /api/v1/learn/batch Bulk store
POST /api/v1/recall Semantic search
GET /api/v1/recall/stream SSE streaming recall
GET /api/v1/search Keyword search
GET /api/v1/stats Memory statistics
GET /api/v1/tags List all tags
POST /api/v1/tags/delete Delete tag from all memories (body: {"tag": "..."})
DELETE /api/v1/memory/{id} Delete a memory
POST /api/v1/prune Decay-based cleanup
GET /api/v1/graph Knowledge graph (nodes + edges for D3.js)
GET /api/v1/export/parquet Download .parquet backup
POST /mcp MCP JSON-RPC endpoint
GET /.well-known/mcp.json MCP discovery
GET /dashboard Second Brain UI
GET /health Minimal liveness check
GET /api/v1/health Full health check with uptime and auth state
Configuration
All options can be set via environment variables:
MEMOS_BACKEND=chroma # memory | json | chroma | qdrant | pinecone
MEMOS_PERSIST_PATH=~/.memos/ # path for json/sqlite storage
MEMOS_CACHE_PATH=~/.memos/embeddings.db # path for local embedding cache
# ChromaDB
MEMOS_CHROMA_URL=http://chroma:8000
MEMOS_EMBED_HOST=http://localhost:11434 # Ollama — bypasses server-side ONNX
MEMOS_EMBED_MODEL=nomic-embed-text
# Qdrant
MEMOS_QDRANT_HOST=localhost
MEMOS_QDRANT_PORT=6333
# Pinecone
MEMOS_PINECONE_API_KEY=***
MEMOS_PINECONE_INDEX_NAME=agent-memories
Docker
Single container (local backend, no dependencies):
docker run -p 8100:8000 \
-e MEMOS_BACKEND=local \
-v memos-data:/data/.memos \
ghcr.io/mars375/memos:latest
The official Docker image keeps the runtime lean by omitting the optional memos-os[local] embedding stack, which pulls in large ML dependencies such as Torch. The local Docker example above uses JSON-backed local storage; for semantic embeddings in containers, point MemOS at an external Ollama/Chroma setup or build a custom image with the local extra.
Full stack with ChromaDB + Ollama embeddings:
git clone https://github.com/Mars375/memos
cd memos
docker run -p 8100:8000 \
-e MEMOS_BACKEND=chroma \
-e MEMOS_CHROMA_URL=http://host.docker.internal:8000 \
-e MEMOS_EMBED_HOST=http://host.docker.internal:11434 \
--add-host=host.docker.internal:host-gateway \
-v memos-data:/data/.memos \
ghcr.io/mars375/memos:latest
The container runs as a non-root memos user. Mount persistent data at /data/.memos so the runtime user can write stores, caches, and generated sidecar files.
If you want MemOS plus ChromaDB/Qdrant together, use your own compose/orchestrator setup — the repository no longer ships a root docker-compose.yml.
Import conversations
Mine your existing conversations into MemOS:
# Auto-detect format
memos mine conversations.json
# Supported formats
memos mine export.json --format claude # Claude Projects export
memos mine conversations.json --format chatgpt # ChatGPT export
memos mine messages.json --format discord
memos mine result.json --format telegram # Telegram Desktop export
memos mine channel.jsonl --format slack
memos mine ~/.openclaw/workspace-labs/ --format openclaw
# Options
memos mine ~/notes/ --dry-run --tags project-x --chunk-size 600
Python API:
from memos.ingest.miner import Miner
miner = Miner(mem, chunk_size=800, chunk_overlap=100)
result = miner.mine_auto("conversations/") # auto-detect
# MineResult(imported=127, dupes=12, cached=0, empty=3, errors=0)
Knowledge Graph
Store and query temporal facts between entities:
memos kg-add "Alice" "works-at" "Acme Corp" --from 2024-01-01
memos kg-query Alice
memos kg-path Alice Carol --max-hops 3
memos kg-neighbors Alice --depth 2
memos kg-timeline Alice
from memos.knowledge_graph import KnowledgeGraph
kg = KnowledgeGraph()
kg.add_fact("Alice", "works-at", "Acme Corp", valid_from="2024-01-01")
facts = kg.query("Alice")
paths = kg.find_paths("Alice", "Carol", max_hops=3)
Living Wiki
Compile memories into entity-based markdown pages with backlinks:
memos wiki-living update # scan memories, create/update entity pages
memos wiki-living read Alice # print Alice's page
memos wiki-living search "python" # search across all pages
memos wiki-living lint # find orphans, contradictions, empty pages
Memory decay
Memories age automatically. Important ones persist; stale ones fade.
memos decay # preview what would decay (dry-run by default)
memos decay --apply # apply decay
memos prune --threshold 0.1 # delete memories below importance threshold
Versioning and time-travel
Every write is versioned. Query the past, diff changes, roll back.
memos history <memory-id>
memos diff <memory-id> --latest
memos rollback <memory-id> --version 1 --yes
memos recall-at "user preferences" --at 2d # as of 2 days ago
memos snapshot-at 1w # all memories 1 week ago
Multi-namespace (multi-agent)
Each agent gets its own isolated namespace in the Python API:
from memos import MemOS
alice = MemOS()
alice.namespace = "agent-alice"
alice.learn("Alice's memory")
bob = MemOS()
bob.namespace = "agent-bob"
bob.learn("Bob's memory")
alice.recall("what do I know?")
Development
git clone https://github.com/Mars375/memos
cd memos
pip install -e ".[dev]" # includes pyarrow, so parquet tests run out of the box
# Lint
ruff check src/ tests/
ruff format src/ tests/
# Tests (Python 3.11 / 3.12 / 3.13)
pytest -q --tb=short # ~2400 tests
pytest tests/test_core.py # specific module
Architecture
MemOS is built around three core layers plus focused facade mixins on the main MemOS class:
- Capture — Mine conversations and events into structured memory units via the CLI, SDK, or MCP.
- Engine — Storage, recall, decay, reinforcement, versioning, and knowledge graph. Pluggable backends (in-memory, JSON, ChromaDB, Qdrant, Pinecone).
- Knowledge Surface — Living wiki, graph view, and context packs (
wake_up,context_for,recall_enriched) that serve the right context at the right time.
Recent cleanup extracted dedicated FeedbackFacade, IOFacade, MaintenanceFacade, SharingFacade, and VersioningFacade mixins so core.py stays focused on the CRUD/orchestration nucleus.
See ROADMAP.md for planned features and PRD.md for product requirements.
License
MIT — Mars375
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 memos_os-2.3.10.tar.gz.
File metadata
- Download URL: memos_os-2.3.10.tar.gz
- Upload date:
- Size: 489.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
23326a92ee8ef61d2019055c16e827f56227445a7ed28561dc15f2dd0ba252ca
|
|
| MD5 |
ec1b119c397ebfe7c791ba22f2306943
|
|
| BLAKE2b-256 |
8f3fe3f80333c82e7770386f09a263ae99203dee11c94deda1968baa3e5476ba
|
Provenance
The following attestation bundles were made for memos_os-2.3.10.tar.gz:
Publisher:
publish.yml on Mars375/memos
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
memos_os-2.3.10.tar.gz -
Subject digest:
23326a92ee8ef61d2019055c16e827f56227445a7ed28561dc15f2dd0ba252ca - Sigstore transparency entry: 1408673625
- Sigstore integration time:
-
Permalink:
Mars375/memos@7f5c0cfd81fc277a2933f2761f519c0ed4583e02 -
Branch / Tag:
refs/tags/v2.3.10 - Owner: https://github.com/Mars375
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7f5c0cfd81fc277a2933f2761f519c0ed4583e02 -
Trigger Event:
release
-
Statement type:
File details
Details for the file memos_os-2.3.10-py3-none-any.whl.
File metadata
- Download URL: memos_os-2.3.10-py3-none-any.whl
- Upload date:
- Size: 383.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9f6e8b1d15ee0fa6afc0d633ed123da2856d8be94071d395540812f147ccd0e3
|
|
| MD5 |
d967263ce594fb9fe6d147025a4625c1
|
|
| BLAKE2b-256 |
dd93d6b3b4ddecc5982bad5bbc8f26e7ac13688ae93cc33e1d203ff508e4855f
|
Provenance
The following attestation bundles were made for memos_os-2.3.10-py3-none-any.whl:
Publisher:
publish.yml on Mars375/memos
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
memos_os-2.3.10-py3-none-any.whl -
Subject digest:
9f6e8b1d15ee0fa6afc0d633ed123da2856d8be94071d395540812f147ccd0e3 - Sigstore transparency entry: 1408673723
- Sigstore integration time:
-
Permalink:
Mars375/memos@7f5c0cfd81fc277a2933f2761f519c0ed4583e02 -
Branch / Tag:
refs/tags/v2.3.10 - Owner: https://github.com/Mars375
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7f5c0cfd81fc277a2933f2761f519c0ed4583e02 -
Trigger Event:
release
-
Statement type: