1. Why runtime self-evolution must happen after delivery

After turns, ledgers, and tool ownership are clear, "self-evolving" becomes concrete. It should not mean that the model reflects while answering, or that every turn is summarized into long-term knowledge. Both designs are risky: the foreground task is delayed, and temporary trial paths can harden into future rules.

What is a nudge? The ordinary word means a gentle push. In Hermes it is closer to a due reminder: runtime counters track elapsed user turns or tool-call iterations, and reaching a configured interval only sets the corresponding review flag to true. A nudge does not inject text into the user message, call a model immediately, or mean that a memory or skill has already been created. It tells the finalizer, "after this turn is safely delivered, a review may be worth scheduling."

The opening figure deliberately draws three clocks. The first stops at "Final answer: delivered." The second can enter the Finalizer gate only through after answer. The third wakes Curator through its own schedule gate. Section 2 asks when turn review may start, Section 3 asks what its fork may see and change, and Section 4 asks who maintains the library after many turns.

Use the coding-session example again. The agent finds a fixed project command, learns your commit preference, and also tries several paths that turn out to be wrong. The test log belongs in SessionDB. A repeatable project command may become a skill. A stable preference may become memory. The failed detours should usually remain transcript only.

Hermes implements self-evolution as a controlled write after delivery. The foreground turn produces the final answer. The finalizer checks whether review is allowed. A background review fork may look at the completed turn snapshot. That fork can only call memory and skill-management tools. Successful writes land in their stores, and later turns use them through the normal Memory and Skills paths. The already-delivered answer is not rewritten.

Step What happens Why this shape matters
1. Deliver first The foreground turn finishes tool calls and returns a final answer. The user is waiting for the task result, not for self-summary.
2. Check after The finalizer checks final response, interrupt status, and whether the Memory or Skill due reminder has fired. Failed or interrupted turns do not become long-term lessons by accident.
3. Fork review Background review receives the completed messages snapshot and forks a restricted AIAgent. It can inspect user messages, assistant output, tool calls, and tool results without taking over the foreground turn.
4. Narrow writes The review fork can only use memory and skill tools; external memory providers are skipped. Self-evolution can write ledgers, but it cannot become another environment-acting agent.
5. Affect future turns Successful writes are read later through normal Memory or Skills paths. Learning changes future work, not the answer already delivered.

2. Finalizer schedules review only after the answer

Expand the final steps of finalization. Hermes already has the final answer, runs post hooks, synchronizes external memory, and only then checks the background-learning gate. With error handling removed, the order is visible directly in the source:

agent._sync_external_memory_for_turn(...)

if final_response and not interrupted and (
    _should_review_memory or _should_review_skills
):
    agent._spawn_background_review(
        messages_snapshot=list(messages),
        review_memory=_should_review_memory,
        review_skills=_should_review_skills,
    )

There is no "the model feels that it should reflect" condition. The gate contains three runtime facts: a final response exists, the turn was not interrupted, and at least one due reminder has fired. Memory counts user turns and Skills count tool-call iterations. Reaching their respective intervals sets _should_review_memory or _should_review_skills. The Memory path is visible in turn_context.py. The Skill path is visible in conversation_loop.py. The complete gate is in turn_finalizer.py.

Suppose the Memory interval is three user turns. The first two turns only advance the counter; the third sets "review is due." If that third turn is interrupted, the finalizer still does not launch review. If it completes, review may still find no durable lesson and write nothing. Conversely, if the foreground agent already uses memory or skill_manage, the corresponding counter resets in tool completion bookkeeping. Review is therefore not a per-turn tax. It is best-effort work after a safe ending: failure cannot revoke the delivered answer, and success is still allowed to write nothing.

3. Review fork reuses runtime, but narrows tools

The finalizer does not pass a sentence that says "summarize a lesson." It passes a copy of completed messages. In the running test-repair example, the relevant tail of that snapshot looks like this:

user: Fix this failing test
assistant -> terminal: Run pytest directly
tool -> assistant: Failed; generated files are stale
assistant -> terminal: Run the generator, then pytest
tool -> assistant: Tests passed
assistant: Fixed and verified

Because both the failed path and the adopted path remain visible, review can extract "run the generator first" without turning "run pytest directly" into recommended procedure. The module contract also says that writes go directly to memory or skill stores; the main conversation and prompt cache remain untouched.

A complete snapshot does not imply complete permission. By default Hermes reuses the parent's provider, model, credentials, and cached system prompt. If background review is configured with a different auxiliary model, it resolves that runtime instead and sends a digest because no cross-model warm cache can be reused. Both paths disable external memory-provider ingestion and compression, then install a whitelist at tool-dispatch time. The reduced construction and call shape is:

review_agent = AIAgent(..., skip_memory=True)
review_agent._cached_system_prompt = agent._cached_system_prompt
review_agent.compression_enabled = False

review_whitelist = {
    tool["function"]["name"]
    for tool in get_tool_definitions(
        enabled_toolsets=["memory", "skills"]
    )
}
set_thread_tool_whitelist(review_whitelist)
try:
    review_agent.run_conversation(
        user_message=prompt + "...Only memory/skill tools...",
        conversation_history=messages_snapshot,
    )
finally:
    clear_thread_tool_whitelist()

skip_memory=True prevents an external provider from ingesting the review harness as user conversation. Disabling compression prevents a fork from racing the parent over the same session lineage. The whitelist permits only Memory and Skills operations, so review cannot continue terminal work, edit code, or delegate another task. The complete construction is in _run_review_in_thread.

The current implementation adds a second boundary: persistence isolation. A same-model fork temporarily shares the parent's session_id for prompt-cache parity. Normal session persistence would then write the review harness itself into the real transcript, where a later foreground turn could misread it as user instruction. Hermes sets _persist_disabled=true, clears the fork's _session_db, and prevents fork shutdown from closing the parent's session. The fork can write Memory or Skills through whitelisted tools, but it cannot write its own conversation into SessionDB; see review-fork isolation.

A successful write still affects future work, not the turn that produced it. Memory reaches a later model view when a new snapshot is built; a skill reaches later turns through the skills index. Hermes finally scans review tool results and surfaces only successful actions as a short self-improvement summary; see the action-summary code. If no experience qualifies, silence is the correct output.

4. Curator is long-term maintenance, not per-turn reflection

Background review asks whether one completed turn revealed something worth saving. Months later, the problem changes shape. A library may contain "generate code before testing," "refresh generated files before testing," and "rerun tests after a schema change" as three separate skills. Every one may come from a real success, but keeping all three forever may make retrieval worse. Another rarely used skill may still be important and should not disappear merely because its task has not appeared recently. Curator handles maintenance pressure that becomes visible only across many turns.

4.1 It wakes on periodic entry-point checks, not after every turn

Curator does not sit on the finalizer-to-background-review path above. The CLI checks at new-session startup, while a long-running Gateway asks from its housekeeping loop once an hour. Whether a pass actually starts is then decided by maybe_run_curator and should_run_now:

CLI session starts / Gateway polls hourly
  -> is curator.enabled true?
  -> is the curator paused?
  -> has interval_hours elapsed since last_run_at?
  -> has the caller reported at least min_idle_hours of idle time?
  -> yes: start one Curator run
  -> no: stop this check without reading or changing skills

The defaults are a seven-day interval and a two-hour idle gate. On the first observation of an install with no Curator history, Hermes only seeds last_run_at and waits a full interval. It does not reorganize the library immediately after an update. A manual hermes curator run bypasses this periodic gate. See the CLI startup hook, Gateway poll, and should_run_now.

4.2 Phase one applies time thresholds without a model

Hermes keeps operational telemetry out of SKILL.md. A sidecar at ~/.hermes/skills/.usage.json records how often a skill was actually loaded or referenced, viewed with skill_view, and patched, plus the latest time for each event. last_activity_at is the newest of last_used_at, last_viewed_at, and last_patched_at:

{
  "generated-code-testing": {
    "use_count": 12,
    "view_count": 4,
    "patch_count": 2,
    "last_used_at": "2026-04-10T09:00:00Z",
    "last_viewed_at": "2026-04-12T08:00:00Z",
    "last_patched_at": "2026-03-28T18:00:00Z",
    "state": "active",
    "pinned": false
  }
}

This record's latest activity is April 12. Counter updates and timestamp derivation live in bump_view, bump_use, and bump_patch and activity derivation. The lifecycle is not four mutually exclusive states. It has three states plus one orthogonal protection flag:

State or flag Discoverable by later work? How it enters How it leaves
active Yes Creation, restoration, or renewed activity after stale Becomes stale after 30 inactive days by default
stale Yes. Its directory remains in the normal skill tree Crosses stale_after_days Returns active after activity and the next pass, or ages into archive
archived No. Its directory moves under skills/.archive/ Crosses 90 inactive days by default, or is manually archived hermes curator restore <name> restores it as active
pinned Yes; pin does not replace active or stale, and is not a fourth state The user explicitly pins it The user unpins it; automatic transitions skip it while set

Phase one walks these records and applies one configured threshold policy. Reduced to its decision shape, the source reads like this:

anchor = newest(last_used_at, last_viewed_at, last_patched_at)
anchor = anchor or created_at

if skill.pinned or skill.referenced_by_cron:
    continue
if now - anchor >= archive_after:
    archive(skill)                 # move to .archive; recoverable
elif now - anchor >= stale_after and skill.state == "active":
    skill.state = "stale"
elif now - anchor < stale_after and skill.state == "stale":
    skill.state = "active"

Follow generated-code-testing through time. It is used on day 10. A Curator pass on day 41 sees 31 inactive days and changes active to stale, but the skill remains discoverable. Work views or uses it again on day 45, updating the timestamp; the next Curator pass restores active. If nothing touches it after day 45, it becomes stale again on day 76 and is only archived after day 135. The complete transition and new-skill grace logic is in apply_automatic_transitions.

The candidate set is not every skill on disk. Skills autonomously created and marked by background review qualify. With prune_builtins: true, bundled built-ins also receive time-based maintenance, but their first observation only seeds a clock. Hub-installed, external-directory, and protected built-in skills remain outside the set. Skills referenced by cron jobs and pinned skills skip automatic transitions. See candidate enumeration.

4.3 This is neither LRU nor LFU

"Recently used," "frequency," and "archive" sound like cache eviction, but Curator has no rule saying a full library must evict one entry. It does not rank every skill and sacrifice the last one. Phase one is better understood as an independent lifecycle clock for each skill:

Question LRU / LFU cache Hermes Curator phase one
When removal happens Usually under capacity or memory pressure When a periodic pass finds one skill beyond its time threshold
Primary signal Global recency order or global frequency That skill's latest use, view, or patch timestamp
Global ranking required? Yes, to choose a victim No; many skills may remain active, become stale, or archive together
Is removal destructive? A cache entry is usually dropped and rebuilt from its source The directory moves to .archive and can be restored or rolled back

Status and the semantic candidate list expose use_count, view_count, and patch_count, but automatic stale/archive decisions do not sort by frequency. use_count == 0 only adds a grace rule: a newly created skill whose trigger has not appeared must survive at least the stale window. Zero frequency is absence of evidence, not an immediate LFU eviction signal.

4.4 Phase two is optional semantic consolidation

Timestamps can say how long a skill has been quiet; they cannot say whether three testing skills belong in one reusable procedure. Phase two therefore renders each candidate's state, pin and cron flags, counters, and latest activity for a restricted auxiliary agent to inspect. In the current source, consolidate defaults to false. A normal automatic pass only runs phase one. The model pass costs tokens only after setting curator.consolidate: true or manually running hermes curator run --consolidate.

counts = apply_automatic_transitions(now=start)  # phase one always runs

if not consolidate:
    write_report("llm: skipped (consolidation off)")
    return

candidate_list = _render_candidate_list()
if candidate_list:
    llm_meta = _run_llm_review(candidate_list)   # phase two is optional

Return to the three testing skills. The auxiliary agent must inspect complete skill packages rather than merge on name similarity. If they implement one class of workflow, it may choose or create a generated-code-testing umbrella, preserve unique details in its body, references/, templates/, or scripts/, and then archive the absorbed source directories. It can patch a drifting skill, consolidate overlapping skills, keep an already broad umbrella, or archive genuinely obsolete content. The model does not reinvent inactivity thresholds.

before
  test-after-codegen
  refresh-generated-files
  pytest-schema-change

semantic decision
  all three serve generated-code validation
  each still contains a distinct tool, failure signal, or command

after
  generated-code-testing/
    SKILL.md
    references/schema-change.md
    scripts/verify-generated-files.sh
  old directories -> skills/.archive/ (absorbed_into recorded; recoverable)

A pin is a user-owned safety fence, not an excellence grade the model may award; phase two must skip pinned skills. Bundled built-ins may only be archived when pruning is enabled, not rewritten into umbrellas. Hub and external skills remain out of bounds. The consolidation gate and ordering are in run_curator_review, and the rendered fields are in _render_candidate_list.

4.5 What later work observes

Before a real mutating pass, Curator makes a best-effort snapshot of ~/.hermes/skills/. It then writes state, transitions, consolidation destinations, tool calls, and recovery data under ~/.hermes/logs/curator/<timestamp>/. Active and stale directories remain in the normal skill tree, so later discovery can still see both. Archived directories live under .archive and leave the normal discovery path. A new umbrella becomes available when later work rebuilds or queries the skill catalog; none of these writes reaches backward into the turn that was already delivered.

hermes curator run --dry-run is the safety preview. It skips automatic state mutations, instructs the model to report without write tools, and does not advance the scheduled last_run_at. After a real pass, one archived skill can be restored or the pre-run snapshot can roll back the whole maintenance pass. The two phases now have separate questions: phase one asks where a skill sits in its lifecycle; phase two asks how the knowledge that remains worth keeping should be organized.

5. Conclusion: three clocks improve one agent without becoming one chain

The foreground turn, background review, and curator all improve the agent, but they run on different clocks. The foreground solves the current task. Review extracts a preference or procedure after one turn. Curator maintains the skill library after many turns. Their trigger, input snapshot, decision method, and write permissions are deliberately different.

This closes runtime learning, not offline optimization. Background review asks what this turn is worth preserving, and the curator asks how to maintain the skill library. Neither proves that a particular rewrite performs better on an independent set of tasks. That requires offline evaluation and optimization. Before entering that heavier evidence chain, the next chapter covers the user's active-learning entry point: how one /learn request reads named material, creates a Skill, and exposes relationships through a Learning Graph that is a view rather than a hidden learning engine.

Source References