Hermes Agent
Hermes desktop can write a new chat into the wrong profile
A Hermes Agent bug report says a profile swap can leave a dead socket marked active, then silently fall back to the primary backend. The reporter found 20 secondary-profile sessions in the default state database; related issues expose ambiguous new-chat targeting and stale renderer IDs.
NousResearch/hermes-agent issue #79005 is the inspected primary source: “[Bug]: Desktop profile swap can route session.create to the wrong backend — cross-profile state.db pollution.” The related records below were inspected as supporting context rather than independent confirmation.
The facts
- NousResearch/hermes-agent issue #79005 was created 2026-08-05T01:22:26Z and was open at inspection; its title is “[Bug]: Desktop profile swap can route session.create to the wrong backend — cross-profile state.db pollution.” - NousResearch/hermes-agent issue #79003 was created 2026-08-05T01:22:10Z and was open at inspection; its title is “[Bug]: Desktop — new chat from the all-profiles view always targets the startup profile, with no visible indication.” - NousResearch/hermes-agent issue #79001 was created 2026-08-05T01:21:50Z and was open at inspection; its title is “[Bug]: Desktop boot 404s ("Session not found") for sessions deleted from state.db — renderer storage never drops dead IDs.” - The repository reported 225514 stars, 27932 open issues, default branch main, and last push 2026-08-05T00:33:39Z. - The latest tagged-release baseline checked was v2026.8.3 published 2026-08-03T16:57:52Z.
What changed
NousResearch/hermes-agent issue #79005 reports: Bug Description Same family as #41517 (closed), different mechanism — renderer socket identity during a profile swap. Three combined flaws in apps/desktop/src/store/ (gateway.ts ×2, profile.ts ×1): 1. ensureGatewayForProfile marked the profile active on a dead socket. 2. activeGateway() silently fell back to the primary socket (?? g.primaryGateway). 3. The no-op guard only checked $gateway non-null. Result: the UI shows profile A while session.create goes to backend B and writes into **B's** state.db. Concrete evidence: 20 sessions belonging to a secondary profile landed in the default profile's state.db over two days, and windows appeared to "switch agent" mid-conversation. Expected Behavior A swap either fully establishes the target socket or fails loudly; no write ever reaches the wrong profile's state.db. Actual Behavior Silent fallback + dead-socket "active" marking → cross-profile writes. Additional context Local fix (running since 2026-08-04): setActive only if the socket is open (+ throw after scheduleReconnect), primary fallback removed
NousResearch/hermes-agent issue #79003 reports: Bug Description Session creation resolves the target profile as $newChatProfile?? activeGatewayProfile (use-session-actions). The all-profiles grouped view is browse-only: it does not change the active profile. So Ctrl+N / the generic new-chat button always creates the session on the *startup* profile, regardless of which profile group the user is looking at. Nothing in the UI shows where the session will land. Worse, the default-profile rail button doubles as the all-profiles view toggle ($showAllProfiles), so clicking it feels like selecting the default profile while the active profile never changes. Steps to Reproduce 1. Start the desktop with profile B as startup profile. 2. Open the all-profiles grouped view, look at profile A's sessions. 3. Ctrl+N (or the generic new-chat button). 4. The session is created on profile B. Expected Behavior Either the new chat follows the visual context (the group being browsed), or the target profile is displayed on the draft
NousResearch/hermes-agent issue #79001 reports: Bug Description After sessions are removed from state.db (retention purge, manual delete), the desktop keeps their IDs in renderer localStorage (composer drafts hermes:composer-drafts:v3, pinned sessions hermes.desktop.pinnedSessions, composer queue). On every boot, startup fetchers re-request those IDs → hermes:api 404 {"detail":"Session not found"} repeated N times. Cosmetic but permanent: nothing ever drops the dead entries. Steps to Reproduce 1. Pin a session and/or leave a draft in its composer. 2. Delete that session from state.db. 3. Restart the desktop app. 4. Console shows repeated 404 "Session not found" from the hermes:api handler, one per dead reference. Expected Behavior A 404 on re-assert/fetch should drop the local entry (unpin, discard draft, dequeue) — dead references should self-heal. Actual Behavior The pin-sync re-asserts every pin at boot (src/store/session-pin-sync.ts) and its pull only consults rows present in the payload, so pins whose rows are gone are never dropped. Queue entries behave the same. The
Why it matters
A profile label is not cosmetic when it selects a state database. Silent fallback turns a UI race into cross-profile state pollution and makes the visible operator context untrustworthy. The operator test is whether persisted state, execution authority and the visible outcome describe the same event after retries, restarts or delegation.
Current
The primary record was open when captured on 2026-08-05. The release baseline was v2026.8.3 published 2026-08-03T16:57:52Z. Repository metadata, pull requests, issues, release records, Google News discovery, Hacker News discovery, Lobsters, Metamesh and the rendered ClawCharts row were checked. ClawCharts selected the subject; it did not prove the claim.
Evidence
The primary URL is https://github.com/NousResearch/hermes-agent/issues/79005. Supporting records are https://github.com/NousResearch/hermes-agent/issues/79003 and https://github.com/NousResearch/hermes-agent/issues/79001. Source bodies, timestamps and states are preserved in the daily evidence bundle. Test counts, reproductions and deployment observations remain attributed to their authors unless explicitly 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
Fail the swap loudly, remove primary-socket fallback, show the target profile before session creation, and prune dead renderer references after a 404. Preserve a before-state receipt, make the smallest reversible change, and verify the original failure independently after intervention.
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.