How my agents remember: five layers of memory I can read and edit
How 10 agents on one Azure server remember what matters across months of daily work. Small notes I can read and edit keep the active rules fresh, while full searchable history on my own server preserves every past conversation.
The Core Difference: Hosted AI memory lives on a provider's servers in its format; I can view or delete entries but not version, script or move the files. Mine is split into five layers I own. What must survive permanently sits in plain Markdown files with strict character caps, so I can open, audit and edit them in seconds with any text editor. Past conversation history is kept in a local SQLite database on my own server (LCM-X), allowing agents to search earlier turns without crowding their active working window.
- Production platform
- Hermes Agent on Azure VPS · SQLite WAL · Markdown
- Design principle
- Short curated files for permanent rules · Searchable database for history
- Human oversight
- Agent operations run with human approval gates for irreversible actions
Architecture: the five layer hierarchy
Each layer has one specific job, one retention rule, one size budget, and one gate on who may write to it. The model reads only L1 directly. Everything else arrives through the context assembler or a tool call.
The problem: remembering everything makes agents worse
Agents that try to remember everything fail in two quiet ways. The context window fills with stale detail, so the model spends attention on noise. And a store full of unchecked fragments lets the model recall things that were never true. Neither failure raises a clean error.
Cutting old messages blindly is not the answer either: the agent forgets earlier decisions, and a retried task starts from zero. I wanted durable memory small enough to read and audit in full, every durable write reversible, and the bulk of history compressed for the model without ever being thrown away.
How the five layers work
- L1 Session window and system prompt: The live working desk. Holds the system prompt, the agent's role rules, active conversation turns, and tool results. When it grows past the compaction threshold, LCM-X folds the oldest turns into summary nodes and preserves pointers to the original messages.
- L2 Ephemeral scratch: The scratchpad. Each agent's TMPDIR points to its own cache/scratch directory. Downloads, extracted archives, and probe scripts land here. Nothing in scratch is read by subsequent sessions, and entries idle for 24 hours are pruned automatically.
- L3 Curated persistent memory: The personal notebook. Two plain Markdown files per agent, MEMORY.md for system notes and USER.md for my profile, with hard character caps (2,200 and 2,600 characters on the router agent). Both files are loaded in full into every session, eliminating vector ranking latency and missed context. The strict cap forces active curation.
- L4 Curated knowledge base: The reference library. 20 Markdown files in ~/.hermes/knowledge, organized with one topic per file. Contains verified facts about me, systems, and operating boundaries, edited by hand and read on demand per domain.
- L5 Procedural skills library: The workshop tool rack. 980 SKILL.md files (249 distinct skills) across the router and 9 domain agents. Each skill defines activation triggers, step-by-step procedures, exit criteria, and runnable scripts. Skills represent executable procedures rather than raw facts, keeping them separate from L4.
Layer specifications
| Layer | Scope | Persistence | Capacity cap | Storage engine | Tool access gate |
|---|---|---|---|---|---|
| L1 Session window and system prompt | One session of one agent | Not stored as is; overflow is compacted into lcm.db | Model context window; compaction starts at 0.4 of the window | Prompt assembled in memory | No tool; always present |
| L2 Ephemeral scratch | One task of one agent | Entries idle for 24 hours are pruned | Disk, pruned | Filesystem; TMPDIR points to the agent's cache/scratch | Shell and file tools; never read back unless promoted |
| L3 Curated persistent memory | Every session of one agent | Permanent; timestamped snapshot before each curator run | 2,200 characters of notes, 2,600 of user profile (router agent; each agent sets its own) | Markdown, written by temp file, fsync and rename | memory tool only; refuses writes over the cap; queued writes reviewed by the curator |
| L4 Curated knowledge base | Facts shared by all agents, loaded by domain | Permanent, edited by hand | One topic per file; 20 files | Markdown in ~/.hermes/knowledge | Read on demand; md_guard.py checks every edit and runs daily |
| L5 Procedural skills library | Per agent | Permanent, versioned | 980 SKILL.md files, 249 distinct skills | SKILL.md plus references and scripts | Loaded when a task matches; configuration drift audited hourly by the infrastructure agent |
| LCM-X (beneath L1) | Full history of one agent; each agent has its own lcm.db | Permanent raw rows; removal only by an explicit owner purge | Disk; 441,511 raw messages in the router agent's store | SQLite in WAL mode with FTS5 indexes | lcm_grep, lcm_recall, lcm_expand |
Curation, human approval gates, and rollback
Writes to persistent memory (L3) never go straight to disk. They pass through a structured validation pipeline with snapshots, so any incorrect fact can be rolled back instantly.
- Pending queue: Proposed memory writes requiring review are saved as JSON records in ~/.hermes/pending/memory rather than applied directly.
- Pre-filter: A fast gate checks candidate writes to discard transient session noise before deeper evaluation.
- Review tier: Fable, the top reasoning tier, evaluates each candidate. Durable operational facts and user preferences are accepted. Routine task progress is logged only, since LCM-X already records full transcripts. Irreversible changes (such as deletions, security boundaries, or suppression lists) wait for my manual confirmation.
- Snapshot backup: Before modifying memory, the curator copies MEMORY.md and USER.md to timestamped files in memories/backups (3 snapshots on disk today).
- Atomic apply: Approved updates use atomic file operations (write to temporary file, fsync, and rename) behind file locks, ensuring no agent ever reads a partially written file. The memory tool strictly rejects updates exceeding the character limit until old entries are consolidated.
- Audit ledger and recovery: A local SQLite ledger tracks the source session and reasoning behind every remembered fact. If an incorrect claim is detected, restoring the previous snapshot takes one command. Explicit forgetting leaves a clean audit tombstone.
In addition, an automated hourly job backs up agent state and memory files, and a daily guard script checks that knowledge edits stay within their assigned topic files.
LCM-X: lossless context memory
LCM-X operates beneath L1. Every message sent or received is recorded once in lcm.db with an immutable store_id. When the active context window fills up, LCM-X compacts older messages into a depth 0 summary node that references the exact store_ids it summarizes. When multiple depth 0 nodes accumulate, they compact into a depth 1 node. This creates a clean directed acyclic graph where summaries always link back to the exact source messages, and compaction never deletes or alters raw history.
- Compaction: The router agent's database currently holds 441,511 messages from 947 sessions and 990 summary nodes (922 at depth 0, 63 at depth 1, 5 at depth 2). Maximum depth currently in use: 2.
- FTS5 search: SQLite FTS5 full-text indexing indexes all messages and summary nodes. Search ranks results by keyword match strength and recency, allowing agents to pinpoint exact filenames, error strings, and identifiers instantly.
- Lossless expansion: If an agent needs full historical context beyond a summary, the lcm_expand tool fetches the exact source messages by store_id or node_id. Compaction reduces token load in the active prompt without losing historical fidelity.
- Concurrent WAL mode: SQLite Write-Ahead Logging allows background compaction jobs to write without blocking active agent reads.
Live telemetry and verification
Every figure on this page is either an architectural design constant or the output of a live, read-only system check probed on 1 Nov 2026.
| Figure | Value | Reproduce with | Source |
|---|---|---|---|
| Memory layers | 5 | Design, see the table above |
declared |
| Router agent notes | 2,199 of 2,200 characters | wc -m ~/.hermes/memories/MEMORY.md |
probed at build |
| Router agent user profile | 2,571 of 2,600 characters | wc -m ~/.hermes/memories/USER.md |
probed at build |
| Character caps | 2,200 and 2,600 | grep char_limit ~/.hermes/config.yaml |
probed at build |
| Memory snapshots on disk | 3 | ls ~/.hermes/memories/backups/MEMORY_*.md | wc -l |
probed at build |
| Knowledge files | 20 | ls ~/.hermes/knowledge/*.md | wc -l |
probed at build |
| Skill files | 980 (249 distinct names) | find ~/.hermes/skills ~/.hermes/profiles/*/skills -name SKILL.md | wc -l |
declared, verified 7 Oct 2026 |
| Agents | 10 | router plus ls -d ~/.hermes/profiles/*/ |
probed at build |
| lcm.db journal mode | wal | sqlite3 lcm.db 'PRAGMA journal_mode;' |
probed at build |
| Raw messages | 441,511 across 947 sessions | SELECT COUNT(*) FROM messages; |
probed at build |
| Summary nodes | 990 (922 at depth 0, 63 at depth 1, 5 at depth 2) | SELECT depth, COUNT(*) FROM summary_nodes GROUP BY depth; |
probed at build |
| Dangling references | 0 of 50,569 | integrity query below |
probed at build |
| Host | Azure VPS | uname -r contains azure |
probed at build |
Integrity check for the lossless DAG claim: every store_id and node_id referenced in a summary node must exist in the database. Result on 1 Nov 2026: 0 dangling references out of 50,569.
SELECT COUNT(*) FROM summary_nodes s, json_each(s.source_ids) j
WHERE (s.source_type = 'messages'
AND NOT EXISTS (SELECT 1 FROM messages m WHERE m.store_id = j.value))
OR (s.source_type <> 'messages'
AND NOT EXISTS (SELECT 1 FROM summary_nodes n WHERE n.node_id = j.value));
Prototype vs production lineage
Prototyping history
From 11 Sep 2026 I ran a local prototype on my MacBook to test two ideas: local vector embeddings for semantic recall, and the Hindsight memory service for episodic, dated facts that agents could search by meaning. On 20 Sep 2026 the platform migrated to the Azure VPS. The Hindsight daemon moved with it and kept running on the server. On the night of 20 to 21 Sep, its nightly ingest job extracted 0 items because it called a CLI command that did not exist. The daemon was also a heavy always-on process; my own notes from that time record that external daemons using more than 1 GB of RAM caused gateway stalls. On 22 Sep 2026 I looked for alternatives, listed the practical disadvantages, and removed Hindsight. Production memory uses the five structured layers described above: built-in curated Markdown with hard character caps, a knowledge base of plain files, and LCM-X on SQLite for compressed history recall. No extra daemon, no RAM cost, and the memory files are readable and editable by hand.
| Attribute | Laptop prototype (11 to 20 Sep 2026) | Azure VPS production (Current) |
|---|---|---|
| Historical recall | Local vector embeddings | LCM-X on SQLite WAL with FTS5 keyword indexing |
| Persistent memory | Hindsight API | Curated Markdown files with strict character caps |
| Deployment status | Ran on laptop, then on Azure VPS; removed around 22 Sep 2026 | Active production system |
Key design decisions
- Hard character caps over soft limits: Soft warnings get ignored during complex tasks. Hard limits force active consolidation before new facts are saved.
- Plain Markdown over key-value databases: Human-readable, diffable, and directly editable with any standard text editor.
- SQLite WAL over append-only JSONL files: Transactional safety, non-blocking concurrent reads, and built-in FTS5 search in a single file.
- Exact keyword search over vector embeddings: Most developer and agent lookups require exact file paths, error codes, and entity names, where keyword search provides zero-hallucination precision.
- Preserving raw evidence: Summaries represent compact interpretations. The underlying source messages remain the ground truth evidence.
Failure modes and automated recovery
| Failure condition | Detection mechanism | Automated recovery path |
|---|---|---|
| Write exceeds L3 character cap | Memory tool enforces hard boundary | Rejects write and prompts consolidation |
| Incorrect fact added to memory | Curator audit and ledger tracking | Restore previous snapshot or mark with tombstone |
| Summary lacks needed detail | Summary lists covered store_ids | lcm_expand retrieves full original turns |
| Dangling reference in summary DAG | Automated integrity build query | Page reports count; builds flag inconsistencies |
| Knowledge file drift | Daily md_guard.py scan | Alerts on misplaced content across topic files |
Explore the platform
See how memory connects with the rest of the multi-agent operations platform
Stack
Hermes Agent · LCM-X · SQLite WAL · FTS5 · Python · Markdown