Persistent Memory as Cross-Session Knowledge

+15 Mana ✨

Introduction

Persistent memory is the part of Hermes that makes the second session feel different from the first. Two small Markdown files, MEMORY.md and USER.md, sit in ~/.hermes/memories/ and get pasted into every system prompt the agent builds. They are tiny on purpose: roughly 2,200 characters for MEMORY.md and 1,375 for USER.md. The cap forces the agent (and you) to keep them dense and useful.

Key Concepts

  • MEMORY.md: Environment and project facts. The agent's notes about your conventions, tools, paths, and quirks discovered while working.
  • USER.md: Your profile. Name, role, timezone, communication style, technical level.
  • Capacity limits: ~2,200 chars (MEMORY.md, roughly 800 tokens) and ~1,375 chars (USER.md, roughly 500 tokens). Configurable.
  • Substring matching: Replace and remove operations identify entries by short unique substrings, not exact text.
  • Security scanning: Entries are checked for prompt-injection and exfiltration patterns before they are accepted.

Real World Context

A freelance developer works across three client repos in a week. Without persistent memory, every session asks "what test command do you use? what is your indentation preference? do you commit on each step or batch?" With persistent memory, those answers live in USER.md once. The agent stops asking. The session starts in productive mode.

Deep Dive

Look inside a healthy MEMORY.md:

markdown
# Memory

## Environment
- macOS 14.5, fish shell, brew at /opt/homebrew, ~/.hermes config
- Primary repo: ~/code/api (Go 1.22 + sqlc + chi router)
- Test command: `make test`. CI: GitHub Actions.

## Conventions
- Prefer table-driven tests with subtests over single-case tests.
- Migrations are generated, never hand-edited.
- Pull requests use Conventional Commits in the title.

## Quirks
- The local docker-compose ports postgres at 5435, not 5432.

And a healthy USER.md:

markdown
# User

## Profile
- Olivier, senior backend engineer, Europe/Paris timezone.
- Comfortable with Go, TypeScript, Postgres internals.

## Style
- Wants short answers and code over prose.
- Comments only when the why is non-obvious.
- Confirms before destructive commands.

Notice what is not there: no "in this conversation", no transcript fragments, no scratch notes. Persistent memory is identity and environment, expressed densely. When entries grow vague ("User has a project") they get replaced with denser ones ("Primary repo: ~/code/api uses Go 1.22, sqlc, chi router, make test, GitHub Actions CI").

The agent reads and edits these files through a memory tool that supports three actions: add, replace, and remove. replace and remove accept a short unique substring; the agent does not need to quote the full entry. If the character cap is exceeded, the tool returns an error listing existing entries, prompting consolidation rather than silent truncation.

Finally, every entry passes a security scan. Patterns that look like prompt injection ("ignore previous instructions"), credential exposure, or invisible Unicode get rejected. Exact duplicates are also rejected.

Common Pitfalls

  1. Hoarding low-value entries: A near-full MEMORY.md of stale facts is worse than a half-full one of sharp facts.
  2. Storing secrets: Persistent memory is plaintext on disk. Tokens, passwords, and API keys do not belong there.

Best Practices

  1. Pack multiple related facts into one entry: "Project ~/code/api uses Go 1.22, sqlc for DB, chi router, make test, GitHub Actions CI" beats four separate entries.
  2. Curate occasionally: Open the files manually every few weeks and prune dead context. You can edit them by hand at any time.

Summary

  • Persistent memory is two tiny Markdown files in ~/.hermes/memories/.
  • MEMORY.md is for environment and project facts; USER.md is for your profile.
  • Character caps force density; entries are managed via add / replace / remove with substring matching.
  • Each entry is security-scanned before acceptance; secrets do not belong in persistent memory.

Code Examples

yaml
# ~/.hermes/config.yaml
memory:
  memory_enabled: true       # turns persistent memory on
  user_profile_enabled: true # enables USER.md profiling
  memory_char_limit: 2200    # cap for MEMORY.md
  user_char_limit: 1375      # cap for USER.md
✓ Completed