OptMem: Permanent Memory for AI Agents in a 426-Token Prompt
Posted 2026-11-04 · by han · 10 min read
A grounded writeup of Victor Taelin's OptMem — what it is, how it stores and recalls memory, where its claims hold up, and where they don't. Every quantitative claim is tagged: [project-reported] (stated by the project, not independently verified), [verified] (checked against the source code in this writeup), [as of YYYY-MM-DD] (snapshot value).
TL;DR
OptMem gives an AI agent a memory that survives session resets, compaction, and even vendor changes. It ships two artifacts and nothing else:
- A ~426-token prompt block (
## Memory) that you paste into your agent'sAGENTS.md/CLAUDE.md. - A single Python file (
memo, ~31 KB, Python 3 stdlib only) that the agent calls as a CLI.
Storage is an append-only log at ~/.optmem/memory/LOG.txt — one line per memory, max 280 bytes — plus a rebuildable binary-tree summary cache (TREE/). Retrieval is regex, not semantic. The agent wakes by reading a slice of that tree (recent memories verbatim, older ones collapsed into one-line summaries).
- Repo:
github.com/VictorTaelin/OptMem— 2.4k ⭐, 148 forks, 42 commits, no LICENSE file [as of 2026-11-04]. - Author: Victor Taelin (also author of HVM and Kind).
- Published: 2026-07-25 (per project notes); 887 stars in 5 days [project-reported, not independently verified].
1. What OptMem is
OptMem's pitch is that agent memory should be permanent, append-only, and trivially portable — outliving "every session, compaction, model and vendor change." The mechanism is deliberately minimal:
- No database, no embeddings, no vector store. One Python file, zero dependencies.
- No background processes. "Merges arrive one at a time, in the output of
note. Nothing ever runs in the background." - The prompt IS the integration. The installer prints a
## Memoryblock; you paste it at the top of your agent instruction file. That block is the whole contract between agent and tool.
The tool lands at ~/.optmem/memo; put ~/.optmem on PATH to type memo. Memory lives in ~/.optmem/memory/ (or $MEMORY_DIR).
2. How it stores memory
Three files, all under ~/.optmem/memory/:
| File | Role |
|---|---|
LOG.txt |
Every memory, one per line, append-only, never edited |
TREE/ |
One-line summaries per tree level (a rebuildable cache) |
config |
Size knobs (written by memo config) |
Fixed-width records are the trick. Each log record is exactly 320 bytes (LOG_REC = 320), each tree record 288 bytes (TREE_REC = 288) [verified against source]. A memory's position is its identity: memory i lives at byte offset i × 320 in LOG.txt. No index file, no scanning — "one seek per lookup." Padding costs ~2× on disk and buys O(1) everywhere [project's own comment].
Each log record looks like:
#<id> YYYY-MM-DD <text up to 280 bytes>
Example (padded to 320 bytes with trailing spaces):
#42 2026-11-04 User prefers concise replies; dislikes filler phrases.
Entry cap: ENTRY_CHARS = 280 bytes default, tunable via memo config ENTRY_CHARS=N (max 280 because records are fixed-width) [verified]. Accented characters cost 2 bytes in UTF-8.
Tree (binary compression). Memories form a binary merge tree: #0-1, #2-3, … are one-line summaries of pairs; pairs of those become #0-3, and so on. memo wake prints a slice: recent memories verbatim, older ones collapsed into tree nodes. memo zoom <a-b> opens a node into its two halves; memo forget <a-b> drops a bad summary so the next nap rebuilds it.
Compression is agent-driven, not automatic. When memo note creates a memory that pushes a block past its threshold, it prints a nap prompt asking you (the agent) to compress #lo-hi into one line ≤ 280 bytes. "Keep what has lasting effect, drop what does not. Invent nothing." Nothing runs in the background — the agent must answer the prompt before its next action.
3. Retrieval model: regex, not semantic
This is the most important design choice to understand, and the main limitation.
memo recall <regex>searches every memory ever recorded, word-for-word, case-insensitive (re.compile(pattern, re.I)). It is regex over raw text — no embeddings, no similarity, no fuzzy matching.- The tree is a partial mitigation: older memories survive only as one-line summaries, so a vague regex still finds the summary node, and
zoomdrills down. - There is no semantic recall. If you remember "the thing about the database" but not the exact word,
recallwon't help unless your regex matches the stored wording.
Contrast with pgvector/Chroma (or NullClaw's 10 memory engines, or MicroClaw's semantic recall): those retrieve by meaning. OptMem trades recall quality for zero dependencies and O(1) storage.
4. Performance claims & limits
From the project's own README and source comments [project-reported unless noted]:
| Claim | Value | Tag |
|---|---|---|
| Prompt size | 426 tokens | [project-reported] |
| Default wake output | WAKE_LINES=96 ≈ 8k tokens |
[project-reported; code comment says "~8k tokens of dense text"] |
| Entry cap | 280 bytes | [verified: ENTRY_CHARS default] |
| Log record width | 320 bytes | [verified: LOG_REC = 320] |
| Tree record width | 288 bytes | [verified: TREE_REC = 288] |
| 1M memories → disk | 608 MB | [project-reported] |
1M memories → wake |
0.03 s | [project-reported; not independently verified] |
| Raw-memory compression threshold | up to 16 memories per block (RAW_MAX = 16) |
[verified] |
The WAKE_LINES tradeoff. WAKE_LINES is "a reading budget, not a storage budget": change it any time, in either direction, and nothing is recomputed. Higher = more context per wake (more tokens), lower = cheaper wake (older memories more collapsed). Default 96 ≈ 8k tokens is a reading-budget choice, not a storage limit.
Output paging. Because harnesses truncate differently (Claude Code cuts the middle at 30k chars, pi cuts the head at 50 KB, Codex budgets 10k tokens), memo wake paginates into parts ≤ 20,000 bytes / 500 lines (PART_CHARS, PART_LINES) [verified]. The agent runs memo wake 2 <T> to continue; the final part prints "You are awake."
Honest limits:
- Regex retrieval misses paraphrases (see §3).
- Summary fidelity loss: each
napcompresses N memories into one ≤280-byte line; detail decays with age by design. - 280-byte cap per memory forces compression at write time.
- No encryption, no access control — memory is plaintext on disk.
5. Installation & integration
The installer is a short shell script that requires python3, downloads the single memo file into ~/.optmem/memo, and runs memo init. memo init creates the store and prints the ## Memory block to paste into your agent's instruction file. Re-running is safe (it never overwrites existing memories).
The block to paste looks like this (paths are filled in by the installer):
## Memory
Your memory is OptMem:
- The tool is `~/.optmem/memo`
- Your memories are in `~/.optmem/memory`
OptMem outlives every session, compaction, model and vendor change.
Without it you do not know who you are, or what was decided and tried.
### At startup: activating OptMem (mandatory)
Run `~/.optmem/memo wake` before any other tool call, in every session,
and then do exactly what it prints, to the end of its output.
### While working: register memories (mandatory)
Call `~/.optmem/memo note "<1 line, max 280 bytes>"` whenever you learn
something new, or something worth keeping happens. That covers a task
worth real effort, a fact or insight the user teaches you, anything you
learn about their life (even indirectly), any event of lasting effect.
Do not register redundant memories.
If `~/.optmem/memo note` asks a compression: do it before your next action.
Never edit or delete anything under `~/.optmem/memory`: the tool manages it.
### When you need an old memory: search, or navigate
`~/.optmem/memo recall <regex>` searches every memory, word for word.
Your memories also form a binary tree: #0-1, #2-3 ... exist as one-line
summaries, pairs of those as #0-3, and so on -- every `#a-b` line wake
prints is one node of it. `~/.optmem/memo zoom <a-b>` opens a node into
its two halves, down to the raw memories.
### If you're a subagent: skip everything above
Parallel sessions on this machine are all you, and may all write memories.
A subagent is not: it must never run `memo`, because it cannot judge what
is already known, and its notes would arrive duplicated and incorrectly.
When you spawn one, write: `You are a subagent. Don't run memo.`
Key commands (safe usage examples, not install commands):
memo wake # first command of every session
memo note "..." # record one memory (≤ 280 bytes)
memo nap # answer pending compressions
memo recall <regex> # search all memories, word-for-word
memo zoom <lo>-<hi> # open a tree node
memo forget <lo>-<hi> # drop a bad summary; nap rebuilds
memo config # show sizes
memo config WAKE_LINES=300
Concurrency — correction to common belief. Some summaries describe OptMem as having "no lock protocol." That is inaccurate: the memo source uses advisory file locks — fcntl.flock(LOCK_EX) on Unix, msvcrt locking on Windows — around every append and tree write [verified]. Parallel sessions queue rather than clobber. The README's statement "Parallel sessions on this machine are all you, and may all write memories" is consistent with this. What is not provided: cross-machine locking or a merge protocol for conflicting summaries — two machines sharing $MEMORY_DIR via a synced folder can still race at the file level.
6. Where it breaks (honest assessment)
Grounded in the source and README, not opinion:
- Regex retrieval misses meaning. If the user said "Postgres" and you search "database," no hit. The tree helps only if a summary happened to use your word.
- Summary fidelity decays. Each level compresses further; by
#0-15a week of work is one line. "Invent nothing" is an instruction, not a guarantee — bad compressions persist untilforget+nap. - 280-byte cap. Long facts must be split or compressed at write time.
- No license. The repo ships no
LICENSEfile [verified: file list shows.gitignore, README.md, WINDOWS.md, install.sh, memo, test.py]. Default copyright applies: personal use OK, redistribution blocked. Do not vendormemointo a shipped product without contacting the author. - Merge stalls.
wakerefuses to print if a needed tree node is missing ("Cannot wake: … not compressed yet") and asks you tonapfirst. In practice this forces a compression round-trip before the agent can even read its memory. - Single-machine identity.
$MEMORY_DIRcan point at a synced folder, but there is no multi-writer coordination beyond advisory locks on one filesystem. - Subagent discipline is prompt-level. "You are a subagent. Don't run memo." is a convention, not an enforcement — a subagent that ignores it duplicates notes.
7. When to keep a vector store
OptMem is a good fit when: you want zero dependencies, O(1) storage, human-readable plaintext memory, and regex-level recall is enough (or you're willing to zoom).
Keep pgvector/Chroma (or NullClaw's SQLite+FTS5+cosine hybrid, or MicroClaw's semantic recall) when: you need meaning-based retrieval, team/shared memory across writers, or you can't afford summary fidelity loss. OptMem and a vector store are not mutually exclusive — OptMem as the always-on identity layer, a vector store for deep recall.
8. FAQ
Claude Code compatible? Yes — the prompt is tool-agnostic and uses AGENTS.md/CLAUDE.md. Claude Code's 30k-char output truncation is handled by PART_CHARS paging [verified].
Context cost? 426-token prompt + wake output (default ~8k tokens, tunable). Nothing else is injected.
Scaling? Linear disk (320 B/record ≈ 306 MB per million memories), O(1) lookup by position. wake at 1M memories claimed at 0.03 s [project-reported].
License? None shipped → default copyright. See §6.4.
vs. CLAUDE.md / AGENTS.md alone? Those are static. OptMem is append-only and grows; the prompt just tells the agent to use it.
Sources
Primary (all verified against the live repo on 2026-11-04):
github.com/VictorTaelin/OptMem— repo page (stars, forks, commits, file list, license absence, README). [as of 2026-11-04]raw.githubusercontent.com/VictorTaelin/OptMem/main/memo— full source (constantsLOG_REC,TREE_REC,ENTRY_CHARS,WAKE_LINES,RAW_MAX,PART_CHARS,PART_LINES; locking; commands). [as of 2026-11-04]raw.githubusercontent.com/VictorTaelin/OptMem/main/install.sh— installer. [as of 2026-11-04]
Secondary (referenced in prior research notes, not independently retrieved for this writeup): a Zentor blog post on OptMem. Claims in this writeup that came from project notes rather than primary sources are tagged [project-reported].
Prepared 2026-11-04. All [project-reported] figures are the project's own statements; they have not been independently reproduced. EOF echo done