Architecture
Last verified against the code: 2026-10-21 (first commit)
One Python package, one SQLite file, five stages. No service, no server, no dependencies.
~/.claude/projects/<project>/*.jsonl the raw stream (Claude Code transcripts)
│
▼ openmemory ingest transcripts.py → ingest.py
┌─────────────────────────────┐
│ ~/.openmemory/memory.db │ episodes (session / error / correction / note), sessions,
│ │ lessons, predictions store.py, embed.py
└─────────────────────────────┘
│ │
│ recall │ sleep (nightly) sleep.py: decay → lessons → verify → predict
▼ ▼
recall.py render.py ──▶ ~/.claude/projects/<project>/memory/ om-<id>.md + a section of MEMORY.md
(CLI, MCP) ──▶ ~/.openmemory/lessons.jsonl the wire format
──▶ ~/.openmemory/morning.md the owner's report
Components
| Component | File | Role |
|---|---|---|
| Paths | openmemory/paths.py |
Every location, each overridable by an environment variable |
| Transcripts | openmemory/transcripts.py |
Claude Code JSONL → Session of Turns; tool calls paired with their results; corrections detected |
| Store | openmemory/store.py |
SQLite schema and all reads and writes; strengths, touches, predictions |
| Embed | openmemory/embed.py |
256-dimension hashed word and bigram vectors; cosine |
| LLM | openmemory/llm.py |
Optional local model over an OpenAI-compatible API; every call fails soft to None |
| Ingest | openmemory/ingest.py |
Sessions → episodes; deterministic gist or a model-written one |
| Recall | openmemory/recall.py |
Scoring (relevance, recency, strength), touching, formatting |
| Sleep | openmemory/sleep.py |
The four nightly passes and the morning report text |
| Render | openmemory/render.py |
Lesson files, the managed section of MEMORY.md, vetoes, lessons.jsonl |
| MCP | openmemory/mcp.py |
JSON-RPC over stdio: initialize, tools/list, tools/call (recall, remember) |
| CLI | openmemory/cli.py |
status, ingest, recall, sleep, morning, serve, hook, paths |
The store
Four tables in memory.db (SCHEMA in store.py):
| Table | Columns | Notes |
|---|---|---|
episodes |
id, session_id, cwd, kind, title, gist, detail, at, created, strength, recalls, last_touched, archived, embedding | kind is session, error, correction or note; embedding is a JSON list |
sessions |
id, path, mtime, ingested, episodes | Makes ingest idempotent; a changed mtime re-reads the session |
lessons |
id, text, kind, cwd, strength, seen, sources, created, updated, embedding | sources is a JSON list of episode ids |
predictions |
id, lesson_id, text, made, resolved, outcome, embedding | outcome is confirmed or failed once resolved |
Timestamps are ISO 8601 UTC with microseconds, so "created after this prediction was made" is unambiguous.
Data flow in detail
- Ingest lists every top-level
*.jsonlunder every project folder (subagent transcripts in subfolders are skipped). For each file whose mtime is new,parse()builds turns: user text (meta lines and slash-command records stripped), assistant text and tool calls merged across the streamed records of one turn, and tool results attached to the assistant turn that made the call.episodes_of()yields one session episode and one per surprise. Each episode's embedding is of its title and gist. - Recall scores every unarchived episode and every lesson:
0.6·cosine + 0.25·2^(−age/30d) + 0.15·min(strength,2)/2, returns the top k, and touches the episodes it returned (+0.1 strength, +1 recall). - Sleep runs decay (strength × 2^(−days since last touch / 45); below 0.15 → archived), consolidation (surprises join the nearest lesson at cosine ≥ 0.55 or cluster into a new one; one correction suffices, an error must repeat), verification (open predictions matched against episodes created since, cosine ≥ 0.5; failed after 14 days), prediction (one per lesson with strength ≥ 1 and no open prediction).
- Render writes one
om-<id>.mdper lesson into each project's memory folder (lessons with nocwdgo everywhere) and rewrites only the section ofMEMORY.mdbetween the markers.written.jsonrecords what was written; a lesson whose file is missing on the next render is added tovetoed.json.
Where it runs
On the person's machine only. The CLI runs on demand; sleep is meant for cron; serve is started by the agent
(Claude Code) as an MCP server; ingest --quiet is meant for the agent's SessionEnd hook. See
OPERATIONS.md.
What is designed but not built
The commons (sharing lessons between agents under verification), compiled memory (lessons as a model's attention state) and the raw stream beyond the terminal are described in the paper §5, §6 and §3.2, the protocol in PROTOCOL.md, and the order of work in ROADMAP.md.