memio
Unified memory gateway for AI agents. One interface, multiple memory providers.
memio lets you swap between memory backends (Mem0, Zep, Chroma, Letta, Qdrant, Supermemory) without changing your application code. Define what memory capabilities you need — facts, conversation history, documents, knowledge graphs — and plug in any supported provider.
Features
- Protocol-based architecture — providers implement Python protocols, so you can mix and match or bring your own
- Async-first — all operations are
async/await - Zero production dependencies — install only the providers you need
- Composable — use Mem0 for facts, Zep for history, and Chroma for documents in the same client
- Multi-tenant — scope data by
user_idoragent_id - Consistent error handling — all provider errors wrapped in
ProviderErrorwith context
Install
pip install memio
Install with providers:
pip install memio[mem0] # Mem0 provider
pip install memio[zep] # Zep provider
pip install memio[chroma] # Chroma provider
pip install memio[letta] # Letta provider
pip install memio[qdrant] # Qdrant provider
pip install memio[supermemory] # Supermemory provider
pip install memio[all] # All providers
pip install memio[server] # REST API server
Quick start
from memio import Memio
from memio.providers.mem0 import Mem0FactAdapter
from memio.providers.zep import ZepHistoryAdapter
from memio.providers.chroma import ChromaDocumentAdapter
import chromadb
client = Memio(
facts=Mem0FactAdapter(api_key="your-mem0-key"),
history=ZepHistoryAdapter(api_key="your-zep-key"),
documents=ChromaDocumentAdapter(
client=chromadb.EphemeralClient(),
collection_name="my-docs",
),
)
# Store and retrieve facts
fact = await client.facts.add(content="likes coffee", user_id="alice")
results = await client.facts.search(query="coffee", user_id="alice")
# Manage conversation history
from memio import Message
await client.history.add(
session_id="session-1",
user_id="alice",
messages=[
Message(role="user", content="hello"),
Message(role="assistant", content="hi there"),
],
)
messages = await client.history.get(session_id="session-1")
# Store and search documents
doc = await client.documents.add(content="memio is a memory gateway")
results = await client.documents.search(query="memory")
Memory stores
memio defines four memory store protocols. Each provider implements one or more:
| Store | Purpose | Mem0 | Zep | Chroma | Letta | Qdrant | Supermemory |
|---|---|---|---|---|---|---|---|
FactStore |
Structured facts about users/agents | yes | yes | - | yes | - | yes |
HistoryStore |
Conversation message history | - | yes | - | yes | - | - |
DocumentStore |
Document storage with semantic search | - | - | yes | yes | yes | yes |
GraphStore |
Knowledge graph triples | yes | yes | - | - | - | - |
FactStore
fact = await store.add(content="prefers dark mode", user_id="alice")
fact = await store.get(fact_id=fact.id)
results = await store.search(query="preferences", user_id="alice")
updated = await store.update(fact_id=fact.id, content="prefers light mode")
all_facts = await store.get_all(user_id="alice")
await store.delete(fact_id=fact.id)
await store.delete_all(user_id="alice")
HistoryStore
await store.add(session_id="s1", user_id="alice", messages=[Message(role="user", content="hello")])
messages = await store.get(session_id="s1", limit=50)
results = await store.search(session_id="s1", query="hello")
sessions = await store.get_all(user_id="alice")
await store.delete(session_id="s1")
await store.delete_all(user_id="alice")
DocumentStore
doc = await store.add(content="some text", metadata={"source": "wiki"})
doc = await store.get(doc_id=doc.id)
results = await store.search(query="text", limit=10)
all_docs = await store.get_all(limit=100)
updated = await store.update(doc_id=doc.id, content="updated text")
await store.delete(doc_id=doc.id)
await store.delete_all()
GraphStore
from memio import Triple
await store.add(
triples=[Triple(subject="Alice", predicate="likes", object="coffee")],
user_id="alice",
)
result = await store.get(entity="Alice", user_id="alice")
result = await store.search(query="coffee", user_id="alice")
await store.delete_all(user_id="alice")
Data models
from memio import Fact, Message, Document, Triple, GraphResult
# Fact — a stored piece of knowledge
Fact(id, content, user_id, agent_id, metadata, score, created_at, updated_at)
# Message — a conversation message
Message(role, content, metadata, timestamp, name)
# Document — a stored document
Document(id, content, metadata, score, created_at, updated_at)
# Triple — a knowledge graph triple
Triple(subject, predicate, object, metadata)
# GraphResult — result from graph queries
GraphResult(triples, nodes, scores)
REST API server
Use memio from any language (JavaScript, TypeScript, Go, etc.) over HTTP:
pip install memio[server,mem0,chroma]
Create memio-server.yaml:
stores:
facts:
provider: mem0
config:
api_key: "${MEM0_API_KEY}"
documents:
provider: chroma
config:
collection_name: "my-docs"
Start the server:
memio-server
# Open http://localhost:8080/docs for interactive API docs
Use from JavaScript:
// Add a fact
const fact = await fetch("http://localhost:8080/v1/facts", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ content: "likes coffee", user_id: "alice" }),
}).then(r => r.json());
// Search
const results = await fetch("http://localhost:8080/v1/facts/search", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query: "preferences", user_id: "alice" }),
}).then(r => r.json());
See the REST API guide for full endpoint reference, authentication, Docker deployment, and configuration options.
Custom providers
Implement any protocol to create your own provider:
from memio import Memio, DocumentStore, Document
class MyDocumentStore:
async def add(self, *, content, doc_id=None, metadata=None):
# your implementation
return Document(id="...", content=content, metadata=metadata)
async def get(self, *, doc_id):
...
async def search(self, *, query, limit=10, filters=None):
...
async def update(self, *, doc_id, content, metadata=None):
...
async def delete(self, *, doc_id):
...
async def get_all(self, *, limit=100, filters=None):
...
async def delete_all(self):
...
# memio validates the protocol at runtime
client = Memio(documents=MyDocumentStore())
Error handling
All provider errors are wrapped in ProviderError:
from memio import ProviderError, NotSupportedError, MemioError
try:
await client.facts.delete(fact_id="123")
except NotSupportedError as e:
print(e.hint) # "use delete_all"
except ProviderError as e:
print(e.provider) # "mem0", "zep", etc.
print(e.operation) # "search", "add", etc.
print(e.cause) # original exception
except MemioError:
# base class for all memio errors
...
NotSupportedError is a subclass of ProviderError, raised when a provider doesn't support a specific operation (e.g., individual delete on Zep). It includes an optional hint suggesting what to do instead. Unlike other ProviderError subclasses, its cause is a NotImplementedError (not an underlying SDK exception).
Provider notes
Mem0 — content may be rephrased by Mem0's LLM. Duplicate content is deduplicated automatically.
Zep — graph operations are eventually consistent. graph.add sends text to an LLM for asynchronous fact extraction. Individual fact/triple deletion is not supported; use delete_all instead.
Chroma — uses a local client you provide. No API key required for ephemeral or persistent local usage.
Letta — supports both Letta Cloud (api_key) and self-hosted (base_url). All stores are agent-scoped via agent_id. Facts and documents both map to archival passages. No graph support.
from memio import Memio
from memio.providers.letta import LettaFactAdapter, LettaHistoryAdapter, LettaDocumentAdapter
client = Memio(
facts=LettaFactAdapter(api_key="letta-xxx", agent_id="agent-123"),
history=LettaHistoryAdapter(api_key="letta-xxx", agent_id="agent-123"),
documents=LettaDocumentAdapter(api_key="letta-xxx", agent_id="agent-123"),
)
Qdrant — uses qdrant-client with built-in fastembed for automatic embeddings. Supports in-memory, on-disk, and Qdrant Cloud deployments. No API key required for local usage.
Supermemory — cloud-hosted memory API. Content is auto-processed by an LLM for fact extraction. get() and delete_all() on FactStore are not supported. Documents are processed asynchronously after add().
Development
git clone https://github.com/y3zai/memio.git
cd memio
python -m venv .venv && source .venv/bin/activate
pip install -e ".[all,dev]"
# Run unit tests
pytest
# Put OPENAI_API_KEY, MEM0_API_KEY, ZEP_API_KEY, and SUPERMEMORY_API_KEY in .env, then run integration tests
pytest -m integration -v
Pytest loads .env automatically from the repository root for local test runs.
License
MIT
Metadata
Release files for memio 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| memio-0.3.1.tar.gz | 64.5 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| memio-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 107.6 kB
Release files / memio-0.3.1.tar.gz
| Download URL | memio-0.3.1.tar.gz |
|---|---|
| Size | 64.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9f5213bc66914de7922183efb197a305b117f52ef2f73c2ca022a2103eaaf1e7
|
|
BLAKE2b-256 checksum How to use checksums |
80dc4df62f44641b96dd5b8f99b17f67a8e77e98bed523ae84d8877fb61386b3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 3, 2026.
Transparency logRelease files / memio-0.3.1-py3-none-any.whl
| Download URL | memio-0.3.1-py3-none-any.whl |
|---|---|
| Size | 43.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
28dd84014ab81f5685269cbbb7f86f32a570bd54c4be78b4f27dc37b606c25ad
|
|
BLAKE2b-256 checksum How to use checksums |
d82d328b651051a36b287ec6e8291004f823d289409f30d56e10d5edf5c63b05
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 3, 2026.
Transparency logSecurity for memio 0.3.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for memio-0.3.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 3, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.