hermes-learning-loop.md
How Hermes (Nous Research) actually learns. Technicalities, not slogans.
The loop has four cycles operating at different time scales:
turn-level → background review (after every turn)
session-level → trajectory recording (every completion)
week-level → curator consolidation (every 7 days)
forever → agentskills.io export (portable knowledge)
The agent improves on three substrates: memory (facts about the user), skills (procedural knowledge), trajectories (training data for next-gen models).
Cycle 1: background review — after every turn
File: agent/background_review.py. Fires after every AIAgent.run_conversation turn.
Mechanics
- Parent spawns a daemon thread via
spawn_background_review_thread(agent, messages_snapshot, review_memory, review_skills). - Thread runs a forked
AIAgentinheriting the parent's runtime: same provider, model, credentials, cached system prompt. Cheap fork — shares the loaded state. - The fork has a tool whitelist limited to memory and skill management tools. Everything else is denied at runtime, so the review pass cannot exec, write files arbitrarily, or call the network.
- Receives the conversation snapshot plus a review prompt.
- Runs with
max_iterations=16. - Parent scans returned messages for successful tool actions and surfaces a one-line summary in the UI (
💾 Self-improvement review: Memory updated). - Memory providers shut down, fork closes, stale messages are filtered to avoid re-acting on actions already taken in earlier turns of the same conversation.
The three review prompts
_MEMORY_REVIEW_PROMPT — asks one question:
Has the user revealed things about themselves — their persona, desires, preferences, or personal details worth remembering?
If nothing, response is literally Nothing to save. — the fork is allowed to no-op, which is the cheap path.
_SKILL_REVIEW_PROMPT — biased aggressively toward action:
Be ACTIVE — most sessions produce at least one skill update, even if small. A pass that does nothing is a missed learning opportunity.
Watches for specific signals:
- User corrected style / tone / format / approach.
- Frustration signals like "stop doing X" — explicitly called out as FIRST-CLASS skill signals.
- Non-trivial techniques or debugging paths surfaced.
- Loaded skills turned out wrong or outdated.
Preference order for skill writes:
- Patch currently-loaded skills (smallest change).
- Update existing umbrella skills.
- Add support files (
references/,templates/,scripts/). - Create a new class-level umbrella skill (most disruptive — last resort).
_COMBINED_REVIEW_PROMPT — fires when both memory and skill triggers hit.
What gets written
- Memory entries via memory tool calls, with provenance metadata:
write_origin="background_review", session ID, platform info. - Skill patches via
skill_managetool:action=patch | create | write_file | delete. - Protection layer: bundled or hub-installed skills are read-only. Pinned skills can be improved but not deleted by the curator (the long cycle).
Cost: one forked LLM call per turn, restricted scope, short iteration cap. Hidden from the user unless something is written.
Cycle 2: trajectory recording — every completion
File: agent/trajectory.py. Captures every conversation as training data.
Format
ShareGPT JSONL — the de-facto standard for tool-using conversation corpora. Each entry:
Two streams:
trajectory_samples.jsonl— successful completions.failed_trajectories.jsonl— incomplete attempts.
The split matters: the failed corpus is as valuable as the successful one for RL-style training (negative examples + recovery patterns).
Reasoning preservation
<REASONING_SCRATCHPAD> tags are normalized to <think> tags, preserving the model's internal reasoning alongside the tool calls and dialogue. This means trajectories carry not just what the agent did, but why — directly trainable.
Downstream
_convert_to_trajectory_format is called by batch_runner.py. This is the bridge from Hermes-as-product to Hermes-as-training-data-pipeline. Nous trains its next model on its own agent's execution. Closed loop at the model layer.
Cycle 3: curator — every 7 days
File: agent/curator.py. The long, slow consolidation pass.
Gating
Four conditions, all required:
curator.enabled == True(default).- Not paused.
last_run_atis older thaninterval_hours(default: 168 = 7 days).- First-run defers by one full interval.
Plus a caller-side idle check: the curator spawns only when the agent has been inactive for min_idle_hours (default: 2 hours). Compute and attention budget protection.
Phase A: automatic transitions (no LLM)
Walks every agent-created skill:
- Inactive ≥
stale_after_days(default 30) → markSTATE_STALE. - Inactive ≥
archive_after_days(default 90) → move to.archive/. - Stale skill with new activity → reactivate.
- Pinned skills → skip entirely.
This is pure bookkeeping. No LLM cost.
Phase B: forked review LLM
Spawns an auxiliary LLM with the CURATOR_REVIEW_PROMPT. The prompt mandates "umbrella-building consolidation" — merge narrow sibling skills into broader class-level umbrella skills with labeled subsections, support files (references/, templates/, scripts/).
Tool actions used:
action=patch— add sections to an existing umbrella.action=create— create a new umbrella skill.action=write_file— add support files under an existing skill.action=delete— archive a skill, takingabsorbed_into=<target>for forward links.
Classification: consolidation vs pruning
When a skill is deleted, the curator needs to know: was it absorbed into a bigger skill (consolidation) or dropped (pruning)? Three signals in priority order:
- Model-declared
absorbed_intoparameter at delete time (authoritative). - Substring matching in subsequent tool calls (heuristic — was the absorbed name referenced in a later patch?).
- Structured YAML block parsed from the model's final response.
Contradiction between these falls back to heuristic evidence or explicit pruning. The forward-pointer (absorbed_into) is what lets old skill references heal into new ones.
Output and state
State file .curator_state:
Reports under ~/.hermes/logs/curator/{YYYYMMDD-HHMMSS}/:
run.json— structured metadata (model calls, counts, classification breakdown).REPORT.md— human-readable summary with consolidated / pruned skill lists.
Plus a "rename summary" (up to 10 entries) appended to the agent's user-facing log, telling the user where skills were archived and suggesting hermes skill pin <name> commands for ones the user might want to keep.
Cycle 4: agentskills.io — the portable substrate
Skills are not Hermes-internal. They are folders in the open agentskills.io format (originated by Anthropic, adopted by ~40+ agents per the showcase: Claude Code, Cursor, Goose, OpenCode, OpenHands, GitHub Copilot, Codex, Letta, etc.).
Format
my-skill/
├── SKILL.md # required: YAML frontmatter + markdown body
├── scripts/ # optional: executable code
├── references/ # optional: extra docs, loaded on demand
├── assets/ # optional: templates, images, schemas
SKILL.md frontmatter:
| field | required | constraint |
|---|---|---|
name |
yes | ≤64 chars, [a-z0-9-], no leading/trailing/consecutive hyphens, must match parent dir |
description |
yes | ≤1024 chars, what + when to use |
license |
no | string or filename |
compatibility |
no | ≤500 chars, env requirements |
metadata |
no | arbitrary string→string map (author, version, etc.) |
allowed-tools |
no | space-separated pre-approved tools (experimental) |
Progressive disclosure — the key idea
Skills load in three stages by token cost:
- Discovery (~100 tokens): only
name+description, loaded for all skills at startup. - Activation (<5000 tokens recommended): full
SKILL.mdbody, loaded when the agent decides to use the skill. - Resources (as needed): files from
scripts/,references/,assets/loaded on demand.
This is what makes "hundreds of skills" affordable. The agent sees a flat namespace of one-liner descriptions; full instructions only enter context when relevant.
Validation
Reference library at github.com/agentskills/agentskills.
Hermes' skill taxonomy
The repo ships ~25 skill bundles. Notable categories from /skills/:
autonomous-ai-agents creative data-science devops
diagramming email github inference-sh
mcp media mlops note-taking
productivity red-teaming/godmode research
smart-home social-media software-development
yuanbao (Tencent) apple gaming gifs
Two interesting ones:
red-teaming/godmode— adversarial skill bundle, kept inside the agent for self-evaluation.dogfood— internal testing / self-hosting skills, meaning Hermes uses itself for its own QA.
User-created skills land in ~/.hermes/skills/<category>/<skill-name>/, alongside protected hub-installed ones.
Memory architecture
Three tiers:
- Procedural — skills (covered above).
- Semantic — FTS5 full-text search across saved session content, plus LLM-generated summarization for cross-session recall. The session itself is the corpus; no separate vector store needed.
- User model — Honcho dialectic system. External service that builds a persistent psychological/preference model of the user across all conversations.
The memory_manager.py + memory_provider.py split: memory_provider is the read path used by the agent loop, memory_manager is the write path used by background review and curator. Read-write separation lets the agent stay fast while writes happen async.
context_engine.py + context_references.py build the prompt's context window from these three tiers, with conversation_compression.py summarizing old turns when token budget tightens.
error_classifier.py categorizes failures into reusable taxonomy — feeds back into skill creation triggers (a recurring error class becomes a candidate skill).
What makes this loop different
Most "agent memory" systems are passive RAG: vectors of conversation, retrieved by similarity. Hermes is active on three counts:
-
The background review is a separate LLM call after every turn. Most frameworks would summarize-on-demand at the next session start. Hermes pays for the review upfront because the conversation is still hot in context.
-
The curator is its own LLM call on a 7-day cadence, with the only job of refactoring the skill library. Most frameworks accumulate skills monotonically and degrade as the library grows. Hermes garbage-collects.
-
The trajectory pipeline is not user-facing. It exists to feed model training. The agent is both product and data generator. This is the closed loop at the substrate level — Hermes the framework runs Hermes the model, which gets better because Hermes the framework records what worked.
What cyb takes from this
Direct lifts:
-
The four-cycle topology (turn / session / week / forever) is the right shape. Cyb should implement at least the turn-cycle review and the week-cycle consolidation from day one.
-
agentskills.io as the on-disk format. No reason to invent another. Cyb's existing
cyber/cyber/root/cyberia/midao/agents.mdaligns naturally — every neuron is a skill folder. -
The forked-agent-with-restricted-tools pattern for reviews. Same model, same context, but a tool whitelist that prevents the review pass from doing harm.
-
The frustration-signal-as-skill-trigger heuristic. Cyb users will swear at the robot; that swearing is training data. "Stop doing X" is the cheapest, highest-signal skill creation prompt.
-
Forward-pointer archival (
absorbed_into=<new-name>). Old skill references survive consolidation by pointing at their new home. This is exactly how cyb's cybergraph treats particle merges — content-addressed forwards. -
Two-stream trajectory recording (success / failure JSONL). Even before cyb trains its own model, this corpus is invaluable for debugging and for ranking which neurons earn karma.
Patterns to study but defer:
-
Honcho-style external user model. Cyb already has the cybergraph for this — the user's own particle history is the user model. Don't add another store.
-
FTS5 session search. SQLite-side feature, fits cleanly when cyb adopts the agentfs-style SQLite-as-FS layer.
discover all concepts