Hermes Agent

Hermes exposes the return address behind background work

Hermes reports persisted heartbeats that look active after restart but have no live watcher, Kanban cards created without a session return address, and split inbound events that can interrupt their own turn outside Telegram.

← Back to homeOriginal source ↗

NousResearch/hermes-agent issue #92584 is the inspected primary source: “feat(heartbeat): restore persisted gateway watches after restart and add admin session registration.” The related records below were inspected as supporting context rather than independent confirmation.

The facts

- NousResearch/hermes-agent issue #92584 was created 2026-08-23T00:07:19Z and was open at inspection; its title is “feat(heartbeat): restore persisted gateway watches after restart and add admin session registration.” - NousResearch/hermes-agent issue #92583 was created 2026-08-23T00:05:48Z and was open at inspection; its title is “[Feature]: hermes kanban create should stamp session_id and auto-subscribe WebUI/TUI sessions.” - NousResearch/hermes-agent PR #92582 was created 2026-08-23T00:01:00Z and was open at inspection; its title is “fix(gateway): apply the follow-up grace window to every platform, not just Telegram.” - The repository reported 234393 stars, 34796 open issues, default branch main, and last push 2026-08-23T00:08:29Z. - The latest tagged-release baseline checked was v2026.8.19 published 2026-08-21T12:16:39Z.

What changed

NousResearch/hermes-agent issue #92584 reports: Problem In Hermes v0.20.5 (v2026.8.19), gateway heartbeat state is persisted, but heartbeat execution is not. HeartbeatState is stored in SessionDB.state_meta under heartbeat:. However, the gateway’s _heartbeat_watch registry—which maps a session to its platform/chat/topic source and drives the poller—is memory-only. After a gateway restart, the database can still report a heartbeat as active, while no watcher is registered and no heartbeat will fire. This is especially painful with Telegram topics: users must run /heartbeat resume or set the heartbeat again in every topic after each restart. /heartbeat status may report an active heartbeat without making it operational. Reproduction 1. Start the gateway with two or more Telegram topics bound to separate Hermes sessions. 2. In each topic, run: 3. Confirm that the heartbeats fire. 4. Restart the gateway: 5. Leave the topics idle for more than one interval. 6. Observe that no heartbeat fires. 7. Run /heartbeat status; the persisted state still appears active. 8. Run /heartbeat resume in each topic; heartbeat delivery starts again. Expected behavior An active, persisted gateway heartbeat should automatically resume when the gateway restarts. No inbound message or per-topic /heartbeat command should be required. Hermes should also expose a backend/admin mechanism to list and manage heartbeats for existing sessions by session ID, so operators and plugins can register heartbeats without sending commands through every frontend

NousResearch/hermes-agent issue #92583 reports: Problem or Use Case When a Kanban card is created from a Hermes WebUI session via hermes kanban create (including --json helpers), the card has no return address: tasks.session_id is left NULL — _cmd_create never passes session_id= into create_task(). The create parser has no --session flag (that flag exists only on kanban list). No kanban_notify_subs row is written — CLI create never calls _maybe_auto_subscribe. The kanban_create **tool** already stamps session_id from HERMES_SESSION_ID / the origin-session binding and auto-subscribes. Gateway /kanban create auto-subscribes. CLI create is the gap. WebUI already exports a persistent session identity on every turn (HERMES_SESSION_PLATFORM=webui, and HERMES_SESSION_ID = HERMES_SESSION_KEY = HERMES_SESSION_CHAT_ID = the WebUI session id). That identity is enough to stamp and subscribe. Without the stamp, even after WebUI grows a collector for platform='webui' rows (nesquena/hermes-webui#5883 and PRs #5421 / #6854 / #6133), cards created through the CLI still cannot wake the originating tab. hermes kanban notify-subscribe --platform webui --chat-id $HERMES_SESSION_ID already accepts those flags, but CLI create does not invoke it. Related but distinct: #35417 is the broader TUI/WebUI terminal-event callback feature. #85575 is dispatcher-spawned workers inheriting an *ephemeral* session (wrong target). This issue is CLI create having *no* target. #86208 (open PR) is a desktop/TUI HERMES_SESSION_ID fallback inside _maybe_auto_subscribe; it does not change CLI _cmd_create. #19718 (reverted) is the reason _maybe_auto_subscribe must not treat

NousResearch/hermes-agent PR #92582 reports: Problem Some transports deliver **one human message as several events**. iMessage does this whenever the message carries a URL preview or an attachment: the user types a sentence, pastes a link, presses send **once**, and the BlueBubbles adapter receives two TEXT events a second or two apart. Without a follow-up grace window the trailing event lands mid-turn and is treated as the user interrupting themselves. The run is aborted, and the user is told they interrupted a message they sent as one piece. The gateway **already solves this**. _handle_message has a grace window that folds a text arriving shortly after a run starts into that run instead of interrupting it — but it is gated to a single platform: Telegram hit this first, and the fix was written at the call site rather than as a transport-level property, so every other adapter re-encounters a solved bug. BlueBubbles is the one I hit; anything that splits sends has the same problem. Reproduction Added to tests/gateway/test_busy_session_ack.py. Against main, unchanged: Both halves of a single send interrupt the run. Fix Replace the platform check with a resolver, GatewayRunner._followup_grace_seconds(platform): HERMES_TELEGRAM_FOLLOWUP_GRACE_SECONDS keeps working by construction, not by special case** — Platform.TELEGRAM.value.upper() reproduces that exact name. A test asserts this explicitly, including the case where the legacy name is set while the gateway-wide value is 0.

Why it matters

Background work is not operational merely because intent survived in a database. The runtime still needs a registered route, an owning session and transport-aware follow-up behavior. The operator test is whether the system remains bounded and its receipts still describe the action after failure, retry or restart.

Current

The primary record was open when captured on 2026-08-23. The tagged-release baseline was v2026.8.19 published 2026-08-21T12:16:39Z. Repository metadata, full source bodies, current pull requests and issues, releases, Google News, Hacker News, Lobsters, Metamesh and the rendered ClawCharts row were inspected. ClawCharts selected the subject; it did not prove the claim.

Evidence

The primary URL is https://github.com/NousResearch/hermes-agent/issues/92584. Supporting records are https://github.com/NousResearch/hermes-agent/issues/92583 and https://github.com/NousResearch/hermes-agent/pull/92582. Source bodies, timestamps and states are preserved in the daily evidence bundle. Test counts and reproductions remain attributed to their authors unless identified as independently rerun.

Source boundary

Open work is described as open, closed work as closed, and operator reports as reports. A pull request is evidence of proposed or reviewed direction, not proof of a shipped release. Search residue, package mirrors and historically published source spines were excluded.

Operator take

Separate configured from registered heartbeat state, stamp persistent session identity on CLI-created work, and make follow-up grace a transport contract rather than a Telegram exception. Preserve a before-state receipt, make the smallest reversible change, and verify the original failure independently.

Caveat

Public project records are mutable. Status, scope and evidence can change after publication. This brief records the inspected state and does not authorize changes to a reader’s deployment.

Source inspected; source state, environment and release boundary remain explicit.