The Two-Tier Model: Session and Persistent

+15 Mana ✨

Introduction

Most "agent memory" confusion collapses the moment you draw a single line. On one side: the running conversation, which the model can read directly because it is in the prompt. On the other side: durable notes that survive after you close the terminal. Hermes calls these tiers session memory and persistent memory, and almost every memory decision (compression, retrieval, write triggers) follows from knowing which tier a piece of information belongs to.

Key Concepts

  • Session memory: The conversation buffer the model sees on every turn. It is in-prompt, volatile, and capped by the model's context window.
  • Persistent memory: Hermes-managed Markdown files (MEMORY.md, USER.md) stored in ~/.hermes/memories/. They survive across sessions.
  • System prompt injection: Persistent memory is read once at session start and pasted into the system prompt as a frozen snapshot.
  • Two-tier separation: Session memory holds what we just said. Persistent memory holds what we always know about this user and environment.

Real World Context

Without the two-tier split, every new session feels like meeting a stranger. A developer who sets up their workflow once ("I use pnpm, not npm; my repo lives in ~/code/api") wants the next session to start with that context already loaded. Persistent memory makes that automatic. Meanwhile, the messy back-and-forth of this debug session (failed attempts, dead-end ideas) should not pollute future sessions. Keeping it in session memory means it disappears when the session ends.

Deep Dive

Hermes draws a strict boundary between the two tiers:

text
┌──────────────────────────────────────────────────────────┐
│  System prompt (built at session start)                  │
│   ├── SOUL.md          (personality, from HERMES_HOME)   │
│   ├── MEMORY.md        (frozen snapshot, ~/.hermes/...)  │
│   ├── USER.md          (frozen snapshot, ~/.hermes/...)  │
│   └── Project context  (AGENTS.md / CLAUDE.md / .hermes) │
├──────────────────────────────────────────────────────────┤
│  Conversation turns (session memory, mutable)            │
│   ├── user message 1                                     │
│   ├── assistant message 1 (with tool calls)              │
│   ├── user message 2                                     │
│   └── ...                                                │
└──────────────────────────────────────────────────────────┘

Notice two design choices that follow from the diagram:

  1. The persistent files are loaded once, not on every turn. That keeps the LLM prefix cache stable, which is what makes long sessions affordable. If the agent edits MEMORY.md mid-session, the file on disk updates immediately, but the system prompt does not re-read it until the next launch.
  2. Session memory is where compression happens. Persistent memory does not get compressed because it is not the thing growing. The conversation buffer is.

This is the mental model to keep: persistent memory is the frozen part of the prompt, session memory is the flowing part.

Common Pitfalls

  1. Expecting MEMORY.md edits to apply instantly: They write to disk immediately but the model sees them at the next session start, not mid-conversation.
  2. Storing temporary debugging notes in persistent memory: "Trying approach X for ticket 1234" belongs in session memory or a scratch file, not in your durable profile.

Best Practices

  1. Think "frozen vs flowing" before writing: If the fact is true across sessions, persist it. If it is only true today, leave it in the conversation.
  2. Treat persistent memory as identity, not transcript: It is for who you are and how you work, not for what just happened.

Summary

  • Hermes splits memory into two tiers: session (in-prompt, volatile) and persistent (on-disk, durable).
  • Persistent files live in ~/.hermes/memories/ and inject as a frozen snapshot at session start.
  • The two tiers exist to keep the LLM prefix cache stable and to separate identity from transcript.
  • Almost every memory feature (compression, retrieval, write rules) is downstream of this split.

Code Examples

bash
# Inspect the two persistent memory files
ls -la ~/.hermes/memories/
# -rw-r--r--  USER.md      ← profile (~1375 char limit)
# -rw-r--r--  MEMORY.md    ← environment facts (~2200 char limit)

# Both files are loaded into the system prompt at session start
hermes
# > /status   ← shows tokens used, including the memory injection
✓ Completed