Architecture
Last verified against the code: 2026-11-13 (0.9.0)
One Python package, one SQLite file, five stages. No service, no server, no dependencies.
~/.claude/projects/<project>/*.jsonl the raw stream (Claude Code transcripts)
│
▼ remem ingest transcripts.py → ingest.py
┌─────────────────────────────┐
│ ~/.remem/memory.db │ episodes (session / error / correction / surprise / environment / 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) ──▶ ~/.remem/lessons.jsonl the wire format
──▶ ~/.remem/morning.md the owner's report
Components
| Component | File | Role |
|---|---|---|
| Paths | remem/paths.py |
Every location, each overridable by an environment variable |
| Transcripts | remem/transcripts.py |
Claude Code JSONL → Session of Turns (mid-turn messages included, harness lines left out); tool calls paired with their results; corrections, refusals, error classes and stated surprises read |
| Store | remem/store.py |
SQLite schema and all reads and writes; strengths, touches, predictions |
| Embed | remem/embed.py |
A local embedding model through Ollama when there is one, else 256-dimension hashed word and bigram vectors; each vector tagged with its space; cosine, relevance, centroid |
| LLM | remem/llm.py |
Optional local model over an OpenAI-compatible API; every call fails soft to None |
| Ingest | remem/ingest.py |
Sessions → episodes; deterministic gist or a model-written one |
| Recall | remem/recall.py |
Scoring (relevance, recency, strength), touching, formatting |
| Sleep | remem/sleep.py |
The six nightly passes (embed, decay, lessons, merge, verify, predict) and the morning report text |
| Prime | remem/prime.py |
Three hooks, one command: lessons a prompt bears on (UserPromptSubmit), correction lessons a hand-back at the end of a turn bears on (Stop), error lessons a tool call bears on (PreToolUse); once per session, half the sessions held out, all logged |
| Delegation | remem/delegation.py |
Counts "asked, told to act" (a correction after a hand-back) and "acted, stopped" (a refused call) by kind of action; shown to the owner in morning.md, not to agents (0.8.0) |
| Setup | remem/setup.py |
Wires every installed agent: Claude Code hooks and MCP; MCP for Claude Desktop, Cursor, Windsurf, Gemini CLI, Codex; the nightly cron |
| Chats | remem/chats.py |
Conversations from any model (OpenAI, Anthropic, Gemini message formats) → Session, for the same detectors |
| Events | remem/events.py |
The open event format (PROTOCOL §0) → episodes; MCP remember, --events, the inbox, the proxy |
| Proxy | remem/proxy.py |
OpenAI- and Anthropic-compatible proxy: memory into every system prompt, conversations recorded; the /memory/* HTTP API |
| Ed25519 | remem/ed25519.py |
RFC 8032 signatures in pure Python, for signed sharing |
| Codex | remem/codex.py |
Codex CLI's session files → Session (experimental) |
| Installer | site/install-src/install.sh, scripts/build-site.mjs |
One-line install on another machine from /install/ (token-gated): checksummed wheel, uv, setup, commons |
| Release check | scripts/release-check.py |
Every release step checked mechanically; a release is done only when it passes |
| Commons | src/commons.js |
The Worker's /commons/ route: one signed file per memory in KV, writes verified with WebCrypto Ed25519 |
| Share | remem/share.py |
Lessons between memories: export with hash and origin, receive as candidates (safety checks, corroboration by hash or meaning), confirmations back, revocations, sync through a folder |
| Experiment | remem/experiment.py |
Controlled tests on a model: behaviour, mechanism, loop (tools), boundary (where asking is right); training pairs |
| Goals | remem/goals.py |
Goals A1–A10 checked from the kept experiments, the store and the adapters |
| Adapter | scripts/adapter.py |
Compiled memory: a LoRA adapter trained on the reminder pairs, tested with no reminder (outside the stdlib CLI) |
| Compare | remem/compare.py |
Replays the history: Remem against retrieve-similar memory on repeated corrections, and what each injects |
| Measure | remem/measure.py |
Goal 10: the repeat-yourself and repeated-error rates, prediction accuracy, themes, by day |
| Render | remem/render.py |
Lesson files, the managed section of MEMORY.md, vetoes, lessons.jsonl |
| MCP | remem/mcp.py |
JSON-RPC over stdio: initialize, tools/list, tools/call (recall, remember) |
| CLI | remem/cli.py |
status, setup, ingest, recall, sleep, measure, compare, experiment, goals, prime, morning, serve, proxy, share, context, tools, call, hook, paths |
The store
Five 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, surprise, environment or note; id is a hash of session, kind and title (stable across re-reads; notes keep random ids); embedding is a JSON list (hashed) or {"s": model, "v": [...]} (a model's space) |
sessions |
id, path, mtime, ingested, episodes, offers | Makes ingest idempotent; a changed mtime re-reads the session. offers (0.2.3) is JSON: each reply that offered to act, its kind and how the person answered (corrected, declined, approved, other), and how many replies waited on the person |
lessons |
id, text, kind, cwd, strength, seen, sources, created, updated, embedding, origin, hash, origins | sources is a JSON list of episode ids (empty for a lesson from another memory); origin the memory it came from, hash its identity across memories, origins the memories that corroborated or confirmed it (0.4.0) |
predictions |
id, lesson_id, text, made, resolved, outcome, embedding | outcome is confirmed or failed once resolved |
aliases |
old, new, at, created | A lesson merged into a theme (old) and the theme it lives on in; created is when the old lesson was made, so the measure knows how long the theme has been in mind |
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, except a correction's, which is of the person's words alone; one batch per transcript. - 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 first embeds again whatever is not in the current space, then runs decay (strength × 2^(−days since last touch / 45); below 0.15 → archived), consolidation
(surprises join the lesson whose sources they resemble, by mean cosine ≥ 0.62 in a model's space or 0.55 hashed, or cluster into a new one; one correction suffices, an
error or a stated surprise must repeat;
environmentepisodes are never consolidated), merging (lessons of one kind whose sources mean the same thing, by average linkage, become one theme; the others become aliases), verification (open predictions matched against episodes of the lesson's kind that happened since, cosine ≥ 0.5 hashed or the same-surprise cut; failed after 14 days), prediction (one per lesson with strength ≥ 1 and no open prediction). - Render writes one
remem-<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.