Hermes Agent v0.21.1
Overview
v0.21.1 — The Consolidation Release. Released September 7, 2026. ~5,139 commits · ~4,364 files changed (+601,014 / −768,419) · ~632 merged PRs since v0.21.0.
This window has no single headline feature — it is a consolidation pass, and the biggest story is invisible: the codebase was decomposed and slimmed by ~34% of its source LOC with zero behavior change (#102117). Around that deep clean, the user-facing work concentrates where power users actually feel it: delegation got faster and safer (results land the moment each subagent finishes, children can hand running background processes back to you), MCP servers can now authorize with device codes on machines that have no browser to open, OpenRouter provider pins became per-model and model pickers refresh every 20 minutes, local search_files runs native ripgrep up to 6× faster, compaction keeps its prefix cache across rebuilds in coding sessions, and cron stops letting silent ticks erase continuity while finally showing you when a job fired late.
This is a patch release: the official notes are brief and the full curated documentation ships with v0.22.0. This page covers the most valuable parts of the window.
Highlights
1. The deep clean: −34% source LOC, zero behavior change
The window’s biggest internal story is a whole-codebase simplification (#102117, merged September 4): 1,063,826 → 698,363 source LOC (−34.4%). Every god file was decomposed — 37 files over 5,000 lines became 6; gateway/run.py went from 34,847 to 5,512 lines, cli.py from 22,426 to 4,656; functions over 300 lines dropped from 192 to 2 and the worst cyclomatic complexity from 1,075 to 84. The old files remain as thin public entry points, and behavior is unchanged: tool JSON schemas, system-prompt text, config defaults and wire formats are byte-identical, verified by full-suite parity runs. What you get as a user is a codebase that is cheaper for an agent to navigate, faster to load, and easier to maintain — no config or command changes on your side.
2. delegate_task: results land the moment each child finishes
Background fan-outs no longer wait for the slowest subagent. delegate_task now returns each task’s result on its own as soon as that task completes, and tasks that share an optional per-task group string return together as one message (#104299):
{
"tasks": [
{ "goal": "check api latency", "group": "bench" },
{ "goal": "check db latency", "group": "bench" },
{ "goal": "scan the changelog" }
]
}
The two bench tasks report in one grouped message; the changelog scan lands by itself the moment it finishes — no more waiting hours for one stuck child to see the other results. Ungrouped tasks each occupy their own unit, but the whole call still counts as a single slot against delegation.max_concurrent_children.
3. Children hand running processes back to the parent
A subagent can now transfer a long-running background process to you before it exits: process_manage(action="handoff", session_id=<id>, data="<purpose>") flips ownership to the parent, and the completion notice lands in your chat with the purpose attached (#105125). Anything a child leaves behind is explicitly reported as terminated in the parent’s delegation notice instead of being silently killed, and the child is told up front that its notify=true is not a promise — no more orchestrators waiting hours for a completion that can never arrive.
4. MCP logins without a browser: device codes
MCP servers that support RFC 8628 can now authorize from a terminal with no browser callback listener at all (#104891) — the workflow that used to force you onto a machine with a browser now works on any headless host:
hermes mcp login <server> --flow device
Hermes discovers the server’s advertised device endpoint, prints the verification URI and user code, and polls until you approve on any device. oauth.flow: device in your MCP server config makes device flow the default for login and reauth (browser PKCE remains the default overall; --flow browser overrides the config for one login). Denied or expired grants never replace existing credentials.
5. Per-model OpenRouter pins + pickers that stay fresh
provider_routing.models.<model-id> now pins a different OpenRouter provider set per model, so routing rules can no longer silently send a model to a provider you did not choose (#104159):
provider_routing:
sort: price
models:
"openai/gpt-6-astra": { only: [openai] }
"anthropic/claude-fable-5.1": { only: [anthropic] }
The per-model entry is applied at the one chokepoint every request path already calls, so CLI, gateway, desktop, cron, /model and delegated children all honor it. Meanwhile the /model picker stopped going stale: catalogs now refresh every 20 minutes (down from a 1-hour TTL), and a gateway background loop keeps them warm even when nobody opens the picker (#101319). The Meta Model API provider now treats its live /v1/models response as the authoritative catalog, excluding non-chat prefixes like muse-image-* and muse-voice-* (#101503).
6. Local file and search operations got a lot faster
search_files on a local POSIX host now runs ripgrep as a direct subprocess instead of through two bash spawns per call (#104502): content searches drop from ~85 ms to ~15 ms, file-name searches from ~73 ms to ~12 ms (5–6× lower tool latency, identical results; HERMES_NATIVE_FILE_READ=0 restores the shell path). Two companion wins keep token bills down in long coding sessions: compaction rebuilds now pin the coding workspace snapshot per session instead of re-probing git status every time, keeping the prompt prefix cache intact across compaction boundaries (#104455); and finished subagents release their transcripts from the parent heap, with subagent content excluded from the trigram FTS index (schema v30) — a 1,320-child run previously left a 1.9 GB parent heap and 1 GB of shadow tables behind (#102032).
Improvements
- Startup:
hermes serve— the command the desktop spawns on every cold start — dispatches through a standalone lean parser and skips building the ~40-subcommand argparse tree (falls back to the full parser for help, unknown flags, and container routing) (#101265). - Cron visibility:
hermes cron listnow prints a per-jobDispatch:line andhermes cron statusadds a late-jobs callout, so a missed-fire catch-up run shows⚠ catch-up after missed fireinstead of masquerading as an on-time success (#100445). - Delegation config: a delegated child pinned to a provider/model no longer silently reroutes through the parent’s fallback chain on failure;
delegation.fallback_providersgives children their own chain ([]disables, absent inherits when unpinned) (#105347). Children also no longer inherit the parent’s 1-hour prompt-cache tier — subagents write at the 5-minute tier they actually use, avoiding a 2× cache-write price for retention they never collect (#104168). - Token hygiene:
write_filenow flags a whole-file rewrite that mostly re-sends what is already on disk (≥20k chars, ≥80% unchanged lines), steering the agent topatchfor small edits — 661 such writes (~24.9M chars, ≈$155 of output tokens) were caught in one refactor run (#103551). - Desktop: transcript timestamps are readable again in both themes, and a new Message Bubble slider (Settings → Appearance) controls your bubble’s opacity from solid to outline-only (#103146).
Fixes
approvals.denyrules are now enforced inside isolated Docker/cloud sandboxes — they previously skipped the container fast path, so a deny list could be bypassed with a sandboxed shell even under--yoloorapprovals.mode: off;hermes approvals testmirrors the corrected order (#103649).- Cron: silent monitor/script-gated ticks no longer replace useful continuity context with an empty stub — output selection walks files newest-first and skips empty/silent documents while keeping error documents eligible for recovery (#104877). Cron incident and notepad stores also survive upgrades that leave an older execution module cached (#104939).
Upgrade
hermes update
After upgrading, run hermes doctor to verify the install and restart the gateway (hermes gateway) so platform changes take effect. The structural refactor keeps every public entry point in place, so third-party plugins and configs carry over unchanged. To see what the next update will touch before running it: hermes update --plan.