Top 10 practical changes in Hermes Agent v0.21.3 (and what they're for)
Hermes Agent v0.21.3, the Remote Fix rollup, landed on 2026-09-14. The upstream highlight list runs to two named fixes for remote Desktop / Cloud users plus a dozen friction-reducers. These are the ten that actually shift how a one-person operator runs Hermes day to day: refresh-coalesce on the gateway, shared state.db writer handles, JSON-RPC reverse calls, per-model reasoning-effort control, OpenRouter OAuth PKCE, HEIF/HEIC/AVIF decoding, FAL catalog expansion, Slack pasted tables, multiplexed-profile isolation, and a daily MCP re-auth nudge.
Context: I run Hermes as my main agent on multiple named profiles (default, pclm_commander, vereby_ops_manager) for separate coding projects. Telegram is the primary channel, with daily cron briefings and delegated multi-step builds. v0.21.3 (the Remote Fix rollup, dated 2026-09-14) is a small tagged patch on the 0.21 line. The window since 0.21.2 contains 1,036 non-merge commits across 2,642 changed files and 338 merged PRs, and yet the maintainers flagged exactly two as urgent enough to ship under a new tag: the remote-Desktop refresh burst fix and the state.db writer-handle leak. Everything else is either a small friction reducer or plumbing. The "size" of 0.21.3 is the two named fixes plus everything else that turned out to be ready in the same window, not the commit count for one tag.
Even so, ten of those items genuinely move how I work. They are the ones below, with the two named fixes listed first because they are the reason this tag exists.
1. Remote desktop sessions no longer expire on refresh bursts
What it is: Both refresh paths on the gateway (the cookie gate and the desktop's native bearer route) now coalesce concurrent requests carrying the same rotating refresh token, so a Desktop wake burst can no longer replay an already-rotated token into the Portal's reuse detection and revoke the whole session. Refresh also runs off the event loop, so a slow identity provider no longer freezes /api/status. Pairs with Portal-side hermes-portal #1209 (sliding 30-day idle horizon, 5-minute rotated-token grace).
Why it matters: The bug was loud enough to warrant the tag on its own. A remote operator who woke up to a revoked session every other morning has a working backup pattern now.
Practical example: First thing in the morning, three devices with the desktop app wake at the same instant and try to refresh. Before, the rotation window was open and the second rotated token got flagged as replay. Now those three requests coalesce into one, and the session lives until you choose to leave it.
2. Long-lived processes stop leaking duplicate state.db writer handles
What it is: Gateway, dashboard/Desktop backend, ACP and CLI readers attach read-only; in-process writers share the registry handle. The "N live SessionDB handles" precursor warning stops firing on a healthy topology.
Why it matters: Long-running backends used to log this warning roughly every thirty minutes even when nothing was wrong. The warning now waits to mean something.
Practical example: A gateway and an ACP client run side-by-side for a week. Previously, the warning ended up trained to be ignored. Now a warning actually happening means there is a problem, so hermes logs --level WARNING becomes useful again.
3. JSON-RPC reverse calls land in the desktop
What it is: The TUI/Desktop now have a generated TS/OpenRPC contract for server-to-client requests, with a Pydantic wire-contract registry on the server. New request types can land in the desktop without a desktop rebuild; the server side is the source of truth.
Why it matters: For a desktop that runs alongside a session that's been going for hours, having the protocol declared in a typed registry is the difference between a desktop that upgrades and a desktop that freezes for a tool rename. Once the registry is in, new request types from the server can show up in the desktop without rebuilding it. Backwards-compat is handled on the wire, not in the app bundle.
Practical example: The desktop is at version N, the server is at N+2. Three new request types have been added server-side since the desktop shipped. Before, those would not render. Now they do, because the desktop treats them as opaque contracts and the server is the source of truth.
4. Reasoning-effort per model, with a composer pill
What it is: Every model picker now has reasoning-effort selection. The Desktop surfaces it both as a composer pill and as a per-auxiliary control.
Why it matters: Reasoning-effort used to be a picker-wide setting that you set at session start. Picking a "deep" model for one branch of a worktree and a "shallow" model for another used to require a second agent. Now it is per-picker, mid-session, without dropping model identity.
Practical example: The morning routine: draft replies shallow, audit the day's brief deep, switch pickers, run the audit, switch back. Each switch is a single click and the rest of the session state holds.
5. OpenRouter OAuth PKCE login
What it is: OpenRouter joins Anthropic and the rest as a first-class PKCE provider, alongside the existing OAuth flows.
Why it matters: For an operator who jumps between provider accounts daily, one fewer bespoke env var.
Practical example: The OpenRouter auth used to require an API key in an env file. PKCE means the desktop login flow works for OpenRouter the way it works for every other OAuth provider.
6. HEIF, HEIC and AVIF are decoded locally
What it is: Image decoding for those formats is in the upstream now, locally, no third-party decoder round-trip.
Why it matters: Until now, an iPhone photo pasted into a Telegram chat arrived as a pink square (or went through a third-party decoder). Now it arrives as itself.
Practical example: A client sends an iPhone screenshot of their CRM. The agent reads the screenshot rather than guessing from a pink square.
7. FAL catalog expands
What it is: Wan 3.0, Kling 3.0 and Kling Image v3, MiniMax H3 Max Turbo, Gemini Omni Flash 1.1 and Meta Muse join the catalog.
Why it matters: Picking a generative video model used to mean reinstalling the integration. Picking a model that was a different version of an existing provider used to mean editing config. Now it is a name change in the call.
Practical example: Moving a video generation call from Kling 2 to Kling 3 is a string change in the prompt, not a reinstall.
8. Slack pasted tables, and the Agent Sessions API
What it is: Slack messages now keep tabular context when they arrive as messages rather than text dumps, and an Agent Sessions API exposes logs and state for a running agent session.
Why it matters: Pasting an agent's Markdown table into a spreadsheet is a real copy of workflow, not a metaphor. The Slack change plus the Sessions API make it one paste, not five.
Practical example: The morning briefing posts the day's KPI table into Slack. Pasting it into a Numbers tab now preserves cells, headers, and number formatting. The Sessions API lets you point a separate job at a specific agent run from a tab in the desktop.
9. Multiplexed-profile isolation
What it is: The gateway now isolates session state cleanly across profiles when you run multiple sessions under one backend, and refuses to write to a state.db hosted on a cross-VM filesystem where the WAL would lose its guarantees.
Why it matters: Two profiles on the same host used to share state.db quietly because both home directories resolved to ~/.hermes. They no longer do. The WAL refusal also keeps a flaky filesystem mount from corrupting session history.
Practical example: A workspace profile and a client profile both point at the same Hermes backend. Each gets its own state.db. Switching profiles does not accidentally leak a conversation from one into the other.
10. Daily MCP re-auth nudge in Desktop
What it is: Refresh tokens from MCP OAuth now bind to their issuer, and the Desktop surfaces a daily nudge for any server whose token is about to expire.
Why it matters: Silent MCP token expiry is one of the failure modes that costs a morning. The nudge flips the failure from silent to skippable.
Practical example: Every morning at 09:00, the desktop shows a list of MCP servers whose tokens expire in the next 24 hours. You rotate the ones that matter before any tool call actually breaks.
What did not make the list (but is in the notes)
v0.21.3 is also a stated rollup. The window since 0.21.2 contains the Honcho peer-model rework, Zapier-style tooling internals, TUI splash rewrite, and quiet infrastructure work (Pydantic wire-contract stabilisation, gateway-liveness fixes, MCP refresh-token issuer-binding). Real changes, but either narrower than the ten above or only material for specific workflows. Full curated release notes for the whole 0.21 window ship with v0.22.0, which will roll everything from 0.21.0 onward into a single changelog. Nothing in this window is skipped.
The honest version of how to read this release
v0.21.3 is a patch tag, not a feature release. The upstream notes are explicit: it exists because the two named fixes needed to reach Cloud agents, which auto-update to the newest release tag, and everything else in the window was clean enough to ride the same train. The headline list runs to two named fixes plus about a dozen friction reducers; the daily-impact list runs to ten; the rest are mentioned in the section above. That is the honest shape. Everything in the notes is worth a skim when you hit the specific problem it solves, not before.

