Production-grade plug-and-play memory for AI agents. Zero config, single-file storage, framework-agnostic.
Project description
membox
Production-grade plug-and-play memory for AI agents.
Give any LLM, agent, or rule-based system persistent episodic + semantic memory. Zero config, single-file storage, framework-agnostic.
from membox import Membox
memory = Membox("my_agent.db")
memory.record("User said they love hiking in the Himalayas", importance=0.8)
memory.learn("user", "prefers", "black coffee", confidence=0.9)
# Retrieve relevant memories
results = memory.recall("what are the user's hobbies?", k=3)
# Get prompt-ready context string
context = memory.context("what does the user like?")
# → "## User Profile\n- user prefers black coffee (90%)\n\n## Relevant Memories\n- ..."
Features
| Feature | Description |
|---|---|
| Episodic memory | Timestamped events with importance + emotion scoring |
| Semantic memory | Fact triples with reinforcement & contradiction |
| Procedural memory | Trigger → action routines, surfaced in context |
| Temporal facts | valid_from / valid_until windows + recurrence patterns |
| Reflection | Synthesizes higher-order patterns across episodes |
| Smart retrieval | Recency × relevance × importance (keyword or embeddings) |
| Context builder | Token-budgeted prompt string: profile + procedures + memories + patterns |
| Thread summarization | pi-style compaction of long conversation threads |
| Consolidation | Compress episodes → stable facts |
| Forgetting | Importance-weighted decay (trivial memories die, critical ones survive) |
| Editing & correction | In-place episode edits + timestamped annotation audit trail |
| Multi-user isolation | owner_id scoping — one DB, many users, no cross-contamination |
| Embeddings (optional) | SQLite-backed semantic retrieval via sentence-transformers |
| Zero dependencies | Core runs on Python stdlib only (SQLite) |
| Single-file storage | One .db file = entire memory. Copy it, back it up, version it. |
Install
# From source (development)
git clone <repo-url> && cd membox
uv sync --extra dev
# Coming soon: pip install membox
Quick Start
Want to run these examples in a browser? Open
notebooks/quickstart.ipynb— a 5-minute executable version of everything below. For the full simple→advanced tour, seenotebooks/walkthrough.ipynb.
1. Record Events
from membox import Membox
memory = Membox("jarvis.db")
# Record what happens
memory.record("User got promoted to Director of Engineering!", importance=1.0, emotion="ecstatic")
memory.record("User ordered black coffee", importance=0.3)
memory.record("User's dog Rocky had a vet visit. All clear.", importance=0.5, emotion="relieved")
2. Learn Facts
# Semantic facts with automatic conflict resolution
memory.learn("user", "name", "Pranav", confidence=0.95)
memory.learn("user", "prefers", "black coffee", confidence=0.9)
memory.learn("user", "lives_in", "Delhi", confidence=0.8)
# Repeat a fact → confidence increases (reinforcement)
memory.learn("user", "prefers", "black coffee") # → confidence: 0.9 → 0.915
# New info → old fact deactivated (contradiction)
memory.learn("user", "lives_in", "Mumbai") # Delhi deactivated, Mumbai active
3. Retrieve Memories
# Keyword + recency + importance scoring
results = memory.recall("coffee", k=3)
for r in results:
print(f"Score: {r.score:.3f} | {r.episode.content}")
# Score breakdown: R=recency, V=relevance, I=importance
print(f" R={r.recency:.2f} V={r.relevance:.2f} I={r.importance:.2f}")
4. Build LLM Context
# Generate a prompt-ready context string
context = memory.context("What should I get for dinner?", max_tokens=2000)
print(context)
# Output:
# ## User Profile
# - user name Pranav (95%)
# - user prefers black coffee (92%)
# - user lives_in Mumbai (80%)
#
# ## Relevant Memories
# - (2h ago) User ordered black coffee
# - (1d ago [ecstatic]) User got promoted to Director of Engineering!
# (when procedures or reflections exist, `## Active Procedures` and `## Patterns`
# sections are added too)
# Plug into any LLM:
messages = [
{"role": "system", "content": f"You are a helpful assistant.\n\n{context}"},
{"role": "user", "content": "What should I get for dinner?"},
]
# → Send to OpenAI, Anthropic, Ollama, etc.
5. Maintenance
# Compress old episodes into semantic facts
memory.consolidate() # one batch; use consolidate_all() to drain the backlog
# Synthesize higher-order patterns across episodes
memory.reflect()
# Prune stale memories (importance-weighted; critical ones survive)
result = memory.forget()
print(f"Deleted: {result['deleted']}, Archived: {result['archived']}")
# …or run all of the above in one call:
memory.maintain()
# Health check
print(memory.stats())
Configuration
from membox import Membox, MemoryConfig
# Custom config
config = MemoryConfig(
decay_rate=0.05, # How fast memories fade (higher = faster)
w_recency=0.3, # Retrieval weight: recency
w_relevance=0.4, # Retrieval weight: keyword match
w_importance=0.3, # Retrieval weight: stored importance
max_context_tokens=2000, # Token budget for context()
)
memory = Membox("agent.db", config=config)
# Or use presets:
fast_memory = Membox("chatbot.db", config=MemoryConfig.fast()) # Aggressive forgetting
deep_memory = Membox("assistant.db", config=MemoryConfig.deep()) # Long retention
Integration Examples
With OpenAI
from openai import OpenAI
from membox import Membox
client = OpenAI()
memory = Membox("openai_agent.db")
def chat(user_message: str) -> str:
# Store the user message
memory.record(f"User: {user_message}", importance=0.5)
# Build context-enhanced prompt
context = memory.context(user_message)
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": f"You are a helpful assistant.\n\n{context}"},
{"role": "user", "content": user_message},
],
)
reply = response.choices[0].message.content
# Store the response
memory.record(f"Assistant: {reply}", importance=0.2, source="response")
return reply
With Anthropic
import anthropic
from membox import Membox
client = anthropic.Anthropic()
memory = Membox("claude_agent.db")
def chat(user_message: str) -> str:
memory.record(f"User: {user_message}")
context = memory.context(user_message)
response = client.messages.create(
model="claude-sonnet-4-20250514",
system=f"You are a helpful assistant.\n\n{context}",
messages=[{"role": "user", "content": user_message}],
max_tokens=1024,
)
reply = response.content[0].text
memory.record(f"Assistant: {reply}", importance=0.2, source="response")
return reply
With Any Agent Framework
from membox import Membox
memory = Membox("agent.db")
# In your agent's observe/act loop:
def agent_step(observation: str) -> str:
# 1. Store observation
memory.record(observation, importance=score_importance(observation))
# 2. Retrieve relevant context
context = memory.context(observation)
# 3. Generate action (your logic here)
action = your_llm_or_rules(observation, context)
# 4. Periodic maintenance
if should_consolidate():
memory.consolidate()
memory.forget()
return action
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Membox │
│ │
│ record() recall() learn() context() consolidate() │
│ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │Episodic│ │Retriev.│ │Semantic│ │Context │ │Consol. │ │
│ │ Store │ │ Engine │ │ Store │ │Builder │ │Pipeline│ │
│ └───┬────┘ └────────┘ └───┬────┘ └────────┘ └────────┘ │
│ │ │ │
│ └──────────┬───────────┘ │
│ ▼ │
│ ┌──────────┐ │
│ │ SQLite │ ← Single .db file │
│ │ (WAL) │ │
│ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
API Reference
Grouped by memory type. All methods are on Membox.
| Category | Method | Returns |
|---|---|---|
| Episodic | record(content, importance, emotion, source, context, thread_id, parent_id, depth) |
Episode |
| Episodic | recall(query, k, min_score) |
list[RetrievalResult] |
| Episodic | recent(n) |
list[Episode] |
| Episodic | search(keyword, limit) |
list[Episode] |
| Threads | thread(thread_id, limit) |
list[Episode] |
| Threads | thread_children(episode_id, limit) |
list[Episode] |
| Threads | threads(limit) |
list[str] |
| Threads | summarize_thread(thread_id) |
ThreadSummaryResult |
| Semantic | learn(subject, predicate, obj, confidence, valid_from, valid_until, recurrence) |
(Fact, action) |
| Semantic | about(subject, at_time) |
list[Fact] |
| Semantic | find_fact(subject, predicate, at_time) |
list[Fact] |
| Procedural | learn_procedure(trigger, action, confidence) |
Procedure |
| Procedural | match_procedures(text) |
list[Procedure] |
| Procedural | procedures() / delete_procedure(id) |
list[Procedure] / bool |
| Context | context(query, max_tokens, min_score, profile_subject) |
str |
| Maintenance | consolidate() / consolidate_all() |
dict |
| Maintenance | reflect(episodes) / reflections(subject) |
dict / list |
| Maintenance | forget() |
dict |
| Maintenance | maintain() — runs consolidate → reflect → summarize → forget |
dict |
| Editing | update_episode(id, ...) / annotate_episode(id, ...) |
Episode |
| Editing | edit_fact(id, ...) / correct_fact(id, ...) |
Fact / (Fact, action) |
| Lifecycle | stats() / close() |
dict / None |
learn()'s action is 'new' / 'reinforced' / 'contradicted'. Retrieval scores combine as w_recency·R + w_relevance·V + w_importance·I (see notebooks/walkthrough.ipynb §5).
Design Decisions
| Decision | Why |
|---|---|
| SQLite, not Postgres | Zero config, ~0.05ms reads, single-file backup. Handles 18M rows (10yr heavy use). |
| Stdlib only | No supply-chain risk. Embedding search is an optional extra. |
| Sync API | Lowest latency path. SQLite calls are <1ms — async overhead isn't worth it. |
| Store protocols | EpisodicStoreProtocol / SemanticStoreProtocol — swap in Postgres/Redis by implementing the protocol. |
| Tiered forgetting | Critical memories (importance ≥ 0.9) never die. Trivial ones fade in days. |
Development
# Install dev deps
uv sync --extra dev
# Run tests (262 passed, 19 skipped, ~1.5s)
uv run pytest
# Run with verbose output
uv run pytest -v
# Run scale tests only
uv run pytest tests/test_episodic.py::TestEpisodicScale -v
Documentation
| Doc | What it's for |
|---|---|
| README.md (this file) | Front door: features, install, quick start, API, design |
notebooks/ |
Runnable examples — quickstart.ipynb (5-min) and walkthrough.ipynb (simple→advanced) |
CHANGELOG.md |
History of changes, release by release |
BUGS.md |
Known-issues tracker — audit with severity, status, and fix notes |
lessons/ |
8 incremental teaching scripts that build the library from scratch |
demos/ |
demo_openrouter.py — live end-to-end run with a real LLM |
integrations/pi/ |
Long-term memory for pi: HTTP sidecar + TypeScript extension |
License
MIT
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 remembox-0.2.0.tar.gz.
File metadata
- Download URL: remembox-0.2.0.tar.gz
- Upload date:
- Size: 188.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0697f5ecb165e1678d4a4b7a59c3721821cb87422aa7a6214f6b4eeb707add57
|
|
| MD5 |
b6e6a2108c1c3046efd0f0f19273e132
|
|
| BLAKE2b-256 |
49bc5a6e314fa0c23f570c6b18e336cc78ba9aa0cb3f0c44b511b9f415ae5655
|
File details
Details for the file remembox-0.2.0-py3-none-any.whl.
File metadata
- Download URL: remembox-0.2.0-py3-none-any.whl
- Upload date:
- Size: 56.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e5d198457047fd247c46b6d41b171ffdbcd28f756ea980b457e0ff2d7af15dc6
|
|
| MD5 |
75b31dba3e9e7aad91478d041e7195b2
|
|
| BLAKE2b-256 |
127b20a81d553ab7073f044e4843aefa322124bdd805d0bfcc1902a5b996d4ab
|