notmemory
Deterministic memory observability for long-lived AI agents.
What is notmemory?
notmemory is an open-source Python SDK that gives AI agents auditable, reversible, GDPR-compliant memory.
Every memory write is cryptographically hash-chained — like Git commits for agent state. Every mistake can be rolled back. Every deletion leaves a forensic trail. Every read is logged.
Built for production AI systems where trust, compliance, and debuggability are non-negotiable.
Why notmemory?
| Problem | notmemory solution |
|---|---|
| Agent hallucinates and corrupts memory | rollback(transaction_id) undoes it |
| GDPR deletion request | forget(bank_id) tombstones with audit trail |
| Can't debug what agent remembered | get_audit_trail(cycle_id) forensic replay |
| Memory grows stale over time | Confidence decay c = c₀ · 2^(-t/30) |
| Need semantic search too | Mem0 / SuperMemory sync-layer adapters |
| Want Claude/Cursor to use agent memory | MCP server adapter |
Features
- Cryptographic audit trail — SHA-256 hash chaining on every write
- Git-like rollback — undo any transaction by ID
- Conflict detection — duplicate detection with health score 0–100
- GDPR tombstoning — compliant deletion with forensic trail
- Full-text search — SQLite FTS5 keyword search
- Confidence decay — exponential half-life
c = c₀ · 2^(-t/30) - LangGraph checkpointer — drop-in replacement for
MemorySaver - LangChain chat history —
BaseChatMessageHistoryimplementation - Mem0 sidecar — semantic search via Mem0
- SuperMemory sidecar — semantic search via SuperMemory
- MCP server — Claude Desktop / Cursor / Windsurf integration
Install
# Core SDK
pip install notmemory
# With LangChain / LangGraph
pip install "notmemory[langchain]"
# With Mem0 semantic search
pip install "notmemory[mem0]" mem0ai
# With MCP server
pip install "notmemory[mcp]"
# Everything
pip install "notmemory[langchain,mcp]" mem0ai
Quickstart
import asyncio
from notmemory import AgentMemory, MemoryConfig
async def main():
async with AgentMemory() as memory:
# Store a memory
entry = await memory.retain(
bank_id="facts",
content={"fact": "The Eiffel Tower is in Paris"},
source="user",
)
print(f"Stored: {entry.id}")
# Search memory
result = await memory.recall(
bank_id="facts",
query="Eiffel Tower",
)
for e in result.entries:
print(e.content)
# Rollback a bad write
await memory.rollback(entry.transaction_id)
# GDPR delete entire bank
await memory.forget("facts")
asyncio.run(main())
Core API
AgentMemory
from notmemory import AgentMemory, MemoryConfig
config = MemoryConfig(db_url="sqlite+aiosqlite:///./myagent.db")
async with AgentMemory(config=config) as memory:
...
| Method | Returns | Description |
|---|---|---|
retain(*, bank_id, content, ...) |
MemoryEntry |
Store with hash chain |
recall(*, bank_id, query, ...) |
RecallResult |
Keyword / temporal search |
rollback(transaction_id) |
RollbackResult |
Tombstone a transaction |
detect_conflicts(*, bank_id) |
ConflictReport |
Find duplicates, health score |
log_cycle_event(*, cycle_id, ...) |
CycleEvent |
DAG audit event |
get_audit_trail(*, cycle_id) |
AuditTrail |
Forensic reconstruction |
verify_integrity(bank_id) |
bool |
Verify SHA-256 hash chain |
forget(bank_id, *, entry_ids) |
int |
GDPR tombstone |
Confidence Decay
Memories lose confidence over time using exponential half-life decay: c(t) = c₀ · 2^(-t / half_life_days)
| Age | Confidence (from 1.0) |
|---|---|
| 0 days | 1.000 |
| 30 days | 0.500 |
| 60 days | 0.250 |
| 90 days | 0.125 |
from notmemory.memory.decay import decayed_confidence, filter_fresh
# Current decayed score
score = decayed_confidence(entry, half_life_days=30.0)
# Filter stale entries out, sort fresh ones by score
fresh = filter_fresh(entries, half_life_days=30.0, deprecation_threshold=0.05)
Adapters
LangChain / LangGraph
from notmemory.adapters.langchain import (
NotMemoryCheckpointer,
NotMemoryChatHistory,
)
# Drop-in for MemorySaver — adds hash-chained audit trail
checkpointer = NotMemoryCheckpointer()
graph = builder.compile(checkpointer=checkpointer)
async with checkpointer:
result = await graph.ainvoke(inputs, config)
# Chat history with GDPR tombstoning
history = NotMemoryChatHistory(session_id="user-42")
async with history:
await history.aadd_messages(messages)
msgs = await history.aget_messages()
Mem0
from notmemory.adapters.mem0 import NotMemoryMem0Adapter
import os
adapter = NotMemoryMem0Adapter(
mem0_api_key=os.environ["MEM0_API_KEY"],
user_id="agent-1",
)
async with adapter:
# Writes to SQLite + mirrors to Mem0
await adapter.retain(bank_id="facts", content={"fact": "..."})
# Keyword search (SQLite)
result = await adapter.recall(bank_id="facts", query="Paris")
# Semantic search (Mem0)
results = await adapter.semantic_recall("European capitals")
SuperMemory
from notmemory.adapters.supermemory import NotMemorySuperMemoryAdapter
import os
adapter = NotMemorySuperMemoryAdapter(
api_key=os.environ["SUPERMEMORY_API_KEY"],
user_id="agent-1",
)
async with adapter:
await adapter.retain(bank_id="facts", content={"fact": "..."})
results = await adapter.semantic_recall("European capitals")
MCP Server (Claude Desktop / Cursor / Windsurf)
Add to claude_desktop_config.json:
{
"mcpServers": {
"notmemory": {
"command": "python",
"args": ["-m", "notmemory.adapters.mcp"],
"env": {
"NOTMEMORY_DB_URL": "sqlite+aiosqlite:///./notmemory.db"
}
}
}
}
Available tools: notmemory_retain, notmemory_recall,
notmemory_rollback, notmemory_forget, notmemory_health
Configuration
from notmemory import MemoryConfig
from notmemory.core.config import HashChainConfig, RetentionConfig
config = MemoryConfig(
storage="sqlite",
db_url="sqlite+aiosqlite:///./agent.db",
hash_chain=HashChainConfig(
enabled=True,
algorithm="sha256",
),
retention=RetentionConfig(
confidence_half_life_days=30.0,
deprecation_threshold=0.05,
),
)
Project Structure
notmemory/ ├── core/ │ ├── agent_memory.py # AgentMemory — main interface │ ├── config.py # MemoryConfig (Pydantic v2) │ └── exceptions.py # exception hierarchy ├── memory/ │ ├── models.py # domain models │ └── decay.py # confidence decay ├── storage/ │ └── backends/ │ ├── base.py # abstract storage interface │ └── sqlite.py # SQLite + FTS5 + hash chaining └── adapters/ ├── base.py # BaseAdapter abstract class ├── langchain.py # LangChain / LangGraph ├── mem0.py # Mem0 sync-layer ├── supermemory.py # SuperMemory sync-layer └── mcp.py # MCP server
Development
git clone https://github.com/notmemory/notmemory
cd notmemory
python -m venv .venv
# Windows:
.venv\Scripts\Activate.ps1
# macOS/Linux:
source .venv/bin/activate
pip install -e ".[dev,langchain,mcp]" mem0ai
# Before every commit
ruff check . --fix
ruff format .
pytest --tb=short
Contributing
- Fork the repo
- Branch from
develop:git checkout -b feature/your-feature - Make changes, run
ruff+pytest - Open PR targeting
develop - CI must be green on Python 3.11, 3.12, 3.13
License
MIT — see LICENSE.
Release files for notmemory 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| notmemory-0.1.0.tar.gz | 34.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| notmemory-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 69.7 kB
Release files / notmemory-0.1.0.tar.gz
| Download URL | notmemory-0.1.0.tar.gz |
|---|---|
| Size | 34.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3f31d96291ba60fe8411293edf1d96af33eb9417c91084696b1d36e00a32a672
|
|
BLAKE2b-256 checksum How to use checksums |
8a8b5ea629b44cbc865f794d897aba53bff33727c7a39b227b90cb53449c5c11
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jun 10, 2026.
Transparency logRelease files / notmemory-0.1.0-py3-none-any.whl
| Download URL | notmemory-0.1.0-py3-none-any.whl |
|---|---|
| Size | 34.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
833d7fc859ce2017aecb4aebdf54913e1787afc2426ad347337924064a028ee0
|
|
BLAKE2b-256 checksum How to use checksums |
cacc945bfbb97cac352706084ef3a95d48c137a12159fcce5241625b42dc48bd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jun 10, 2026.
Transparency log