To keep a self-modifying agent safe, treat every change it makes to itself (memory notes, skills, skill scripts, config, hooks, plugins) as a software change: gate it by how hard it is to reverse, record it somewhere the agent cannot rewrite, test it before other sessions load it, and keep a rollback path you have actually tried.
Hermes Agent from Nous Research ships most of the switches you need, but several of the important ones are off by default.
This guide walks through those controls one layer at a time, with the real config.yaml keys, shell hooks, git commands and a CI gate, and ends with a runbook for the day a bad skill turns up in a shared skills directory. We checked every Hermes default, key and command below against the Hermes documentation on the project's main branch and against release v0.22.5 (published 23 October 2026) on 23 October 2026. Hermes ships several releases a week, so check hermes config show on your own install before you copy a value.
Key takeaways
- In Hermes the self-writable surface runs from a 2,200 character memory file up to skill scripts,
config.yaml(writable but not readable by the agent's file tools), cron jobs and gateway hooks. - Pick an approval tier for each surface by how hard it is to reverse. Hermes has the gates, but on the docs we read on 23 October 2026 the skill and memory write gates and the skill content scanner all default to off.
- Hermes ledgers every skill change, but the ledger is telemetry, capped at 5 MB by default and editable by the agent's shell. Memory has no comparable ledger in the docs we read. Commit both to git from a hook and push to a remote that refuses force pushes.
- Stage writes and replay a frozen evaluation set on a canary profile before a change reaches shared profiles.
- Each Hermes undo tool covers one layer. File checkpoints are off by default and do not work with container backends.
- No rollback recalls a sent message, an external API call, a pushed commit or a package that has already been imported into a running process. Put the approval gate in front of those actions.
- For unattended runs, keep the approval modes at
deny, capagent.max_turns, and auditcommand_allowlist, whose rule keys are honored even in deny modes.
What can a self-modifying agent change about itself?
For agent harnesses like Hermes Agent, "self-modifying" does not mean rewriting model weights. It means the agent writes files that shape its own future behaviour. Hermes calls this its learning loop. The README describes agent-curated memory, autonomous skill creation after complex tasks and skills that improve during use. Hermes does not retrain the model it runs on; it changes the text, code and configuration that surround the model.
That still matters a great deal, because those files load into every future session. A memory note is injected into the system prompt, a skill loads as instructions (often with scripts) in chat and cron sessions, and a config change can turn off an approval prompt for good.
Here is the surface, ranked from the smallest blast radius to the largest. Locations and defaults come from the Hermes docs pages listed in Sources, read on 23 October 2026.
| Rank | What changes | Where it lives in Hermes | Who can write it | Default gate | Main undo tool |
|---|---|---|---|---|---|
| 1 | Conversation context | Session in ~/.hermes/state.db | The session itself | None needed | /undo (removes the last exchange) |
| 2 | Memory note | ~/.hermes/memories/MEMORY.md (2,200 character cap) and USER.md (1,375) | Foreground memory tool, background review | memory.write_approval: false | hermes journey delete, git if you add it |
| 3 | Skill text | ~/.hermes/skills/<category>/<name>/SKILL.md | skill_manage, background review, curator, /learn | skills.write_approval: false, skills.guard_agent_created: false | Skills ledger rollback, curator snapshot |
| 4 | Skill scripts and supporting files | scripts/, references/, templates/ under each skill | skill_manage with write_file | Same as skill text | Same as skill text |
| 5 | Project files | Your working tree | write_file, patch, terminal | Dangerous command approval (smart by default) | /rollback, if checkpoints are on |
| 6 | Scheduled work | Cron job store under ~/.hermes/cron/ | cronjob_manage tool, /cron, hermes cron | Not covered by the write gates | hermes cron pause and remove |
| 7 | Agent configuration | ~/.hermes/config.yaml | Control file: read-denied to the agent's file tools, but writable | No dedicated gate; Hermes itself writes it when you choose "always" | Your own copy in git |
| 8 | Gateway hooks and plugins | ~/.hermes/hooks/<name>/, ~/.hermes/plugins/ | Anyone who can write the profile home | Gateway hooks load on placement, with no opt-in | Delete the directory, restart |
| 9 | Python environment | Hermes virtual environment | Lazy installs of optional extras, explicit installs | security.allow_lazy_installs (allowed unless you set it to false) | Reinstall from the lock |
| 10 | Its own installed code | The Hermes install directory | The terminal tool, as the same OS user | Not on the protected-paths list in the docs | Reinstall and verify |
Three facts from the Hermes security page shape everything that follows.
First, the file write denylist is "defense-in-depth, not a hard boundary." The docs say plainly that the terminal tool runs as the same OS user and "can still cat or overwrite denied paths via shell commands."
Second, config.yaml is listed as a control file that is "read-denied but stay[s] writable." When you click "always" on an approval prompt, Hermes itself writes a command_allowlist entry there, and those entries are "silently approved in all future sessions."
Third, gateway hooks are "trusted by placement." The gateway imports every valid hook directory under the profile home at startup, in process, with the gateway's privileges, and the hooks directory "is not on the protected-paths denylist, so it is ordinary writable state." Treat the profile home as one trust zone: if the agent can write any of it, assume it can write all of it, and keep audit and rollback outside it.
Which self-changes should need human approval?
OWASP's Top 10 for LLM Applications 2025 names the underlying problem LLM06, Excessive Agency, and traces it to three root causes: excessive functionality, excessive permissions and excessive autonomy. Its mitigations include "Require user approval" for high-impact actions. For a learning agent, reversibility is the best yardstick: approve by hand what you cannot cheaply undo.
| Tier | Rule | Hermes surfaces | How to set it |
|---|---|---|---|
| 0: allow and log | Fully reversible, local, already ledgered | Conversation turns, file edits inside a checkpointed project | Defaults plus checkpoints.enabled: true |
| 1: allow, notify, review later | Reversible, affects only future sessions of one profile | Memory notes on a single-user profile | display.memory_notifications, daily git diff review |
| 2: stage for approval | Reversible but shared, or loads as instructions | Skill create, patch, delete, scripts; memory on shared or gateway profiles | skills.write_approval: true, memory.write_approval: true, skills.guard_agent_created: true |
| 3: approve every time, never "always" | Hard to reverse or leaves the machine | Package installs, git push, outbound messages, cron job creation, credential changes | approvals.mode: manual or smart, no command_allowlist entries for these |
| 4: forbid | Irreversible or changes the guardrails themselves | Force pushes, writes to the hooks directory, edits to the audit repository | approvals.deny globs, OS file permissions, a separate audit host |
The approval keys Hermes provides
Hermes has two independent kinds of gate for self-changes, and the docs are careful to keep them separate.
skills.write_approval and memory.write_approval are approval gates. When either is true, Hermes stages every write instead of applying it. For skills, staging applies "regardless of whether the write came from a foreground turn or the background review," and staged writes survive restarts under ~/.hermes/pending/skills/. You review them with /skills pending, /skills diff, /skills approve and /skills reject. For memory, the interactive CLI prompts inline (entries are short enough to read), while messaging platforms, scripts and the background review stage writes for /memory pending.
skills.guard_agent_created is a content scanner, not an approval gate. When on, it scans skill writes for dangerous patterns (the docs give credential harvesting, obvious prompt injection and exfiltration instructions as examples) and turns a flagged write into an approval prompt with the scanner's reasoning. The configuration page says it is off by default because legitimate workflows that mention ~/.ssh/ or an API key variable tripped it too often. Turn it on anyway if your agent writes skills other people will load, and accept a few extra prompts.
Approval for commands, which is what most self-changes become
Any self-change that leaves the profile home runs through a command. Hermes's approvals block controls that path:
approvals.modeissmartby default (an auxiliary model approves low-risk commands, denies dangerous ones and escalates the rest);manualalways asks;offequals YOLO mode.approvals.timeoutdefaults to 300 seconds, and an unanswered prompt is denied (fail closed).approvals.denytakes glob patterns that block matching commands "unconditionally," before YOLO andmode: offare consulted, including inside container backends.- A hardline blocklist in the code (filesystem root wipes, fork bombs, raw block device writes and similar) cannot be overridden by any setting.
Scripts have their own rule. On gateway and API sessions Hermes asks once for a whole execute_code script, but in local sessions you typed, the docs say Python-level file and process calls inside the script run without a prompt and only its terminal() calls ask. For a skill that ships a helper script, the skill gate, not the command gate, is where you catch it.
How do you make every self-change auditable?
In NIST SP 800-53 Rev. 5, AU-2 and AU-12 cover deciding what to log and generating the records, and AU-9 asks you to "protect audit information and audit logging tools from unauthorized access, modification, and deletion." AU-9 is the hard part here, because the thing being audited has a shell on the machine that holds the logs. CM-3 and CM-5 add change control and access restrictions for change.
If your agent supports a high-risk use under the EU AI Act, Article 12 adds a legal angle. It requires that high-risk AI systems "technically allow for the automatic recording of events (logs) over the lifetime of the system," including events relevant to "identifying situations that may result in" a risk "or in a substantial modification." Most Hermes deployments are not high-risk in the Act's sense, but the pattern is good practice either way.
What Hermes already records
| Record | Location | What it holds | Limits |
|---|---|---|---|
| Skills change ledger | ~/.hermes/skills/.curator_ledger.jsonl | One JSONL entry per skill mutation: actor (curator, agent or user), action (create, edit, patch, delete, write_file, remove_file, archive, restore, purge, rollback), evidence including the triggering session id when available, and before and after file manifests with SHA-256 hashes | "Telemetry, never a gate": if writing an entry fails, the change still happens. Capped by skills.ledger_max_bytes (default 5 MB), after which the oldest divergent entries are dropped. Can be disabled with skills.ledger: false |
| Skills Hub lock and log | ~/.hermes/skills/.hub/lock.json, audit.log | Source URL, content hash, scanner version, findings and timestamp for each hub install | Hub installs only, not agent-authored skills |
| Staged writes | ~/.hermes/pending/skills/<id>.json, /memory pending | The full proposed change before approval | Only exists when the write gate is on |
| Sessions | ~/.hermes/state.db (SQLite with FTS5) | Conversation history, searchable with session_search | Grows over time and holds raw content, so restrict who can read it |
The skills ledger answers "which actor and session changed this file, from what hash to what hash," with file contents kept in a content-addressed store under ~/.hermes/.curator_backups/blobs/. It is not tamper-evident storage. It sits inside the skills tree, the agent's terminal can edit it, and with the default byte cap it will eventually drop its oldest history. Set skills.ledger_max_bytes: 0 to keep it append-only forever, and ship a copy off the machine.
We found no per-entry change ledger for memory in the memory documentation we read. If you want to know who changed MEMORY.md and when, add git.
Git-backed skills, memory and cron state
The simplest audit trail that survives a confused or compromised agent is a git history that the agent can append to but cannot rewrite, because the authoritative copy lives on a remote with protected branches. Keep the git directory outside the Hermes home so it does not create a .git folder inside the profile, and allowlist only the paths you want tracked.
Before you start: this step only reads Hermes state, but take a backup first so you have a known-good copy to compare against.
# 1. Known-good backup of the whole profile home (excludes checkpoints/ by design)
hermes backup -o ~/backups/hermes-before-audit-repo.zip
# 2. A separate git directory, with ~/.hermes as the work tree
export HERMES_AUDIT="git --git-dir=$HOME/.hermes-audit.git --work-tree=$HOME/.hermes"
git init --bare "$HOME/.hermes-audit.git"
$HERMES_AUDIT config core.bare false
$HERMES_AUDIT config status.showUntrackedFiles no
# 3. Track only learning state. Never track .env, auth files or vault/.
cat > "$HOME/.hermes-audit.git/info/exclude" <<'EOF'
/*
!/memories/
!/skills/
!/cron/
!/config.yaml
/skills/.curator_backups/
EOF
$HERMES_AUDIT add -A
$HERMES_AUDIT commit -m "baseline: hermes learning state" \
-m "Hermes-Version: $(hermes-agent --version 2>/dev/null | head -1)"
# 4. Push to a remote branch that is protected against force pushes and deletion
$HERMES_AUDIT remote add origin git@git.example.internal:agents/hermes-audit.git
$HERMES_AUDIT push -u origin main
Read config.yaml before the first commit in case an older config holds an inline secret.
Next, make Hermes commit after every learning write. Shell hooks are declared in config.yaml, run as subprocesses, receive a JSON payload on stdin and work in the CLI and the gateway. A post_tool_call hook with a matcher fires after the matching tool runs, whether it succeeded, failed or was blocked.
#!/usr/bin/env bash
# /opt/hermes-guard/commit-learning.sh (owned by root, mode 0755, see below)
set -euo pipefail
payload="$(cat)"
field() { printf '%s' "$payload" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('$1') or '')"; }
tool="$(field tool_name)"; session="$(field session_id)"; profile="$(field profile)"
home="${HERMES_HOME:-$HOME/.hermes}"
G="git --git-dir=$HOME/.hermes-audit.git --work-tree=$home"
$G add -A memories skills cron config.yaml 2>/dev/null || true
if ! $G diff --cached --quiet; then
$G commit -q -m "agent self-change via ${tool:-session end}" \
-m "Hermes-Session: $session" -m "Hermes-Profile: $profile" -m "Hermes-Tool: $tool"
$G push -q origin main || echo "audit push failed" >&2
fi
echo '{}'
# ~/.hermes/config.yaml
hooks:
post_tool_call:
- matcher: "skill_manage|memory|cronjob_manage"
command: "/opt/hermes-guard/commit-learning.sh"
timeout: 30
on_session_end:
- command: "/opt/hermes-guard/commit-learning.sh"
timeout: 30
The on_session_end entry is there for a reason. With the write gates on, a staged change lands only when you run /skills approve or /memory approve, which is not a tool call by the agent, so a post_tool_call hook never sees it. The session-end commit picks those up, and so does a systemd timer or a cron entry outside Hermes if you want a fixed schedule.
Two details from the hooks documentation decide whether this is real audit or theatre:
- Consent for shell hooks is recorded per event and command string in
~/.hermes/shell-hooks-allowlist.json, and the docs warn that "script edits are silently trusted" because the allowlist keys on the command string, not the script's hash. Keep hook scripts in a directory the agent's OS user cannot write, such as a root-owned/opt/hermes-guard/, and runhermes hooks doctorto flag modification time drift. - Gateways, cron and CI never show the first-use consent prompt. A hook added there stays unregistered until you allowlist it, accept hooks with
--accept-hooksorHERMES_ACCEPT_HOOKS=1, or sethooks_auto_accept: true. Confirm withhermes hooks list.
Trailers like Hermes-Session link each commit to the session that caused it; our guide on labelling AI-assisted commits covers trailer conventions for product repositories.
An off-host event stream
Git records state. An event stream also records attempts that were blocked or failed. Hermes offers two routes.
Outbound webhooks (hooks.outbound in config.yaml) POST a JSON payload to an HTTP endpoint for any plugin hook event, signed with an HMAC secret named by secret_env. Entries without a secret are sent unsigned and flagged UNSIGNED by hermes hooks list, so always set one.
hooks:
outbound:
- name: self-change-audit
url: https://audit.example.internal/hermes
events: [pre_tool_call, post_tool_call, on_session_start, on_session_end]
matcher: "skill_manage|memory|cronjob_manage|terminal|write_file|patch"
secret_env: HERMES_AUDIT_WEBHOOK_SECRET
timeout: 10
Observer hooks are the read-only telemetry contract for plugins. The developer guide says they exist for "trace, metrics, audit, replay, and export integrations," carry a telemetry_schema_version of hermes.observer.v1, and include correlation fields such as session_id, turn_id, tool_call_id and api_request_id. They fail open: a crashing observer is logged and the agent keeps running. That is the right behaviour for telemetry and the wrong one for enforcement, which is why enforcement belongs in pre_tool_call hooks with fail_closed: true, covered below.
The receiver should be append-only in the AU-9 sense: the agent's credentials can add records but not modify or delete them.
OpenTelemetry spans for tool calls and memory
The OpenTelemetry GenAI semantic conventions give you a shared vocabulary. As of 23 October 2026 they have moved to their own repository (open-telemetry/semantic-conventions-genai) and carry the status "Development," so expect attribute names to change. The agent spans page defines operations that fit self-modification: invoke_agent, execute_tool, create_memory, update_memory, upsert_memory, delete_memory and search_memory, plus agent attributes such as gen_ai.agent.id, gen_ai.agent.name and gen_ai.agent.version.
A practical mapping for Hermes:
| Hermes event | Suggested span operation | Attributes worth adding |
|---|---|---|
| A session or gateway turn | invoke_agent | gen_ai.agent.name = profile, gen_ai.agent.version = Hermes version, gen_ai.request.model |
skill_manage call | execute_tool | Tool name, action, skill name, before and after SHA-256 from the ledger |
memory tool add, patch or remove | create_memory, update_memory, delete_memory | Target file (MEMORY.md or USER.md), whether it was staged |
cronjob_manage call | execute_tool | Job id, schedule, attached skills |
| Approval prompt answered | Span event on the tool span | Decision (once, session, always, deny), who answered |
Keep raw content out of spans by default. The hooks catalog warns that tool arguments "may contain user content, paths, commands, or secrets." Record hashes and identifiers in telemetry, and keep the content itself in the git history where access is controlled.
How do you test a self-change before it is used?
NIST SP 800-53 CM-3(2) asks you to "test, validate, and document changes to the system before finalizing the implementation of the changes." For a learning agent, "before finalizing" means before other sessions load the change. Three techniques work well together.
1. Stage, then diff
With skills.write_approval: true, nothing the agent learns reaches the skill index until you approve it. That is already a shadow mode: the proposed skill exists as a JSON file under ~/.hermes/pending/skills/, it does not load, and you can read the full unified diff with /skills diff <id> on the CLI or in the dashboard. Messaging platforms truncate the diff, so make the CLI or the dashboard your review surface.
The curator has a matching dry run. hermes curator run --dry-run produces the same report as a real pass "without mutating the library." LLM consolidation, the pass that rewrites skill content, is off by default (curator.consolidate: false). If you turn it on, run the dry run first and read what it plans to merge.
2. A frozen evaluation set on a canary profile
Hermes profiles give you isolated homes with their own memory, skills and config. hermes profile create canary --clone copies config, skills and curated memory from the current profile, but not sessions, state.db or cron jobs. Promote a staged change into the canary first, replay a fixed set of tasks, and compare.
Here is a small, reproducible harness. It runs each task in one-shot quiet mode (-Q implies one-shot) with a 300 second wall-clock budget and checks for an expected marker. Run it against the canary before and after the change.
#!/usr/bin/env python3
"""Replay a frozen task set against a Hermes profile and report pass or fail."""
import json, subprocess, sys
PROFILE = sys.argv[1] if len(sys.argv) > 1 else "canary"
TASKS = json.load(open("evals/frozen_tasks.json")) # [{"id", "prompt", "skills", "expect"}]
def run(task):
cmd = ["hermes", "-p", PROFILE, "chat", "-Q", "-q", task["prompt"],
"--run-budget", "300"]
for skill in task.get("skills", []):
cmd += ["-s", skill]
out = subprocess.run(cmd, capture_output=True, text=True, timeout=420)
ok = out.returncode == 0 and task["expect"] in out.stdout
return {"id": task["id"], "ok": ok, "rc": out.returncode}
results = [run(t) for t in TASKS]
failed = [r for r in results if not r["ok"]]
print(json.dumps({"profile": PROFILE, "passed": len(results) - len(failed),
"failed": [r["id"] for r in failed]}, indent=2))
sys.exit(1 if failed else 0)
Keep the task set frozen and versioned, include cases where the old behaviour was correct, and do not ship a change that lowers the pass rate. Check hermes chat --help on your version before you rely on exact flag names; the CLI reference we used documents -q, -Q, -s and --run-budget.
Set approvals.single_query_mode: deny (the default) on the canary so a skill that tries a dangerous command during evaluation is blocked rather than approved, and so the evaluation itself tells you that the skill attempted it.
3. Canary sessions before shared promotion
Use the promoted change on the canary for real work for a day before it reaches shared directories. The skills docs warn that skills.external_dirs "are not a write-protection boundary": if the Hermes process can write a directory, agent skill updates can change it. Mount shared skill directories read-only for every profile except the one that owns promotion.
How do you roll back a self-modifying agent?
Hermes has several undo mechanisms, and each covers one layer. Knowing which one applies to which layer is most of the work.
| Tool | Restores | Does not restore | Default state |
|---|---|---|---|
/undo | Removes the last user and assistant exchange from the conversation | Any file, memory or skill change made during that turn | Available; asks for confirmation when approvals.destructive_slash_confirm is true |
/rollback <N> | Project files Hermes changed, from a shadow git store under ~/.hermes/checkpoints/store/; also undoes the last chat turn | Your hand edits (kept unless you add --all), nested git repositories, anything in a container backend, anything outside the project | Off: checkpoints.enabled: false |
hermes curator rollback <entry-id> | Exactly the files one ledgered skill mutation touched, including a hard-deleted skill | Memory, config, cron, anything the ledger did not record | Ledger on by default |
hermes curator rollback (no id) | The whole live skills tree from the newest snapshot | .archive/, the ledger and .hub/, which are never rolled back | Snapshots are taken before consolidation passes, or by hermes curator backup |
hermes curator restore <skill> | A skill the curator archived for inactivity | Content changes | Curator on, prune-only, every 7 days |
hermes journey delete <node> | Removes a learned node: skills are archived (restorable), memory chunks are removed | Nothing outside the node | Available |
hermes import <zip> | The whole profile home from a hermes backup archive | checkpoints/, which backups exclude; anything newer than the backup is overwritten | Manual |
git revert on your audit repo | Any tracked memory, skill, cron or config change | Untracked paths | Only if you set it up |
File checkpoints: useful, opt-in, and blind in containers
Filesystem checkpoints arrived in v0.2.0 (12 March 2026, per its release notes). They snapshot before write_file, patch and destructive terminal commands such as rm, mv, sed -i, install and git reset, at most once per directory per turn. /rollback <N> keeps your own hand edits by default, using an agent-write ledger to restore only the files Hermes last wrote, and takes a pre-rollback snapshot so you can undo the undo.
The limits are the important part:
- They are off unless you set
checkpoints.enabled: trueor start withhermes chat --checkpoints. - They skip the root directory, your home directory, trees over 50,000 files and files over
max_file_size_mb(10 MB by default). - With any container terminal backend, Hermes "does not take checkpoints" for sandbox paths, and
/rollbackrefuses diff and restore there. That is a trade-off worth knowing about: the backend that gives you the best isolation for commands is the one where file rollback is unavailable, so pair containers with git worktrees or volume snapshots. - Auto-prune drops projects untouched for 7 days and keeps 20 snapshots per project by default.
Rolling back skills: one entry or the whole tree
Warning: the commands in this block change your skills tree. Take a manual snapshot and a full backup first, and confirm the entry id with hermes curator ledger before you restore anything.
# Backup first
hermes curator backup --reason "before rollback of deploy-helper"
hermes backup -o ~/backups/hermes-before-skill-rollback.zip
# Find the mutation
hermes curator ledger --skill deploy-helper --limit 50
# Undo exactly one mutation (fails closed if the safety capture cannot be written)
hermes curator rollback <entry-id>
# Or restore the whole skills tree from a snapshot
hermes curator rollback --list
hermes curator rollback --id <snapshot-id>
Whole-tree rollback is itself reversible: Hermes takes a pre-rollback snapshot first. Snapshots are pruned to curator.backup.keep (default 2) on every pass, so if you rely on them, raise that number.
Rolling back memory
Hermes memory is two small files, so the cleanest rollback is git.
Warning: this overwrites the current memory files. Run the backup line first, and check the diff before you restore.
hermes backup --quick --label "before memory restore"
$HERMES_AUDIT log --oneline -- memories/
$HERMES_AUDIT diff <good-commit> HEAD -- memories/
$HERMES_AUDIT revert --no-edit <bad-commit>
$HERMES_AUDIT push origin main
git revert records a new commit that reverses the bad one, rather than rewriting history, so the audit trail keeps both the change and its reversal. That is exactly what you want in an audit repository; never use git reset --hard on it.
Remember the frozen snapshot. Hermes captures memory into the system prompt once at session start. A running session, including a long-lived messaging gateway chat that the memory docs say can last for weeks, keeps the old snapshot until it ends. After restoring memory, start new sessions with /new on every gateway chat that matters.
What rollback cannot undo
- Messages already sent.
/undoremoves them from the agent's context, not from the recipient's inbox. - External API calls. Tickets, records, cloud resources and payments made through a tool or MCP server stay done.
- Pushed commits and published artifacts. They live on another system with its own history.
- Installed packages already in use. Checkpoints cover the project directory, not a virtual environment, a system package database or modules already imported into a running process. Rebuild from a lock.
- Credentials that left the machine. If a script read and sent a secret, rollback does nothing. Rotate.
- State synced back from remote sandboxes. For SSH and some hosted sandbox backends, the configuration page says Hermes syncs changed
~/.hermes/state back to the host on teardown, including skills the agent created remotely. - Old snapshots in running sessions. As above, a removed memory entry lives on in any session that loaded it.
Anything in this list belongs in tier 3 or 4 of your approval table, because the only control that works is the one in front of the action. Our posts on what checkpoint rewinds cannot undo and approval tiers by reversibility go deeper.
What kill switches and rate limits make sense for unattended runs?
NIST AI RMF 1.0 puts this under MANAGE 2.4: "Mechanisms are in place and applied, and responsibilities are assigned and understood, to supersede, disengage, or deactivate AI systems that demonstrate performance or outcomes inconsistent with intended use." EU AI Act Article 14 makes the same point for high-risk systems in plainer words: oversight measures should let people "intervene in the operation of the high-risk AI system or interrupt the system through a 'stop' button or a similar procedure that allows the system to come to a halt in a safe state."
For Hermes, the stop buttons and limits look like this.
| Control | Key or command | Default (23 Oct 2026 docs) | Suggested for unattended runs |
|---|---|---|---|
| Dangerous commands in cron | approvals.cron_mode | deny | Keep deny |
| Dangerous commands in one-shot runs | approvals.single_query_mode | deny | Keep deny |
| Dangerous commands on webhook and API sessions | approvals.unattended_mode | deny | Keep deny |
| Permanent command approvals | command_allowlist | Empty until you click "always" | Keep empty for install, push and network tools; review monthly |
| Iterations per turn | agent.max_turns | Unlimited | A finite number sized to your longest real task |
| Wall-clock per run | agent.run_budget_seconds, --run-budget | Off | Set for cron and evaluation runs |
| Background learning | auxiliary.background_review.enabled, max_input_tokens | On; budget derived from the model's window | Keep on with write gates, or off on production gateways |
| Skill and memory writes | skills.write_approval, memory.write_approval | false | true |
| Curator consolidation | curator.consolidate | false | Keep false unless you review dry runs |
| Lazy dependency installs | security.allow_lazy_installs | Allowed unless set to false | false |
| Pause scheduled work | hermes cron pause <job_id> | Not applicable | Your first containment step |
| Stop the running agent | /stop | Not applicable | Kills background processes and interrupts the agent |
Two of these deserve a warning.
command_allowlist entries can be exact command text, a glob or a "dangerous-pattern rule key." The security page says rule keys "are honored on every surface, including unattended ones": a cron job under cron_mode: deny "still runs a command whose detected rule key is in command_allowlist." One "always" click can widen what every future cron job may do.
agent.max_turns is unlimited by default because, the configuration page says, a cap caused silent mid-task truncation. That is fair for interactive work, but an unattended job that can write skills should have a cap and a wall-clock budget.
Provider-side spending limits, set with your model provider, are the last backstop.
Blocking self-changes with a fail-closed hook
A pre_tool_call shell hook can block a tool call by exiting with code 2 or by printing a block decision. By default shell hooks fail open on timeouts, crashes and bad output. With fail_closed: true, those failures block the call instead, which is what you want for a security gate. This example blocks skill and cron writes from cron and gateway profiles entirely and leaves interactive profiles to the write gates.
hooks:
pre_tool_call:
- matcher: "skill_manage|cronjob_manage"
command: "/opt/hermes-guard/block-unattended-self-change.sh"
timeout: 10
fail_closed: true
#!/usr/bin/env bash
# /opt/hermes-guard/block-unattended-self-change.sh (root-owned, not writable by the agent user)
payload="$(cat)"
profile="$(printf '%s' "$payload" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("profile") or "")')"
case "$profile" in
cron-*|gateway-*)
echo "self-change blocked on unattended profile $profile; stage it from an interactive profile" >&2
exit 2 ;;
esac
echo '{}'
Python plugin callbacks on pre_tool_call also fail closed when they time out or raise, according to the hooks page, so a hung policy plugin blocks tools rather than waving them through.
How do policy gates in CI apply when the author is an agent?
The cleanest way to bring agent-authored skills into normal change control is to stop letting them land directly in the live skills directory. Hermes supports this with skills.create_dir: set it to a path inside a git checkout, and new skills the agent creates are written there instead of to ~/.hermes/skills/. The skills page says the agent's own instructions update to name the configured path automatically. Note the limit: existing skills are still modified in place wherever they live, so pair create_dir with the write gate.
skills:
create_dir: ~/work/agent-skills/skills
write_approval: true
guard_agent_created: true
ledger_max_bytes: 0
From there, treat the skills repository like any other code repository whose author happens to be an agent:
- Branch and pull request. The agent's profile commits to a branch; only the pull request merges into
main. - Owners. A
CODEOWNERSfile assigns a human reviewer to each skill category. - Protected branch. Require reviews, status checks and linear history, and refuse force pushes. Require signed commits where your platform supports it and check them with
git verify-commit. - Static checks. Fail the build on unpinned dependencies in skill scripts, on network calls to hosts outside an allowlist, and on scripts that read credential paths.
- Dependency inventory and vulnerability policy. Generate an SBOM for the skills repository and evaluate it against your vulnerability policy, as for any application.
- Behavioural check. Run the frozen evaluation set from the previous section against a canary profile that mounts the pull request's skills.
# .github/workflows/agent-skills.yml
name: agent-skills-gate
on:
pull_request:
paths: ["skills/**"]
permissions:
contents: read
jobs:
gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Require pinned Python dependencies in skill scripts
run: |
set -e
for req in $(git ls-files 'skills/**/requirements*.txt'); do
if grep -Ev '^\s*(#|$|--hash)' "$req" | grep -Ev '^[A-Za-z0-9._-]+(\[.*\])?==[^ ]+' ; then
echo "::error file=$req::unpinned requirement"; exit 1
fi
done
- name: Block credential paths in skill scripts
run: |
if git diff --name-only origin/${{ github.base_ref }}... -- 'skills/**' \
| xargs -r grep -nE '(\.ssh/|\.aws/|\.kube/|\.netrc)' ; then
echo "::error::skill touches a credential path"; exit 1
fi
- name: Inventory and policy check with Safeguard
# Install and authenticate the Safeguard CLI as described in
# https://docs.safeguard.sh/docs/cli before this step.
run: safeguard scan --dir .
Install pip dependencies with pip install --require-hashes -r requirements.txt and Node dependencies with npm ci against a committed lockfile, so a skill's script gets the same versions in CI, on the canary and in production. Install and authenticate the CLI in CI as its documentation describes; the Safeguard CLI writes JSON results under ./output, which you can attach to the pull request.
Where Safeguard fits
Safeguard does not monitor, govern or scan Hermes Agent itself, and Hermes is not a Safeguard integration or partner. The fit is the software the learning loop produces. Skills carry scripts, scripts pull in open source packages, and an agent that writes code leaves dependency changes in your repositories. Safeguard generates and analyses SBOMs in SPDX and CycloneDX, matches components against vulnerability data with reachability analysis, evaluates policies and gates, and signs and attests artifacts with SLSA, Sigstore and in-toto, all generally available, for any repository, including a repository of agent skills. Autonomous remediation can open fix pull requests when a fixed version exists, and it ships switched off. Agent identity, also generally available, tracks which agent holds what access. MCP Guardrail, which sits between agents and MCP tools, is in early access. None of this replaces the Hermes controls above; it covers the supply chain half of the problem that Hermes does not try to cover.
Worked runbook: a bad skill turns up in a shared skills directory
The scenario: a teammate notices that the deploy-helper skill in the team's shared skills directory now tells the agent to fetch a helper script from an unfamiliar host before each deploy. Several profiles mount that directory through skills.external_dirs, and two cron jobs attach the skill. Nobody remembers approving the change.
Step 1: Contain (first 15 minutes)
Warning: these steps change running state. Take the backups at the top first, on every host that mounts the directory.
# Backups before touching anything
hermes backup -o ~/backups/incident-$(date +%Y%m%d%H%M).zip
hermes curator backup --reason "incident: deploy-helper"
tar czf ~/backups/shared-skills-$(date +%Y%m%d%H%M).tgz /srv/team-skills
# Stop scheduled use of the skill
hermes cron list
hermes cron pause <job_id>
# Stop new loads of the skill on this profile
hermes config set skills.disabled '[deploy-helper]'
# Stop further learning writes while you investigate
hermes config set skills.write_approval true
hermes config set memory.write_approval true
# Make the shared directory read-only for the agent user
sudo chown -R root:agents /srv/team-skills && sudo chmod -R a-w /srv/team-skills
In any session that is already running, use /stop to interrupt work in progress. Skills load on demand rather than from a frozen snapshot, but a session that has already loaded the skill keeps its instructions in context until the session ends, so end those sessions with /new.
Step 2: Assess
Work out who changed the skill, when, and what it caused.
# Who changed it, from which session
hermes curator ledger --skill deploy-helper --limit 50
# If the shared directory is a git repository
git -C /srv/team-skills log -p -- deploy-helper/
# Your own audit repository
$HERMES_AUDIT log --stat -- skills/
# Which cron jobs attach it (the curator also protects skills referenced by cron)
hermes cron list
Then follow the session ids from the ledger into the session store with session_search or the dashboard. Establish which actor wrote the change (agent, curator or user), what that session was reading at the time (a web page, a document passed to /learn, an imported skill), which sessions loaded the skill afterwards, and what they did: commands, installs, messages, files.
Pull the off-host event stream for the same window; blocked attempts matter as much as successful ones.
If the change came from content the agent read, you are looking at persistent prompt injection through the learning loop: untrusted text that became a durable instruction. See our post on memory poisoning and memory hardening. Do not copy the offending text into tickets or chat; reference the commit or ledger entry instead.
Step 3: Roll back
Warning: the following restores files. Your backups from step 1 are your way back if you restore the wrong version.
# Option A: a ledgered agent change on this profile
hermes curator rollback <entry-id>
# Option B: the shared directory is in git
git -C /srv/team-skills revert --no-edit <bad-commit>
git -C /srv/team-skills push origin main
# Remove the disable entry once the restored version is verified
hermes config set skills.disabled '[]'
Then deal with what file rollback cannot reach. If the sessions that loaded the skill ran the fetched script, treat the host as suspect: rebuild the Hermes environment from its lock, rotate any credential the agent user could read, and check outbound connections for the window. If they installed packages, rebuild those environments from lockfiles rather than uninstalling one by one.
Step 4: Review and harden
- Replay the frozen evaluation set on a canary profile with the restored skill. Add a task that would have caught this change.
- Find why the write was possible: a writable shared directory, the write gate off, the content scanner off.
- Make the shared directory a pull request target, as in the CI section, with a read-only mount everywhere else.
- Record the incident: the ledger entry, the commits, the sessions, the actions taken and the controls changed. NIST AI RMF MANAGE 2.3 asks that "procedures are followed to respond to and recover from a previously unknown risk when it is identified."
- Unpause cron jobs one at a time, watching the event stream.
Threat and control mapping
| Threat | Hermes control (from its docs) | General control | NIST SP 800-53 Rev. 5 | NIST AI RMF 1.0 | EU AI Act (high-risk) |
|---|---|---|---|---|---|
| Agent learns a wrong or poisoned skill | skills.write_approval, skills.guard_agent_created, Hub and project skill scan with quarantine | Staging, PR review, owners | CM-3, CM-3(2) | MANAGE 1.3 | Art. 14 |
| Agent writes poisoned memory | memory.write_approval, memory content scanning, frozen snapshot | Git history, notifications | CM-3, SI-7 | MEASURE 2.4 | Art. 12 |
| Self-change spreads to other profiles | skills.external_dirs precedence rules, profiles | Read-only mounts, promotion pipeline | CM-5 | MANAGE 4.1 | Art. 14 |
| Audit trail edited or truncated | Skills ledger, ledger_max_bytes: 0 | Off-host append-only sink, signed pushes | AU-9, AU-12 | GOVERN, MANAGE 4.1 | Art. 12 |
| Guardrail weakened by an "always" approval | command_allowlist, approvals.deny | Allowlist review, config in git | CM-3, CM-5 | MANAGE 2.4 | Art. 14 |
| Hook script modified to bypass audit | hermes hooks doctor mtime drift | Root-owned hook directory | AU-9, CM-5 | MANAGE 2.4 | Art. 12 |
| Unattended run escalates | cron_mode, single_query_mode, unattended_mode set to deny; hardline blocklist | Turn and time budgets, provider spend caps | AC-6, CM-5 | MANAGE 2.4 | Art. 14 |
| Unvetted dependency arrives with a skill script | security.allow_lazy_installs: false, lock with SHA-256 for managed tools, advisory check in hermes doctor | Hash-pinned installs, SBOM and policy gate | CM-8, CM-14, SI-7 | MANAGE 3.1 | Art. 15 |
| Irreversible external action | Dangerous command approval, approvals.deny | Tier 3 and 4 approvals | AC-6 | MANAGE 2.4 | Art. 14 |
The control ids point to the family that describes the intent; following this table does not by itself satisfy any framework. The AI Act articles apply only to systems that are high-risk under the Act, which most internal agent deployments are not.
A step by step baseline for a team running a self-improving agent
Every key below is documented on the Hermes pages in Sources as of 23 October 2026; run hermes config show afterwards to confirm your version accepted them.
- Back up and baseline.
hermes backup, then create the external audit repository and commit the current state. - Separate profiles. One interactive profile that may learn, one canary profile for evaluation, and separate cron or gateway profiles that may not write skills.
- Apply the config baseline.
# ~/.hermes/config.yaml (interactive learning profile)
approvals:
mode: manual # or smart, if you accept an auxiliary model's risk calls
timeout: 300
cron_mode: deny
single_query_mode: deny
unattended_mode: deny
destructive_slash_confirm: true
deny:
- "git push --force*"
- "dd if=* of=/dev/*"
memory:
write_approval: true
skills:
write_approval: true
guard_agent_created: true
create_dir: ~/work/agent-skills/skills
ledger_max_bytes: 0
curator:
enabled: true
consolidate: false
backup:
enabled: true
keep: 10
checkpoints:
enabled: true
max_snapshots: 50
retention_days: 14
agent:
max_turns: 200
budget_warning_ratio: 0.8
auxiliary:
background_review:
enabled: true
max_input_tokens: 48000
security:
allow_lazy_installs: false
hooks:
pre_tool_call:
- matcher: "skill_manage|cronjob_manage"
command: "/opt/hermes-guard/block-unattended-self-change.sh"
timeout: 10
fail_closed: true
post_tool_call:
- matcher: "skill_manage|memory|cronjob_manage"
command: "/opt/hermes-guard/commit-learning.sh"
timeout: 30
on_session_end:
- command: "/opt/hermes-guard/commit-learning.sh"
timeout: 30
outbound:
- name: self-change-audit
url: https://audit.example.internal/hermes
events: [pre_tool_call, post_tool_call, on_session_start, on_session_end]
matcher: "skill_manage|memory|cronjob_manage|terminal|write_file|patch"
secret_env: HERMES_AUDIT_WEBHOOK_SECRET
- Lock down the guard files. Hook scripts in a root-owned directory, shared skills mounted read-only, the audit remote set to refuse force pushes and deletions.
- Approve the hooks deliberately. Run
hermes chatonce to answer the first-use prompts, thenhermes hooks listandhermes hooks doctor. For gateways, add the allowlist entries rather than turning onhooks_auto_accept. - Set up the CI gate and the frozen evaluation set on the skills repository.
- Rehearse rollback. On the canary profile, make a deliberate skill change, then undo it with
hermes curator rollback <entry-id>and withgit revert. Do the same for memory. - Review weekly. Read the git log of the audit repository, the
command_allowlist,hermes curator status, and any staged writes that have sat unreviewed.
Our hands-on guardrails versus sandboxes checklist covers the isolation layer this list assumes, and the agent audit log fields post lists what each tool call record should carry.
Common mistakes
- Assuming the defaults are conservative. On the docs we read, the skill write gate, the memory write gate, the skill content scanner and file checkpoints are all off by default, and
agent.max_turnsis unlimited. Fine for a personal assistant, wrong for a shared or unattended deployment. - Treating the skills ledger as tamper-proof. It is telemetry. It caps at 5 MB unless you change it, and it sits where the agent's shell can reach it.
- Keeping the audit hook inside the profile home. Consent keys on the command string, and script edits are silently trusted.
- Relying on
/rollbackwith a container backend. Hermes does not checkpoint sandbox paths, so there is nothing to roll back to. - Clicking "always" on an approval prompt during a busy session. The entry persists in
config.yamland can apply to cron jobs running in deny mode. - Pointing two agent processes at one Hermes home. The memory docs warn their writes compound into state nobody authored.
- Sharing an external skills directory that agents can write. Use read-only mounts and a promotion pipeline.
- Testing a skill only by asking the agent whether it works. Use a frozen evaluation set with expected outputs, run on a separate profile.
FAQ
Is Hermes Agent safe to run?
Hermes Agent documents eight security layers, including user authorisation, dangerous command approval, file write safety, container isolation and context file scanning, plus a hardline blocklist no setting can override. Safety depends on configuration: the local backend has no isolation and several self-change gates are off by default. Two CVE records have been published for Hermes Agent, covered in our posts on CVE-2026-71963 and CVE-2026-85105. Keep it updated and apply the baseline above.
Does Hermes Agent change its own model weights?
No. Hermes Agent is an agent harness that runs a model from a provider you choose. Its learning loop writes memory notes, skills and configuration, and searches past sessions. The weights of the underlying model do not change when the agent learns. The Hermes models are a separate family of open-weight fine-tunes from Nous Research.
How do I stop Hermes Agent from writing skills on its own?
Set skills.write_approval: true so every skill write is staged for review, or block skill_manage entirely on a profile with a pre_tool_call hook set to fail closed. To stop the background review from proposing changes at all, set auxiliary.background_review.enabled: false; manual /refine still works.
How do I undo something Hermes Agent learned?
For a skill, find the change with hermes curator ledger --skill <name> and undo it with hermes curator rollback <entry-id>, after taking a backup. For memory, use hermes journey delete <node> or revert the change in your own git history. Then start a new session so the old memory snapshot is dropped.
Can Hermes Agent change its own configuration?
The security docs list config.yaml as a control file that is read-denied to the agent's file tools but stays writable, and approving a command with "always" writes an entry to it. On the local backend a shell command can also change files the file tools refuse. Keep your config in git.
Where does Hermes Agent keep an audit log of its self-changes?
Skill changes go to an append-only JSONL ledger at ~/.hermes/skills/.curator_ledger.jsonl, with actor, action, session id when available and before and after hashes. Hub installs are logged under ~/.hermes/skills/.hub/. We found no equivalent per-entry ledger for memory in the docs, so add git and an off-host event stream.
Should a self-improving agent run unattended?
It can, with tighter limits than an interactive session: approvals set to deny for cron, one-shot and webhook sessions, no skill writes from unattended profiles, a finite turn cap, a wall-clock budget, and a tested way to pause every job. Let it learn interactively and promote changes to unattended profiles through review.
Does the EU AI Act require logs for self-modifying agents?
Article 12 requires automatic event logging for high-risk AI systems, including events relevant to identifying a "substantial modification." Whether your agent is high-risk depends on its use under the Act. If it is not, the same logging is still sound practice and costs little.
Why supply chain hygiene still matters here
A self-improving agent installs packages, writes helper scripts and authors skills whose code becomes part of your codebase, and the agent's own dependency tree, plugins and skill scripts are open source components that receive CVEs like any other. Guardrails and rollback stop a bad change from spreading, but a vulnerable package that a skill pulled in still has to be found and replaced, and that is ordinary software supply chain work.
Fix it without waiting for upstream
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.
3. Gold Registry: start from components that are already fixed
registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | The Gold scan GitHub Action in CI, plus Safeguard policies and gates |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch (early access) |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
See how Safeguard would help
The first demo shows the Safeguard CLI fixing a lodash CVE the way this guide says an agent should work: it reads the finding, asks before each command, edits package.json, runs npm install and npm test with your approval, and pushes nothing. That ask-first pattern, with /permissions modes from Ask to Strict, belongs in front of every tier 3 action.
Click through it at your own pace, or open it full screen.
The second demo connects Claude to the Safeguard MCP server, installed from Claude's connector directory with OAuth, and shows how you choose which tools Claude may use. Scoping tools at connection time is the same least-privilege step this guide applies to Hermes profiles.
Click through it at your own pace, or open it full screen.
The third demo sets up the Safeguard local runner on your own machine, approves it with a device code, and runs scans from the terminal. That is the piece to wire into the skills repository gate, so agent-authored scripts and their dependencies are checked where they are evaluated.
Click through it at your own pace, or open it full screen.
To try the CLI yourself, download Safeguard and follow the CLI documentation.
Quick check
Your Hermes cron jobs run with approvals.cron_mode set to deny. Can a cron job still run a command you once approved with "always"?
Yes, if the approval was saved as a dangerous-pattern rule key in command_allowlist. The Hermes security docs say rule keys are honored on every surface, including cron, one-shot and webhook sessions in deny mode. Review the allowlist after any session where you clicked "always."
You run Hermes with the Docker terminal backend and the agent breaks a file. Can you fix it with /rollback?
No. With container backends Hermes does not take checkpoints for sandbox paths, and /rollback refuses diff and restore. Use git worktrees, volume snapshots or your own version control for files the agent edits inside a container.
Sources
- Hermes Agent docs: Checkpoints and /rollback
- Hermes Agent docs: Skills
- Hermes Agent docs: Memory
- Hermes Agent docs: Curator
- Hermes Agent docs: Security
- Hermes Agent docs: Event hooks
- Hermes Agent docs: Observer hooks
- Hermes Agent docs: Configuration
- Hermes Agent docs: Cron
- Hermes Agent docs: CLI commands reference
- Hermes Agent docs: Slash commands reference
- Hermes Agent docs: Profile commands reference
- Hermes Agent v0.2.0 release notes (12 March 2026)
- Hermes Agent v0.22.5 release (23 October 2026)
- OpenTelemetry GenAI semantic conventions repository
- OpenTelemetry GenAI agent spans
- OWASP Top 10 for LLM Applications 2025: LLM06 Excessive Agency
- NIST AI 100-1, AI Risk Management Framework 1.0
- NIST SP 800-53 Rev. 5 catalog (OSCAL)
- EU AI Act Article 12, Record-keeping (European Commission AI Act Service Desk)
- EU AI Act Article 14, Human oversight (European Commission AI Act Service Desk)
- Git documentation: git revert
- Git documentation: git verify-commit
Last reviewed: 23 October 2026. Hermes Agent ships several releases a week; check the linked docs for current defaults and keys before you apply them.