Hermes Agent
Hermes finds profile collisions in shared gateway state
A Hermes Agent patch adds profile names to Telegram topic-mode state after multiple bots sharing one database overwrote each other’s chat bindings. Two Kanban reports expose the same multiplexing fault line: notifier ownership and profile stamps can silently route subscriptions to a gateway that cannot deliver them.
NousResearch/hermes-agent PR #76487 is the inspected primary source: “fix(gateway): namespace telegram topic mode by profile under multiplex.” The two related records below were inspected as supporting context, not treated as independent confirmation.
The facts
- NousResearch/hermes-agent PR #76487 was created 2026-08-02T00:50:34Z and was open at inspection; its title is “fix(gateway): namespace telegram topic mode by profile under multiplex.” - NousResearch/hermes-agent issue #76483 was created 2026-08-02T00:44:13Z and was open at inspection; its title is “hermes kanban notify-subscribe stamps notifier_profile with the invoking shell's profile, which named-profile gateways then skip.” - NousResearch/hermes-agent issue #76482 was created 2026-08-02T00:44:12Z and was closed at inspection; its title is “kanban notifier silently skips all subscriptions when an adapter-less gateway owns the dispatcher singleton.” - The repository reported 223842 stars, 26526 open issues, default branch main, and last push 2026-08-02T00:53:38Z. - The latest tagged-release baseline checked was v2026.7.30 published 2026-07-30T23:45:37Z.
What changed
NousResearch/hermes-agent PR #76487 reports: What does this PR do? When multiplex_profiles: true, every profile shares one state.db. The Telegram topic-mode tables were keyed only by Telegram identifiers: telegram_dm_topic_mode — PK (chat_id) telegram_dm_topic_bindings — PK (chat_id, thread_id) In private chats, chat_id is the user's Telegram id — **identical across bots**. Multiple profiles therefore collide on the same rows: last write wins, thread bindings get overwritten, replies fail with "Message thread not found." This PR adds a profile_name dimension to both tables and threads the **routed** profile (source.profile) through every gateway access path. Legacy rows migrate into the "default" namespace only (no replication across configured profiles). Split into two commits for
NousResearch/hermes-agent issue #76483 reports: Version:** 0.18.2, multi-profile install, per-profile gateways. Behavior:** subscriptions created from a chat session (_maybe_auto_subscribe) carry an *empty* notifier_profile and deliver fine. Subscriptions created via the CLI (hermes kanban notify-subscribe --platform slack --chat-id …) get stamped with the invoking shell's active profile — "default" from a root-HOME operator shell. The notifier's owner check (owner_profile and owner_profile!= notifier_profile → skip when _profile_adapters has no entry) then skips them forever in a gateway whose profile name is anything else. Net effect: CLI-created subscriptions never fire on named-profile gateways, with only a DEBUG line. Two aggravators for debugging: The delivery log prints profile=%s with sub_profile or "default" —
NousResearch/hermes-agent issue #76482 reports: Version:** 0.18.2, macOS, two profiles on one install, one gateway per profile (the documented multi-profile default). Setup:** profile A's gateway runs a custom iMessage plugin platform; profile B's gateway runs the Slack adapter. Kanban tasks are created from B's Slack sessions with auto-subscriptions back to the Slack thread. Behavior:** _kanban_notifier_watcher gates on dispatch ownership ("only the dispatch-owning gateway opens kanban DBs for notifier polling", gateway/kanban_watchers.py). Which gateway owns.dispatcher.lock is a restart race. When profile A's gateway (no Slack adapter) wins, every Slack subscription is skipped — but only at DEBUG ("adapter not connected"), so at default log levels notifications and artifact deliveries just stop
Why it matters
A shared state database needs tenant identity in every key and every ownership decision. Process-global defaults and restart-race singletons are especially dangerous because they turn isolation failures into silent missing messages. This is an operator boundary: persisted state, execution ownership and visible controls must describe the same event. A workaround that broadens access, deletes state or hides the symptom would trade a visible defect for an unmeasured one.
Current
The primary record was open when captured on 2026-08-02. The release baseline was v2026.7.30 published 2026-07-30T23:45:37Z. Current 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/pull/76487. Supporting records are https://github.com/NousResearch/hermes-agent/issues/76483 and https://github.com/NousResearch/hermes-agent/issues/76482. Their source bodies, timestamps and states were captured 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. Issue closure would not by itself prove a deployed fix. Search residue, package mirrors and historically published source spines were excluded.
Operator take
Migrate legacy rows into one explicit namespace, use the routed profile rather than shell state, and warn loudly when the dispatch owner lacks the adapter required by a durable subscription. 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.