🤖HermesBlog
Hermes Official Tutorials · Part 208/9/2026

Tutorial 20: Persistent Memory — Long-Term Memory

Tutorial 20: Persistent Memory — Long-Term Memory — easy-to-understand guide based on official docs

This is part of the Hermes Agent official tutorial series. View all tutorials

Think of this feature like a sticky note on your desk: Hermes Agent writes down important things about you and your projects so it doesn’t forget them between conversations. No more repeating yourself every time you start a new chat.


Persistent memory: AI’s pocket notebook

What Does Persistent Memory Do?

Normally, an AI agent starts fresh each session — it forgets everything once the conversation ends. Persistent Memory changes that. Hermes Agent keeps two small text files on your computer. It reads them at the start of every session, so it instantly remembers your preferences, your project details, and anything else you’ve taught it.


Step 1: Know the Two Memory Files

The agent’s memory lives in two files, stored in ~/.hermes/memories/:

File What It Stores Size Limit
MEMORY.md Agent’s personal notes — environment facts, conventions, things it learned 2,200 characters (~800 tokens)
USER.md Your profile — preferences, communication style, expectations 1,375 characters (~500 tokens)

The limits are intentional. They force the agent to keep only what’s important, like a well-organized notebook rather than a messy drawer.


Step 2: See How Memory Appears in the Prompt

At the start of each session, the agent loads both files and shows them as a frozen snapshot in its system prompt. Here’s an example of what the agent “sees”:

══════════════════════════════════════════════
MEMORY (your personal notes) [67% — 1,474/2,200 chars]
══════════════════════════════════════════════
User's project is a Rust web service at ~/code/myapi using Axum + SQLx
§
This machine runs Ubuntu 22.04, has Docker and Podman installed
§
User prefers concise responses, dislikes verbose explanations

Notice the details:

  • A header showing which store it is (MEMORY or USER PROFILE)
  • Usage percentage and character counts — so the agent knows how much room is left
  • Entries separated by § (section sign)
  • Entries can be multiline

Important: This snapshot is captured once at session start and never changes mid-session. If the agent updates its memory while chatting, the changes are saved to disk immediately but won’t appear in the prompt until the next session. This keeps things fast by preserving the model’s cache.


Step 3: The Agent Manages Its Own Memory

The agent uses a tool called memory with three actions:

  • add — Add a new memory entry
  • patch — Replace one span inside an existing entry and keep the rest (old_text is the span, content its replacement)
  • remove — Delete an entry that’s no longer relevant (also uses old_text)

There’s no read action because the memory is already injected into the prompt — the agent always sees it.

Here’s a simple example of how the agent might use the tool:

memory action=add content="User prefers bullet points over paragraphs"

Or patching an old preference:

memory action=patch old_text="User prefers concise responses" content="User prefers one-line answers with emojis"

One thing to keep in mind about patch: old_text is the span inside the entry that gets replaced, and content is its replacement — the rest of the entry is kept. (A whole-entry old_text equal to the entry itself is matched exactly and wins over substring matches.)

Every tool call also requires a top-level target: "memory" for agent notes or "user" for the user profile. A batch uses that one target for every operation:

{"target": "user", "operations": [{"action": "add", "content": "User prefers metric units"}]}

Missing or null targets, and a target inside an operation that differs from the top-level one, return an error before writing or staging approval. Correct the payload and retry; use separate calls to update both stores.


Step 4: What Happens When Memory Is Full?

Memory does not auto-compact. When a write would exceed the limit, the memory tool returns an error instead of silently dropping entries — and the error tells the agent exactly how much room it needs to free:

{
  "success": false,
  "error": "Memory at 2,100/2,200 chars; adding this entry (250 chars) would exceed the limit by 153 chars. Retry as ONE 'operations' batch that removes or shortens (replace) stale entries from current_entries below to free at least 153 chars AND adds this entry — the limit is checked only on the batch result.",
  "current_entries": ["..."],
  "usage": "2,100/2,200"
}

The agent then reissues one operations batch that frees at least the stated number of characters (removes, or replaces with shorter versions) and adds the new entry. The limit is checked only on the batch’s final result, so the intermediate state never has to fit.

A patch or remove whose old_text matches no entry fails the same way, with the entries it most resembles listed under closest_entries so the agent can pick the right target.

Also note: patch is bound by the limit too. A patch that lengthens an entry can still overflow, so the new text must be shortened (or another entry removed) to fit.


Step 5: One Agent Per Hermes Home (Important!)

Don’t point two agent processes at the same Hermes home directory. Memory writes are automatic and load back into the system prompt at session start, so two writers sharing one home will compound each other’s entries into a mess neither of them authored. Memory is scoped per profile by design — give a second agent its own profile. If they need shared memory, use an external memory provider instead.


Step 6: Give Memory a Chance to Pay Off

Memory is built around session boundaries: MEMORY.md and USER.md carry the essentials into the next session, and session_search fills the gaps once the old context is gone. Inside a single session that machinery rarely runs — everything important is still in the live context.

This matters on messaging platforms (Telegram, Discord, etc.), where a chat is deliberately one continuous session that survives restarts, gateway crashes, and machine reboots. Shutting your machine down overnight does not end the session — the next message picks it up exactly where it left off. If you never reset, a chat can run for weeks as a single session: convenient, but it grows expensive, and the forget → recall from memory → search past sessions loop almost never gets to fire. Fresh memory entries also stay invisible to the running session because of the frozen snapshot above.

Practice: run /new at natural boundaries — a finished task, a change of topic, the start of a day. Each boundary is when memory pays off: the agent re-reads the updated snapshot, starts from a cheap short context, and reaches for session_search when it actually needs history. On the CLI this mostly takes care of itself (every invocation is a new session); on gateways the boundary is yours to create.


Step 7: Troubleshooting “I Told It to Remember, and the Next Session It Forgot”

The most common report looks like this: you tell the agent where something lives (an Obsidian vault, a project directory, a server), it answers “Done, I’ll remember that”, and a fresh session has no idea what you mean. Work through these in order — the first one explains the large majority of cases.

  1. Check whether the write actually happened. Memory only persists when the model calls the memory tool; a sentence like “I’ve added that to my memory” is just text. Open the file and look for the entry:

    cat ~/.hermes/memories/MEMORY.md
    cat ~/.hermes/memories/USER.md

    If the fact is not there, the model claimed a save it never made. Small local models (roughly under 30B parameters) and models with weak tool-calling do this often — they produce the confirmation without the tool call. Ask explicitly (“use the memory tool to save the vault path /srv/vault”) and confirm the entry landed in the file. If it keeps happening, the fix is a stronger model for setup, not more instructions; once the entries exist, a smaller model reads them fine because they arrive in the system prompt.

  2. Check the write wasn’t staged. With write_approval: true, writes outside the interactive CLI are held for review and never reach the file until approved — run /memory pending and /memory approve all. See Controlling memory writes.

  3. Check you are reading the same memory you wrote. Memory is per profile: hermes -p work (or work chat / work gateway start) reads ~/.hermes/profiles/work/memories/, not ~/.hermes/memories/. A CLI session in the default profile and a Telegram bot on another profile do not share notes. hermes profile list shows what exists.

  4. Check memory is enabled. memory.memory_enabled: false (or memory under agent.disabled_toolsets) removes the tool entirely — the model cannot save anything, whatever it says. See Configuration.

  5. Remember the snapshot is frozen at session start. A fact saved in the current session is visible to the next session, not to another session that was already running. Start a new session (/new, or a fresh CLI invocation) after the write.

Two things that do not make the agent remember: variables in .env (those are credentials and settings, not memory) and facts mentioned in passing without asking for them to be saved. For a location the agent needs on every run of a recurring task, a skill is often the better home than a memory entry — it loads only when relevant and does not compete for the 2,200-character budget.

A couple of extra details worth knowing: hermes journey list lists node ids — skill names and memory:<source>:<index>:<fingerprint> ids for memory chunks (pass one back exactly as printed). And a staged patch or remove (the background review stages these even with the gate off) records the full entry it targets, and /memory pending shows it. Approval applies to exactly that entry: if it changed after the write was staged, the write is refused and stays pending for you to reject. A patch/remove staged before this pinning existed has no verifiable target and is refused too: reject it and recreate the change. /memory approve lists the full text of every entry it overwrote or removed.


Step 8: Going Beyond MEMORY.md and USER.md

The two files above are deliberately small. When you need deeper, persistent memory that goes beyond them, Hermes ships with 2 external memory provider plugins — RetainDB and ByteRover — and more, such as Honcho, Hindsight, Supermemory, Mem0, OpenViking and Holographic, are available from the plugin catalog via hermes plugins install <name>.

External providers return their full prefetched context by default, up to a safety ceiling of 10× hooks.output_spill.max_chars (at least 100,000 characters); recall above that still spills so a runaway provider can’t overflow the context window. If you want oversized recall replaced with a head/tail preview plus a file path instead, set memory.prefetch_spill_enabled: true — but note the relevance-ranked middle is then no longer immediately visible to the model, so prefer your provider’s own recall budget when it has one. Settings are captured at provider registration, so restart Hermes after changing them.


Summary

Persistent Memory gives Hermes Agent a simple, bounded way to remember you across sessions. Two small files — MEMORY.md and USER.md — hold curated notes, injected as a frozen snapshot at session start. The agent manages these files itself using the memory tool, and character limits keep things focused. When you need more than those two files can hold, external memory provider plugins pick up the slack. Just remember: one agent per home directory, reset sessions at natural boundaries, and the snapshot only updates at session start.

Next up: Tutorial 21 — Scheduled Tasks: setting up automations that run themselves on a timer.

📖 Official Docs

This article is based on the official Hermes Agent documentation:Official docs › user-guide/features/memory