Start with an ordinary coding session. You ask an agent to change a repository. It reads the README and project rules, searches the code, edits files, and runs tests. A test fails, so it inspects the log, adds an edge case, and runs again. In the middle you say, "For this project, do not edit generated files directly." Later you ask it to find the failed command from earlier.
For a short chat, the easy answer is to append every message to history and send the whole history back to the model. A long-running agent runs into pressure quickly: history expands, tool output overwhelms the task, user preferences get mixed with one-off failures, and different entry surfaces begin to disagree. The CLI remembers one thing, the gateway remembers another, and a cron job cannot ask the user a follow-up.
A useful first definition is that Hermes Agent is a task runtime wrapped around a model. The model decides what should happen next. Tools read files, edit code, and run commands. Hermes assembles the user's request, project rules, and tool results into work that can continue, recover, and be audited. In this article, runtime means that coordinating layer around the model and its tools.
Hermes Agent describes itself in the README feature map as a self-improving agent. It can work through terminals and messaging gateways, run scheduled jobs, delegate work, and preserve lessons from completed tasks. Those capabilities orbit one simpler question: how should an agent keep the current task, durable history, long-term knowledge, and background learning in their proper places?
Reading contract. The whole article follows one task: fix a failing test. By the end, you should be able to replay where a turn begins and ends, how the model and tools hand work back and forth, why the durable record differs from the model's working copy, and which handoffs the next six articles will examine in detail.
Evidence boundary. This article uses the public README, configuration, and a fixed source
snapshot. Direct claims come from linked source. Design intent is inferred only where call chains, data
shapes, or comments support it. README is the map; source is the mechanism. For example, the visible
session_search path uses SQLite/FTS5 and returns real message windows without another LLM call
inside the tool.
We will not begin with "self-evolution." This article follows one instruction through its different locations and replays a complete turn; later chapters separate standing rules, history, and background learning. Once that route connects, "self-evolving" stops sounding like a vague slogan. It becomes a state discipline: deliver the current task first, write reusable material into the right ledger afterward, and let future turns retrieve it according to source, lifetime, and risk.
1. Why one sentence has to pass through four places
Keep following the sentence from the opening: "Do not edit generated files in this repository." It looks like one user message. For an agent to use it correctly, however, the sentence has to pass through four places. Ignore the source names for a moment and watch the job it performs in each place.
The first place is the door. The sentence may arrive from a terminal, a gateway, or a scheduled job. The door receives the task and hands it to the shared turn lifecycle. If every entry point assembles its own rules and stores its own history, one agent soon behaves like several unrelated assistants.
The second place is the workbench for this turn. Before calling the model, the runtime combines the user's words with project rules, available tools, and material recalled for this task. The model needs to see "do not edit generated files" and may also need a list of files produced by the generator. That list is temporary runtime context; it must not masquerade as something the user said.
The third place is the record. The original user message, the answer, and the actual tool calls and results are stored in order. If the user later asks what they said, the system should recover evidence rather than a model's paraphrase. This record also has to be written early instead of waiting for the whole task to succeed.
The fourth place is experience for future tasks. Only after delivery may a background path decide whether the sentence expresses a stable preference worth preserving. If it was a one-off constraint, that path may write nothing. Receiving a sentence, showing it to the model now, preserving that it happened, and deciding whether to reuse it later are connected steps, but they are not one operation.
Now the source vocabulary has a concrete hook. The door is an entry surface; the workbench
is the model view; the record is the real transcript; post-delivery
distillation happens in background review, whose result may enter durable state.
AIAgent sits between them because every entry point returns
to one turn lifecycle instead of maintaining a separate brain.
| Surface | Role in the example | Typical failure |
|---|---|---|
| Entry surface | Receive the instruction from a terminal, gateway, scheduled job, or delegated task. | Each entry builds context differently and behavior diverges. |
| Model view | Assemble the user's words, rules, tools, and temporary context into a working copy. | Transient recall leaks into stable prompt and breaks cache discipline. |
| Real transcript | Store the original message, answer, tool calls, and tool results in order. | Summaries replace raw evidence, making later recovery brittle. |
| Background review | Decide after delivery which facts or procedures deserve reuse in future tasks. | Preferences, evidence, and procedures collapse into one vague memory. |
The table is only a compact replay. It separates preserving raw evidence from distilling future experience; the next article will place those responsibilities in SessionDB, Memory, and Skills. In the opening figure, direction matters more than node count: entry points do not write long-term knowledge directly, and background review does not compete with the foreground answer.
2. Walk one repair task through a complete turn
Now run the task from the opening. You say, "Fix this failing test." Hermes eventually answers, "I changed two files and the test now passes." Everything from receiving the user message to delivering that answer is one turn. A turn is not one model call. The model may first request files, inspect their contents, request an edit, run a test, and react to another failure. Hermes owns that whole lifecycle rather than any single decision inside it.
A naive implementation saves history only after everything succeeds. A model error, stuck tool, or process exit can then erase the turn. Hermes instead makes four stages visible: receive and preserve the task, prepare what the model should see, let the model and tools hand work back and forth, then deliver the answer and distribute state. Follow them in order.
2.1 Receive the task: build the workbench and preserve the request
When the message arrives, Hermes first creates a workbench for this turn. It restores the prior session, identifies project rules and available tools, assigns turn identifiers, and persists the user's original words early. If a later model call fails, the system still knows what the user requested and where recovery should begin.
The source names now have a job to attach to. The foreground entry is
run_conversation,
and per-turn setup lives in build_turn_context. Its
TurnContext
carries the messages, standing prompt, identifiers, and prefetched context used later in the turn. The
_persist_session path
means that a successful answer is not a prerequisite for preserving the request.
2.2 Prepare the first model call: copy a working view from the record
The durable record is not identical to what the model needs for its next decision. The record should keep the user's words and events that really occurred. For this repair, however, the model may temporarily need a list of generated files or plugin-supplied project guidance. Hermes copies the real messages into a working view and attaches that temporary material to the copy.
That working copy is the model view; the durable record is the transcript.
Before a provider call, Hermes copies messages and adds external recall and plugin context only to the API
copy of the current user message. It leaves the original list unchanged. The transition is visible in
compose_user_api_content.
Without the copy, a later turn could not reliably distinguish user evidence from temporary runtime help.
2.3 Let the model and tools hand work back and forth
Only now does Hermes call the model. The model does not directly open a file or run a test; it returns a request naming a tool and its arguments. Hermes checks and executes that request, appends either the result or the error to the turn in order, and gives the updated working view back to the model. The model then chooses again: request another tool, or produce the final answer when it has enough evidence.
A turn therefore contains a smaller loop that may repeat several times. The source loop begins at the
turn budget and while condition.
The tool layer executes calls and returns results in the model's original order, an invariant stated in
tool_executor.py.
In the running example, the exchange reads naturally:
User: Fix this failing test
Hermes: Preserve the request and prepare project rules and tools
Model: Read the test and the related implementation
Hermes: Run the read tools and append their results
Model: Edit the implementation and run the test
Hermes: Run the tools and append success or failure
Model: The evidence is sufficient; return the final answer
2.4 After delivery: the finalizer distributes state
When the model returns a final answer, foreground work can be delivered, but Hermes still has to close the turn. It confirms the response, assembles the real message record, synchronizes external state, and checks whether background review is due. This owner is the finalizer. If review starts, it runs from a message snapshot after delivery and cannot revise the answer the user already received.
The last two actions are different. Synchronizing stores sends the completed turn to session storage or an external memory provider so it can later be recovered and searched. Starting review opens a separate background path that asks whether any experience deserves long-term reuse, and that path may write nothing. One preserves what happened; the other filters what might help in the future.
The complete replay is now short: receive and preserve the request → assemble the model's working
view → iterate between model and tools → deliver the final answer → synchronize state and conditionally
review. The next six chapters enlarge one handoff at a time. Chapter two separates the system
prompt, Context, Memory, SessionDB, and Skills. Chapter three follows review, nudges, and Curator after
delivery. Chapter four follows /learn into a saved Skill. Only then do the last three chapters
introduce evaluation data, GEPA, and the adoption gate. With the complete turn in view, those source names
arrive as answers to known questions instead of as a vocabulary list.
3. Tool calls are not the model's private business
Tool calling can look like "the model asks for a tool and the tool runs." Hermes puts more runtime around
that moment. The executor separates concurrent and sequential paths; the concurrent path preserves original
tool-call order while appending results, and the sequential path handles stricter interaction cases. The
relevant code starts around
execute_tool_calls_concurrent
and
the sequential path.
The more important boundary is runtime-owned dispatch. session_search needs SessionDB,
memory needs the built-in memory store and external-provider sync, and
delegate_task needs the agent's delegation dispatcher. That dispatch is visible in
tool_executor.py.
Remove middleware, timing, and display concerns, and the ownership boundary becomes visible:
if function_name == "session_search":
db = agent._get_session_db_for_recall()
result = session_search(..., db=db)
elif function_name == "memory":
result = memory_tool(..., store=agent._memory_store)
elif function_name == "delegate_task":
result = agent._dispatch_delegate_task(function_args)
The model supplies only function_name and arguments. The current session database, authoritative
memory store, and parent task's delegation dispatcher are bound at execution time. A syntactically valid
model request therefore cannot choose another history ledger or another user's durable state.
The model may request a tool, but the state boundary, audit trail, permission shape, and recovery semantics belong to the runtime. Without that split, a temporary observation could become long-term memory, a search could guess at past history instead of reading evidence, and delegated work could contaminate the parent context.
4. Multiple entry surfaces share the core, but not every permission
Hermes is not only a CLI. The source also includes gateway, cron, and delegation paths. If each entry surface owned its own agent loop, state discipline would fragment. Hermes instead routes them toward the same core while narrowing each surface's permissions.
4.1 Gateway turns platform context into prompt boundaries
Gateway has to carry platform details such as channel, user, thread, attachments, and response routing.
SessionContext stores per-session state for that surface; see
gateway/session.py.
Gateway should not become a separate agent. It should translate platform context into the boundaries the
core runtime already understands.
4.2 Cron narrows tools because no one is there to answer
Cron is non-interactive. It cannot rely on clarification, chat repair, or a human watching every tool
prompt. The scheduler defines a narrower default toolset in
cron/scheduler.py,
excluding interaction-heavy tools such as clarify and send_message. That is not a
convenience choice. It is the runtime acknowledging that non-interactive work needs a smaller permission
surface.
4.3 Delegation isolates exploration and returns a result
Delegation solves a different context pressure: the parent agent should not absorb every exploratory
detail. delegate_task states that child agents have isolated context, restricted toolsets, and
their own terminal sessions. The parent blocks until completion, but it receives the delegation call and
summary result, not the child's full intermediate reasoning and tool stream; see
delegate_tool.py.
Child agents are also restricted by default. DELEGATE_BLOCKED_TOOLS blocks tools such as
delegate_task, clarify, memory, send_message, and
execute_code; see
DELEGATE_BLOCKED_TOOLS.
The subagent construction also uses skip_context_files=True, skip_memory=True, and
an independent iteration budget; see
child role, toolset, and AIAgent construction.
5. Return to the practical question: where should information live?
The opening scenario now has a concrete answer. A user preference, a failed command, a long tool output, a reusable process, and a temporary task state are not all "memory." Hermes first classifies the information, then decides which ledger owns it and when the model should see it again.
| Information | Home | Reason | If misplaced |
|---|---|---|---|
| Long-term user preference or small environment fact | Memory | Small, stable, auditable, and suitable for a session snapshot. | If left only in transcript, it may be hard to find later. |
| Past tool output or full conversation evidence | SessionDB / session_search | The real message window matters more than a summary. | If written to memory, one-time evidence becomes a fake rule. |
| Reusable method for future tasks | Skills | Procedural memory needs an index, body, and patch semantics. | If written as memory, the model gets a conclusion but not a process. |
| Current task progress, temporary failures, exploration | Transcript only | Useful for recovery, but not stable enough to harden. | If saved too early, future tasks inherit false constraints. |
5.1 Four common misreadings
First, memory is not the home for all history. Memory has budgets, scans, frozen snapshots, and manual semantics. Session search is the path for real past evidence.
Second, skills are not "one experience note per task." The skill system emphasizes class-level workflows, patching existing skills, and support files.
Third, background review is not part of the main answer. The finalizer placement shows it happens after final response. Gateway also queues review summaries after delivery.
Fourth, cron is not ordinary chat automation. Cron narrows interactive tools, assembles prompt context differently, and supports a no-agent script path. Non-interactive entry surfaces need stricter defaults.
6. Conclusion: self-evolution is state discipline, not the word "reflection"
The value in Hermes Agent's source is not the number of feature names attached to "self-evolving." It is the way the runtime separates the state boundaries that long-running agents usually blur: current turn, model view, durable transcript, small facts, searchable history, procedural skills, background review, idle curator, and entry-surface policy.
A reader new to Hermes only needs to keep one sentence: an agent's long-term capability is not remembering everything, but knowing when each kind of information should appear, in which view, and whether it should be written down after the turn ends.
Facts should be small
and auditable.
Evidence stays in transcript.
Workflows become skills.
Current-turn recall does not
pollute the stable prompt.
Background learning happens
after response delivery.
That is the reusable lesson: do not keep stretching one giant prompt. Assign every state an owner, a lifetime, and a recovery path. The hard part of a long-running agent is the boundary between those lifetimes.
Before asking how to improve a Skill, however, we need a more basic distinction: why should a user preference, a project rule, historical evidence, and a reusable procedure not all become "memory"? The next article keeps the same repair task and places the system prompt, Context, Memory, SessionDB, and Skills back under their real owners. Evolution can only be precise after we know which object is actually changing.
Source References
- Fixed source snapshot: NousResearch/hermes-agent
- README feature map
- run_conversation entry
- TurnContext and turn prologue
- concurrent execution and ordered results
- runtime-owned tool dispatch
- finalizer state sync and review trigger
- gateway SessionContext
- cron toolset boundary
- delegation architecture note