Skip to main content
What this unit solvesHermes-Agent is an open-source AI agent framework maintained by Nous Research, positioned as “the agent that grows with you.” It is not tied to any inference backend and does not require the Hermes model family. A set of Markdown files defines the agent’s persona, memory, and instructions, and a three-layer system prompt assembly injects those files in a disciplined way. This unit dissects its origins, core technology, system structure, and Markdown file design so you can see the deliberate choices and trade-offs behind the “minimalist shell.”

Learning objectives

  • Explain Hermes-Agent’s origins and positioning: it is an agent framework, not an inference model, maintained by Nous Research under the MIT license
  • Describe its core architecture: the AIAgent main loop, three-layer system prompt assembly, multi-backend tool dispatch, and SQLite state storage
  • State the role of SOUL.md, MEMORY.md, USER.md, and AGENTS.md in prompt assembly — their layers and responsibilities
  • Identify the trade-offs of the minimalist Markdown file design: easy to understand and externalize, but lacking structured version control under high concurrency or multi-agent scenarios
  • Summarize the essence of this system in one everyday analogy
  • Compare it directly against 05-1 OpenClaw’s multi-file design

1. Origins and positioning

Hermes-Agent is open-sourced and maintained by Nous Research, positioned as “The agent that grows with you” (official repository [1] as of 2026-05). It is a new framework developed independently by Nous Research — not derived from OpenClaw. The hermes claw migrate command is a migration tool for existing OpenClaw users to move their configuration, memory, and skills; the two are independent projects from different organizations (official documentation [2] as of 2026-05). A few common misconceptions to clear up first:
  • It is not the Hermes model family. Hermes-3-405B, Hermes-3-70B, and similar models are open-source LLMs trained by Nous Research. They are separate products from the Hermes-Agent framework. Hermes-Agent is not bound to any inference backend; it supports OpenRouter, Anthropic, OpenAI, Google, vLLM, llama.cpp, and any other OpenAI-compatible API. The Hermes models are simply Nous Portal’s default preferred endpoint.
  • It is not a lightweight SDK. Despite the clean Markdown file interface, it is positioned as a full-featured agentic harness that “can run on a $5 VPS or a GPU cluster and interact across Telegram, Discord, and other platforms.” It ships with sub-agent delegation, SQLite state storage, and cross-session memory.
  • The license is MIT (as of 2026-05, per the repository LICENSE file): commercial use, modification, and closed-source redistribution are all permitted.
Naming clarificationIn Nous Research’s naming scheme, “Hermes” refers to three distinct things simultaneously: the Hermes model family (LLM), Hermes-Agent (the agent framework), and Nous Portal (the inference subscription service). This unit covers the second. The full name “Hermes-Agent” is used whenever confusion is possible.

2. Core technology

Hermes-Agent’s technology stack can be broken into five axes: Compared to OpenClaw’s “many Markdown files plus multi-channel routing” design, Hermes-Agent’s minimalism shows in three places:
  1. Prompt assembly is three layers, not scattered ad hoc. agent/prompt_builder.py assembles the stable / context / volatile layers into a system prompt, with explicit slot numbers and injection strategies for each layer.
  2. Inference backend is fully pluggable. Any service that accepts an OpenAI-compatible API can be connected — a deliberate choice for “no single-vendor lock-in.”
  3. State is SQLite, not plain files. OpenClaw’s memory relies mainly on MEMORY.md + memory/YYYY-MM-DD.md; Hermes-Agent adds a SQLite + FTS5 layer supporting cross-session full-text search and LLM-summary recall.
Why three-layer prompt assemblySplitting the prompt into layers rather than writing one large block is motivated by the different “rate of change” and “cache hit requirements” of each layer: the stable layer (persona) almost never changes and has the highest prefix cache hit rate; the context layer (project instructions) changes with CWD; the volatile layer (user and memory) is re-fetched each session. Layering means only the parts that changed need to be re-fetched. Hermes-Agent further “freezes” the volatile layer into a snapshot at session start — memory operations during the session only write to disk and take effect in the next session (Prompt Assembly documentation [3] as of 2026-05). The trade-off of this design is discussed in Section 4.

2.5 Why it can “grow with you”: the agent curates its own memory and re-injects it next session

The “grows with you” mechanism is not background auto-summarization. It is the agent actively curating its own memory (Memory documentation [4] as of 2026-06). Unpacked:
  1. Two capped memory files: MEMORY.md (2,200 character limit, roughly 800 tokens) records “environmental facts, conventions, and things learned”; USER.md (1,375 character limit, roughly 500 tokens) records “your preferences, communication style, and expectations.” Both live in ~/.hermes/memories/.
  2. Written by the agent itself via the memory tool: there is no background process auto-distilling content. The agent judges during interaction that “this is worth remembering” and actively adds, replaces, or removes entries in the two files above. The character limit is a key design choice: it forces the agent to select and consolidate rather than accumulate indefinitely, so “growth” is curated compression, not a running log.
  3. Re-injected at the next session: at session start, both files are frozen into a snapshot and injected into the volatile layer (see the three-layer assembly above). The agent then opens with “what I remembered about you and this work last time,” producing more contextually appropriate behavior.
A separate SQLite + FTS5 complete history (~/.hermes/state.db) stores all CLI and messaging sessions and can be queried with the session_search tool to retrieve past raw messages. Note that this and the “active memory” above are two independent systems: SQLite is a searchable detailed log; MEMORY.md and USER.md are the agent’s curated long-term notes. The former does not automatically distill into the latter. Key inference: growth happens between sessions, not within them — a direct consequence of volatile freezing. One session is “read last session’s memory, do work, write what’s worth keeping to disk”; repeat next time. This also explains why SOUL.md (persona) stays constant while MEMORY.md and USER.md (learning) grow: persona is a constant you define upfront; growth only occurs in the memory layer. Memory is one arm of growth. The other is skill self-evolution: the agent can write its own skills, and curator.py maintains the lifecycle of these “agent-authored skills” in the background, tracking usage frequency and transitioning rarely-used skills from active to stale (default 30 days) then to archived (sealed at 90 days). It periodically dispatches a helper model to review, proposing consolidations of overlapping skills or repairs for drifted ones. It only touches agent-authored skills, never repository-built-in or hub-installed skills, and never auto-deletes anything — the worst outcome is reversible archival (Curator documentation [5] as of 2026-06). So “growth” has two tracks: the memory layer (facts about you and the work) and the skill layer (capabilities the agent accumulates and rotates on its own).
Difference from OpenClaw’s growth mechanismBoth rely on the agent actively writing memory files to grow. Hermes-Agent’s memory files have character limits that enforce consolidation, and there is a complete SQLite + FTS5 history for searchable recall. The difference is in “strictness of curation” and “depth of recallability,” not in the degree of automation.

3. System structure

Hermes-Agent has four entry points, each serving a different context:
hermes-agent/
cli.py · CLI entry point (hermes command)
run_agent.py · AIAgent main loop
hermes_state.py · SQLite state database
model_tools.py · tool discovery and dispatch
toolsets.py · 28 toolset groups
gateway/
run.py · Gateway entry point (multi-channel persistent connection)
agent/
prompt_builder.py · three-layer system prompt assembly
system_prompt.py · slot definitions per layer
memory_manager.py · memory management
curator.py · background lifecycle maintenance for agent-authored skills
skills/
SKILL.md · skill format definition
adapters/
· third-party integrations (Telegram, Discord, ACP, etc.)
Core components and responsibilities: Sub-agent delegation is triggered via the delegate_task tool: 3 concurrent sub-agents by default, each receiving an independent context and terminal session (official documentation [2] as of 2026-05). Six terminal backends are available — local, Docker, SSH, Singularity, Modal, Daytona — providing flexibility from “run directly on local machine” to “isolated cloud environment.”
A typical agent turn, step by step
1

User sends a message on Telegram

The Telegram adapter receives the message and passes it to the Gateway.
2

Gateway finds the corresponding session

The message is passed to AIAgent.
3

AIAgent calls prompt_builder to assemble the three-layer prompt

Fetches SOUL.md (stable) + AGENTS.md (context, walking up from CWD to git root) + MEMORY.md + USER.md (volatile, from the SQLite frozen snapshot).
4

Assembled prompt is sent to the model

The model response may contain a tool_call; model_tools dispatches based on model and tool configuration, possibly calling delegate_task to spawn sub-agents.
5

Sub-agents return results

The main agent consolidates and replies on Telegram; state is written back to SQLite.
Every link in this chain can be replaced or disabled. That is the real meaning of “minimalist shell”: the core skeleton is not complex, but every junction is exposed as configurable.

User-side configuration directory: ~/.hermes/

The hermes-agent/ structure above is the source code layout (the developer’s view). What you actually edit day-to-day is a different tree: the runtime configuration directory HERMES_HOME, defaulting to ~/.hermes/ on Linux, macOS, and WSL2 (%LOCALAPPDATA%\hermes\ on Windows native). It supports profiles, with each isolated instance having its own HERMES_HOME (Configuration documentation [6] as of 2026-06).
~/.hermes/
config.yaml · main configuration (non-secret): model, terminal, memory limits, compression, security
.env · secrets: API keys, platform tokens, passwords
auth.json · OAuth credentials
SOUL.md · agent persona (system prompt stable slot #1)
memories/
MEMORY.md · cross-session memory, 2,200 character limit
USER.md · user preferences, 1,375 character limit
skills/
· agent-authored skills (lifecycle managed by curator)
cron/
· scheduled tasks
sessions/
· Gateway conversation state
logs/
agent.log · errors.log · gateway.log
state.db · SQLite + FTS5 complete history
The core split in configuration is two layers: config.yaml (non-secret, can go into version control) and .env (secret, never into version control). config.yaml references .env environment variables with ${VAR_NAME} syntax — API keys stay out of config.yaml. The repository ships a cli-config.yaml.example at the root with full inline comments as a starting template. Selected key fields (as of 2026-06):
.env and state.db must never enter a public repositoryconfig.yaml is designed to go into version control as non-secret configuration. But .env (API keys, platform tokens) and state.db (containing all raw conversation content) become a credentials leak and privacy incident the moment they enter a public repo. Add ~/.hermes/.env, ~/.hermes/state.db, and ~/.hermes/auth.json to .gitignore; commit only config.yaml and cli-config.yaml.example.

4. Custom Markdown files: the role of SOUL.md and others

Hermes-Agent’s Markdown file list is leaner than OpenClaw’s, but each file maps to a specific slot in the prompt assembly. The list and responsibilities below come from the three-layer assembly order in agent/system_prompt.py (Prompt Assembly documentation [3] as of 2026-05): Several key design points:
  • SOUL.md is only loaded from HERMES_HOME, independent of CWD. This ensures the persona stays stable across projects: the persona you wrote for project A cannot be overwritten by project B’s AGENTS.md.
  • The default SOUL.md is auto-planted: on first launch, hermes_cli/default_soul.py writes a short identity declaration. Read that default before editing it — then you know “if I delete this entire block, what happens.”
  • Volatile layer frozen snapshot: at session start, the contents of MEMORY.md and USER.md are frozen into a snapshot and injected into the system prompt. Memory operations during the session only write to disk; they take effect in the next session. This design preserves LLM prefix cache stability (the prompt prefix does not change within a session), at the cost of “in-session self-improvement is not visible until the next round.”
  • Sub-agent delegation exception: when delegate_task launches a sub-agent (skip_context_files), SOUL.md is not loaded; the hardcoded DEFAULT_AGENT_IDENTITY is used instead. Sub-agents do not inherit the main persona — this is the design choice that enables “different personas for different tasks.”
The cost of volatile freezingChanges you make to MEMORY.md mid-session will not be read back by the current session. If you expect “I say one thing, it remembers it, and uses it in the very next turn,” you will be disappointed. Think of it as “writing in your diary each evening and reading it only when you wake up.”
Comparison against 05-1 OpenClaw:

5. One everyday analogy

Hermes-Agent is like an intern with a built-in “personal contract” and “morning briefing” mechanism: before leaving home each day they pull out three documents from home ($HERMES_HOME) and read them — “who I am” (SOUL.md), “what I learned yesterday” (MEMORY.md), and “what the boss prefers” (USER.md) — then walk into the office and read the project manual (AGENTS.md, found by walking up from the nearest project folder). The three documents from home do not change during the day (frozen snapshot), and any notes they take during the day go into a desk drawer that can only be read the next morning. Occasionally they delegate work to three independent assistants (sub-agents) who do not inherit the intern’s personal contract and only execute the specific tasks assigned. The person is not fixed — they are reassembled each morning; and the source for that reassembly (those three documents at home) is something you wrote for them, version-controllable.

6. Trade-offs of minimalist design

6.1 What you gain

  • Human-readable, version-controllable, portable across platforms. Everything about “who the agent is, what it should remember, how it should behave” is expressed in Markdown or diffable SQLite. No closed-source binary configuration.
  • Prefix-cache friendly. The volatile frozen snapshot keeps the prompt prefix stable within a session, lowering model costs.
  • No vendor lock-in. Any OpenAI-compatible API works — a real strategic option in 2026’s fast-shifting provider landscape.
  • Progressive skill disclosure. Level 0 only loads the skills index (roughly 3k tokens); Level 1 loads full skill content. This is cost control for “many skills installed but not all used in every session.”

6.2 What you pay

  • Plain-text format lacks structured schema validation. Markdown files have no type checking; personality drift is hard to quantify. How do you know three rounds of edits to SOUL.md haven’t pushed the tone away from the original design?
  • Volatile freezing makes in-session memory changes take effect with a delay. This creates friction relative to the intuition of real-time awareness.
  • Persona differentiation in multi-agent scenarios: sub-agents use hardcoded DEFAULT_AGENT_IDENTITY, but how do you inject different personas into different sub-agents? Official documentation does not describe a SOUL.md override mechanism for sub-agents.
  • SQLite is single-machine storage. If you want to sync session history across multiple machines, you need to add a sync layer yourself (filesystem watcher, Syncthing, or a self-hosted S3-compatible layer).
When to choose Hermes-Agent over OpenClaw
  • Your workflow is “one daemon serving the same me across multiple channels”: choose Hermes-Agent — the minimalist design fits exactly.
  • Your workflow is “one daemon running multiple independent-persona agents each serving different scenarios”: choose OpenClaw — its multi-channel routing and isolated session design fits better.
  • Your workflow is “personal local experimentation, no enterprise hardening needed”: either works — pick based on your Python vs. TypeScript preference.
  • Your workflow is “going to production / enterprise environment”: neither is sufficient on its own; stack 05-3 NemoClaw’s hardening shell on top.

Hands-on exercises

1

Edit SOUL.md to verify the identity slot

Replace ~/.hermes/SOUL.md with a custom persona (for example: “direct tone, conclusion first, refuses marketing speak, no emoji”), restart hermes, and observe the tone of the agent’s opening in the new session. Remember: editing SOUL.md mid-session has no effect on the current session — a restart is required.
2

Observe volatile freezing behavior

Use the hermes memory command to observe the add/remove log for MEMORY.md. Then ask the agent to remember something mid-session, and observe when it writes to disk (at session end) and when it reads back (at the start of the next session).
3

Read the prompt_builder.py source code

Clone the repository and read agent/prompt_builder.py and agent/system_prompt.py directly. Seeing “three-layer assembly” in code gives you better understanding than reading the documentation alone.

Common pitfalls

  • Assuming Hermes-Agent only works with Hermes-series models: any OpenAI-compatible API works (OpenRouter, Anthropic, OpenAI, Google, vLLM, llama.cpp, etc.)
  • Assuming editing SOUL.md takes effect immediately in the current session: a restart is required because the volatile layer is frozen into a snapshot at session start
  • Treating AGENTS.md and SOUL.md as equivalent: they belong to different prompt layers (context vs. stable) and have different scopes (CWD walk-up vs. unique HERMES_HOME)
  • Treating SQLite state as a disposable cache: SQLite contains the basis for session search and LLM-summary recall; deleting it makes “why did it do that last time” unrecoverable. Backup strategy should include the SQLite file.
  • Expecting sub-agents to have the main persona: sub-agents launched by delegate_task do not inherit SOUL.md and use DEFAULT_AGENT_IDENTITY directly. If a specific persona is needed for a sub-agent, pass the context explicitly at call time or set up a sub-agent-specific SOUL.md in advance; official documentation does not explicitly state whether native override support exists.

Self-check

The bar for passing this unit
  1. Can you draw the three-layer system prompt (stable, context, volatile) with each slot and its corresponding file?
  2. Can you explain why the volatile layer uses a frozen snapshot rather than live injection, and what the implications are for memory consistency and inference cost?
  3. Can you state the design rationale for SOUL.md being loaded exclusively from $HERMES_HOME rather than following CWD?
  4. Can you identify the differences between Hermes-Agent and 05-1 OpenClaw on three dimensions: persona file, memory storage, and heartbeat support?
  5. Is your workflow “one self serving multiple channels” or “multiple selves each serving different contexts”? Which framework does that choice point toward?

Sources and further reading

Factual claims are grounded in official documentation; fast-changing items are annotated as of 2026-05.