"One Gateway Owns Every Conversation" — and the Defaults Decide Who's In It
The pitch is continuity: your chat follows you across the terminal, the desktop app, a browser tab, your editor, the team bot and cron. The part nobody explains is that the conversation is no longer a thing on your device — it is one server-side session that many clients and people attach to, and the platform's defaults, not your intent, decide who shares it.
For solo operators and small-team builders running an agent gateway — Hermes, or any platform converging CLI/desktop/browser/bot onto one always-on backend — who have put the agent in one or more team channels, now open the same agent from more than one device, and have been reading "it's all one conversation" as pure convenience.
---
The result, up front
You can keep the continuity and still set the boundaries on purpose. The thing that makes that possible is a six-question session-boundary audit, run per surface before you let an agent listen there:
- Resolve.** What session does a message here produce —
dm,group,thread, Webapp, or cron? A session key is derived from where the message came from, not chosen by you. - Share. Is it isolated or shared by default, and have you changed that? Groups isolate per user; threads share**; DMs are private.
- Reach.** Who else is in the session — which humans, and which non-human clients (cron, bots, editors, the Webapp)?
- Authority. What can a participant do** from this surface — for a browser, is a sign-in equivalent to shell on the host account?
- Budget.** What can this session spend on paid tools, and is the limit enforced even when approvals are off?
- Recover.** How do you rewind, fork, or cancel it?
The decision rule that falls out: never infer isolation from the room you are in — read the default per surface, and set it on purpose.
That is the whole reader outcome. The rest of this article is why it is the right check — why "one gateway, every conversation" is a continuity feature and an identity question at the same time, why the same platform isolates the room but shares the thread, and why a browser tab that opens your workspace carries the authority of a shell. It is also careful about what the defaults do prove, because the easy overcorrection here is to call a protective default a defect.
---
The thing as it is usually presented
On November 5, 2026, Nous Research shipped Hermes Agent v0.23.0, "The Hearth Release." The headline, in the release's own words:
"Your whole Desktop workspace now opens in a browser tab, served by your own gateway. Underneath it, every conversation lives in one place: a single gateway owns each session, and the CLI, TUI, Desktop, editors, bots and cron all sit down at the same table instead of each running its own agent." (Hermes Agent v0.23.0.)
And the problem it fixes:
"Before, the CLI, TUI, Desktop, editors (ACP), messaging bots and cron could each run their own copy of the agent against the same chat, which is how messages got written twice or went missing between surfaces." (Hermes Agent v0.23.0.)
So the surface version is seductive and largely true: one gateway owns every session; every client attaches to it; "a chat you open anywhere is the same chat, with one queue and one history." (Hermes Agent v0.23.0.) Convenience, everywhere, for free. The rest of this piece is about the part that version leaves out.
---
The part nobody explains
When one process owns every session and every surface attaches as a client, a conversation stops being a thing on your device and becomes a server-side object with an identity. That identity — which session a message lands in, and therefore who shares it — is derived, not chosen.
Hermes's own developer guide spells out the derivation. A session "represents a continuous conversation between the agent and one or more users on a messaging platform," and its key is built by build_session_key(source, group_sessions_per_user, thread_sessions_per_user) from the message's origin, roughly:
`
platform : chat_type : chat_id [: thread_id][: participant_id]
`
where chat_type is one of dm, group, channel, thread and "controls session key generation and isolation." (Gateway Session Lifecycle.)
Two config booleans sit on top, and the whole sharing decision falls out of them:
`
if source.chat_type == "dm": return False # DMs are always private
if source.thread_id: return not thread_sessions_per_user # Threads: shared unless per-user
return not group_sessions_per_user # Groups: isolated unless shared
`
Read that slowly, because it is the whole article. Who shares a conversation with whom is a function of where a message came from plus a default you probably never read — not of what you intended when you set the room up. The platform lays out the lanes; you inherit them unless you deliberately look.
That is why one gateway is both a continuity feature and an identity question. The convenience — "it's all one conversation" — is real. The question it hides is: whose conversation is it, when several clients and several people attach to the same session?
---
Why that part matters: the defaults are asymmetric
Here is where a careful operator gets caught, because the rules are not uniform. They differ by chat type, and the differences point in opposite directions. All of these are from the vendor's own session-lifecycle doc (the same table):
| Surface | Default | What it means |
|---|---|---|
| DM | Private (never shared) | DMs are always private; this one never changes |
| Group / Channel | Per-user isolation | group_sessions_per_user defaults to True — "group/channel sessions are isolated" |
| Thread | Shared | thread_sessions_per_user defaults to False — "threads are shared by default (Telegram forum topics, Discord threads, Slack threads all share one session per thread)" |
Same platform. Same bot. Two opposite answers to "who shares this conversation," and the docs state both in the same table. A reader who learns "our agent isolates per person" from a group channel and then assumes the same in a thread is wrong. A reader who learns "threads are collaborative" and assumes the same of a group is wrong in the other direction. The failure mode is generalizing from the room you are in instead of reading the default per surface.
The release makes this matter now because the surfaces it added are all controls over the same new object — a persistent session that many clients and people touch. /rewind (press Esc twice, or type /rewind, "pick an earlier message, then edit and resend it or fork a new session from that point"), spend limits on paid tools, Group Chat rooms where "a lead bot, or an automatic router, picks] who answers a message that names nobody," and the browser Webapp. ([Hermes Agent v0.23.0.) Every one of those is a knob on the same session — which means every one of them is a boundary you can either set or inherit.
Worked example, kept small. You connect Hermes to a Discord server. Your team uses a shared channel for the bot, and someone opens a thread under a message to ask a follow-up. Run the audit by default alone, before you change anything:
- Resolve:* the channel message is
chat_type = group; the thread reply ischat_type = thread. - Share:* the channel isolates per user (the default) — each person talking to the bot in that channel gets their own session, their own history, their own tool costs. The thread does not: it is shared by default, so every participant in that thread sees the same context. (Discord guide.)
- Reach:* in the shared thread, the humans in that thread share one transcript — and any non-human client that posts there attaches to the same session.
So a "private" 1:1 follow-up inside a Discord thread is not private from the other thread participants. Nothing broke. You simply never chose. The default for a thread is collaboration, and you have to know that before you rely on it.
---
The second half of the boundary: the client stops being the trust line
Continuity is the comfortable half. The uncomfortable half is authority.
In the old model, "which app am I in" was a rough trust boundary — the CLI was your shell, a chat bot was a chat bot. When one gateway owns every session and every surface attaches to it, that boundary moves. The meaningful question becomes which session this message resolves to, and what the gateway itself can reach.
The vendor makes the sharp end concrete, and does not soften it. From the Desktop guide's warning box:
"Treat Webapp access like access to Hermes on the host. A signed-in Webapp user can run arbitrary commands as the OS account running Hermes, run agent tools, use host files and Git, and reach that account's environment and credentials. Do not expose it without a sign-in provider. Prefer an SSH tunnel, Tailscale or another trusted VPN." (Hermes Desktop.)
The Webapp "serves this workspace to a normal browser: sessions, profiles, Capabilities, Messaging, Artifacts, scheduled jobs, the host file tree, Git review, previews and the terminal rail," and it "is not the Web Dashboard." (Hermes Desktop.) A browser sign-in is not a window into a chat app — it is equivalent to shell on the host account.
Two scoping facts matter, and both are in the vendor's favor. The Webapp is off by default — "Nothing is served to a browser until you turn on webapp.enabled or Web Access" (Hermes Agent v0.23.0) — and exposing it remotely requires a sign-in gate ("username and password for a trusted LAN or VPN, OAuth/OIDC for anything internet-facing"). (Hermes Desktop.) This is not a hole. It is a boundary you have to draw deliberately, because convenience ("open my agent in a browser tab") and authority ("that tab is a shell") arrive in the same feature.
The same logic runs through paid tools. v0.23.0 adds "price tags and spend limits for paid tools" (Hermes Agent v0.23.0), and the MCP guide explains that the limit is enforced per chat, at the MCP layer, even when approvals are off: "YOLO (/yolo, --yolo) and approvals.mode: off skip the trust: untrusted prompt… but not the spend limit: below the limit a costed call runs without asking, and a call that would cross it still asks (or is refused where nobody can answer, such as a cron job with approvals.mode: off)." (MCP.) Worth knowing, and worth stating precisely: that caps cost on declared-cost tools, per chat — it is not a blanket budget over the model API itself.
---
Where the claim is roughly right, and where it falls apart
Be fair to "it's all one conversation, and it's mine." It is not a dumb read; it is an incomplete one.
Where it is roughly right:
- The continuity is real.** "A chat you open anywhere is the same chat, with one queue and one history," and you can "steer or edit a queued prompt from Desktop without it running twice." (Hermes Agent v0.23.0.) One gateway genuinely removes the double-write/missing-message class of bug.
- The isolation defaults are protective, not reckless. Groups and channels isolate per user by default; DMs are always private; the Webapp is off by default** and gated behind sign-in for remote exposure. (Gateway Session Lifecycle; Hermes Desktop.) Anyone calling this "an insecure gateway" is overstating.
- Thread-sharing is an intentional policy default.* The change is literally named "shared thread sessions by default — multi-user thread support," and the doc says "threads are shared by default." (Gateway Session Lifecycle.) It is a choice* a collaborative room may want, not a bug.
Where it falls apart:
- Isolation is conditional, and the vendor says so. The issue is not that the default is wrong; it is that the default is per surface and conditional. Hermes's own Discord doc names the cause of unexpected shared context directly: "
group_sessions_per_useris disabled, or the platform cannot provide a user ID for the messages in that context.**" (Discord.) So "isolated by default" is only true where the platform supplies stable identity. Where it doesn't, the group isolates in principle and shares in practice — and you would not know unless you looked. - Generalizing across surfaces is the real mistake.** Learning "we isolate per user" from a group and applying it to a thread (or vice versa) is the exact failure the asymmetric defaults set up. (Gateway Session Lifecycle.)
- The client is no longer the boundary.** "Which app am I in" told you almost nothing once every surface attaches to one authority — and the browser surface is shell-equivalent to a signed-in user. (Hermes Desktop.)
What the evidence does not prove — and the research packet is explicit:
- It does not show Hermes is insecure, or that its defaults are wrong. Groups isolate per user by default, DMs are always private, the Webapp is off by default, and remote access requires a sign-in gate. The claim is that the sharing rules are asymmetric, default-set, and easy to read wrong — an operator problem, not a product defect.
- It does not show that any leak, breach, unauthorized access, or dollar loss has occurred. No incident is cited. Do not imply one.
- It does not show that thread-sharing (or group-isolation) is unique to Hermes or new in 0.23.0. The mechanism — a session is a shared server-side object and defaults decide its sharing — is general to agent gateways and chat platforms. Hermes is the case study, not the exception.
- It does not measure context bleed, token cost, or interrupt collision. The evidence is the documented default and the docs' own description of shared-mode consequences ("users share context growth and token costs… one person's in-flight run can interrupt another person's follow-up in the same room"); no numbers are given. (Discord.)
- It does not show that a signed-in Webapp user will reach credentials in normal use — only that the vendor states the surface carries the host account's authority.
- It does not show that operators are getting this wrong at scale. The misread is a plausible mechanism inferred from the defaults' asymmetry, not a measured behavior.
---
The better version of the claim
Stated the way it survives contact with the evidence:
"One gateway owns every conversation" is a continuity feature and an identity question at once. A conversation is now a server-side session that many clients and people attach to, and the platform's defaults decide who shares it before you do — groups isolate per user, threads share one context, DMs are private, and a browser sign-in equals host shell. So the operator's real control is not which app they open; it is which session the message resolves to, whether it is shared, who can attach, and what it can reach and spend.
That sentence keeps everything true about the release — the continuity, the protective defaults, the off-by-default Webapp — and drops only the thing that was never true: that "it's all one conversation" told you who was in it.
---
What changes if you act on it: the session-boundary audit
Six questions, run per surface, before you let an agent listen there. None requires reading source code, and each maps to something the vendor already documents.
- Resolve — what session does this produce?**
dm,group,thread, Webapp, or cron. The key is derived from the message's origin (chat_type, plusthread_idor participant where present), so two different origins produce two different sessions even in the "same" room. (Gateway Session Lifecycle.) - Share — isolated or shared by default, and did you change it?* Groups isolate per user (
group_sessions_per_user: true); threads share (thread_sessions_per_user: false); DMs are private. Read the default for that surface*, not for the room. (Gateway Session Lifecycle.) - Reach — who else is in it?* Name the humans and* the non-human clients: cron jobs that post into the room, bots, ACP editors, the Webapp. And check the identity caveat — isolation only holds where the platform supplies a stable user ID. (Discord.)
- Authority — what can a participant do here?** For a browser surface, sign-in is equivalent to shell on the host account: arbitrary commands, host files and Git, the account's environment and credentials. Treat it exactly that way. (Hermes Desktop.)
- Budget — what can this session spend?** Paid MCP tools can declare per-tool costs and a per-chat
spend_limit, and the limit holds even under YOLO/approvals.mode: off— but it is per chat and at the MCP layer, not a blanket cap on model spend. (MCP.) - Recover — how do you rewind, fork, or cancel it?**
/rewindedits an earlier prompt or forks a new session (the original stays as it was), andrewind_sessionbacks up user turns via soft-delete to keep an audit trail. Know the recovery before you need it. (Hermes Agent v0.23.0; Gateway Session Lifecycle.)
The decision rule. Never infer isolation from the room you are in — read the default per surface and set it on purpose. Then add the second half: remember that one of those surfaces is shell-equivalent, so keep it off until you need it and behind a sign-in when you do.
Worked example — the "private" thread, resolved. You want a 1:1 conversation with the agent inside a busy Discord server, so you open a thread under a message and assume it is private like a DM. It is not: the thread resolves to a shared session by default, so the other thread participants share the context and see the same transcript. The fix is not to distrust the gateway. It is one of two deliberate choices: take the 1:1 into a DM (always private), or set thread_sessions_per_user: true for that room so threads isolate per user. Either way, you now know which line in the config decides your exposure — and it was never the room you were standing in.
---
Where you will get stuck
- "So Hermes shipped an insecure gateway." No — and this is the overcorrection the whole piece is written against. Groups and channels isolate per user by default, DMs are always private, the Webapp is off by default**, and remote exposure requires a sign-in gate. The claim is narrower: the sharing rules are asymmetric, default-set, and easy to read wrong. (Gateway Session Lifecycle; Hermes Desktop.)
- "Threads are shared, so thread-sharing is the flaw."* It is an intentional policy default ("feat: shared thread sessions by default — multi-user thread support"), and a collaborative room may want it. The lesson is to know* the default per surface, not that the default is wrong for everyone. (Gateway Session Lifecycle.)
- "The docs say groups isolate, so we're isolated everywhere." Conditional. "
group_sessions_per_useris disabled, or the platform cannot provide a user ID for the messages in that context.**" Where identity is missing, isolation is documented but not achieved. Name it to yourself before you rely on it. (Discord.) - "The Webapp is just another chat window."** The vendor's own warning says otherwise: "Treat Webapp access like access to Hermes on the host… arbitrary commands as the OS account running Hermes… host files and Git… environment and credentials." Keep it off until you need it, and behind a sign-in when you expose it. (Hermes Desktop.)
- "The spend limit is my cost control."** It is per chat, MCP-layer, and depends on the server declaring
tool_costs. It holds even when approvals are off — but it is not a blanket cap on model spend. (MCP.) - "This is a Hermes-specific problem."** It is not. The mechanism — one gateway owns every session, a session is a shared server-side object, and defaults decide its sharing — generalizes to any platform converging Slack/Teams bots, a desktop app, a browser surface, and cron onto one backend. Hermes is the sharpest example only because the model is written down. (Hermes Agent v0.23.0.)
- "While I'm at it — what about plugin install trust / generic cost caps?" Keep the distinction. Extension install hygiene and the plugin's blast radius belong to the marketplace/extension-trust story; a generic cost-cap/heartbeat pattern is its own piece. This** piece owns session identity and isolation: what a conversation resolves to, who shares it by default, and what a surface can reach.
---
The compressed ending
- A conversation is now a server-side session with an identity — and the identity is derived, not chosen.** The key is built from where a message came from (
platform : chat_type : chat_id: thread_id][: participant_id]) run through two config booleans. Who shares it is decided before you think about it. ([Gateway Session Lifecycle.) - The defaults are asymmetric. Groups isolate per user; threads share**; DMs are private; a browser sign-in equals host shell. Generalizing from one surface to another is the failure mode. (Gateway Session Lifecycle; Hermes Desktop.)
- One gateway moves the trust boundary from the client to the session.** "Which app am I in" stops being a boundary once every surface attaches to one authority. (Hermes Agent v0.23.0.)
- Isolation is conditional, not absolute.** It holds only where the platform supplies a stable user ID. (Discord.)
None of this is an argument to distrust the gateway — it is an argument to stop reading "it's all one conversation" as the answer, and to run the boundary question yourself, six questions per surface.
Read the default per surface, not the room you are in. Keep the shell-equivalent surface off until you need it. And set the boundary on purpose, or you are sharing a conversation — and sometimes a shell — you never agreed to share.
---
Sources
- Nous Research — "Hermes Agent v0.23.0 — The Hearth Release" (Nov 5 2026; tag v0.23.0): the "single gateway owns each session" headline and the "before" model; "a chat you open anywhere is the same chat, with one queue and one history";
/rewind; Group Chat rooms and the automatic router; "Price tags and spend limits for paid tools"; and the upgrade note "The Webapp is off by default. Nothing is served to a browser until you turn onwebapp.enabledor Web Access.": <https://github.com/NousResearch/hermes-agent/releases/tag/v0.23.0> - Nous Research — "Gateway Session Lifecycle" (developer guide, last updated 2026-06-16): the session definition;
build_session_key(source, group_sessions_per_user, thread_sessions_per_user);chat_type∈ {dm, group, channel, thread};group_sessions_per_user(defaultTrue) — "group/channel sessions are isolated";thread_sessions_per_user(defaultFalse) — "threads are shared by default (Telegram forum topics, Discord threads, Slack threads all share one session per thread)"; theis_shared_multi_user_sessiondecision logic; the DM/Group/Thread summary table; andrewind_sessionsoft-delete audit trail: <https://hermes-agent.nousresearch.com/docs/developer-guide/gateway-session-lifecycle> - Nous Research — "Hermes Desktop" (user guide): the Webapp serves "sessions, profiles, Capabilities, Messaging, Artifacts, scheduled jobs, the host file tree, Git review, previews and the terminal rail"; "the same process that serves the CLI, the native Desktop and messaging"; the warning box ("Treat Webapp access like access to Hermes on the host… arbitrary commands as the OS account running Hermes… host files and Git… environment and credentials"); and the sign-in-gate requirement (LAN/VPN username+password; OAuth/OIDC for internet-facing): <https://hermes-agent.nousresearch.com/docs/user-guide/desktop>
- Nous Research — "MCP (Model Context Protocol)" (user guide): per-tool
tool_costsand per-chatspend_limit; "YOLO (/yolo,--yolo) andapprovals.mode: offskip the trust: untrusted prompt… but not the spend limit… a call that would cross it still asks (or is refused where nobody can answer, such as a cron job)": <https://hermes-agent.nousresearch.com/docs/user-guide/features/mcp> - Nous Research — "Discord" (user guide): "By default, Hermes isolates session history per user inside the channel"; the per-thread session namespace; and the conditional-isolation caveat — shared context occurs when "
group_sessions_per_useris disabled, or the platform cannot provide a user ID for the messages in that context," with "users share context growth and token costs… one person's in-flight run can interrupt another person's follow-up in the same room": <https://hermes-agent.nousresearch.com/docs/user-guide/messaging/discord> - Hermes AI News (indexing AlphaSignal) — "Nous Research's Hermes Agent Unifies Every Client Behind one Gateway" (Nov 5 2026, secondary, corroboration only): "One shared gateway backs CLI, TUI, Desktop, ACP, webapp, and messaging platforms on the same live session"; shared spaces "create an isolated session for each sender when the platform supplies a user ID"; "The default favors isolation.": <https://hermes-ai.net/news/nous-research-s-hermes-agent-unifies-every-client-behind-one-gateway>
Editor flags before publish (do not ship without re-checking):
- Snapshot.** v0.23.0's feature set, the exact config keys and their defaults (
group_sessions_per_user: true,thread_sessions_per_user: false), the Webapp mechanics, and the catalog-count/feature anchors are an early-November-2026 snapshot and will drift within weeks. Write and date the piece "as of early November 2026." Decay is low for the tension and the mechanism (structural, generalizes to every unified agent gateway); low-to-medium for the anchors. - Not claimed. Do not write "Hermes shipped an insecure gateway" or "the isolation defaults are wrong." Groups isolate per user by default**, DMs are always private, the Webapp is off by default, and remote access requires a sign-in gate. Thread-sharing is an intentional policy default, not a bug. No incident ties any of this to a real harm.
- Conditional, labelled.** Per-user isolation depends on the platform supplying a user ID — the vendor's own Discord doc says so. Present isolation as conditional, not absolute.
- Scoped. The Webapp warning applies to a signed-in user; the docs require a sign-in provider before exposure, and the Webapp is off by default — do not suggest the loopback default is reachable without a sign-in. The spend limit caps cost on declared-cost, per-chat, MCP-layer** tools — not a blanket model-spend cap.
- Attribution. The gateway consolidation (one process owning every session, every surface attaching) is the new** part in v0.23.0; the isolation config keys and their defaults are documented policy (lifecycle doc stamped 2026-06-16). The piece's claim is that 0.23.0 is when the policy starts to matter, because sessions are now shared across surfaces.
- Distinct from neighbours.
listed-is-not-a-safety-check(Nov 6) owns extension install trust / plugin blast radius;agent-plugin-trust(Oct 9) owns agent-extension install hygiene;budget-circuit-breaker(Sep 18) owns the generic cost-cap/heartbeat pattern;agent-is-the-integration-layer(Nov 4) owns the agent operating existing tools. This piece owns session identity and isolation**: what a conversation resolves to, who shares it by default, and what a surface can reach. If a revision drifts into install hygiene, generic cost caps, or "the agent operates your tools," it has become a re-argument — send it back. - Held, not folded in.** The plugin auto-update switch ("Plugins that keep themselves current") sits in genuine tension with the catalog's "no self-updater" rule — but that belongs to the Nov 6 marketplace/extension-trust story. Do not fold it into this piece.
---
X entryway list (from the approved angle)
Distribution entryways named in the angle brief. Hooks are not yet written as posts — this names each post's type, the one claim or mechanism it carries, and whether it links.
- Hook type: proof (surprising). Hermes's own docs:
group_sessions_per_userdefaults to true — "group/channel sessions are isolated" — whilethread_sessions_per_userdefaults to false** — "threads are shared by default (Telegram forum topics, Discord threads, Slack threads all share one session per thread)." Same platform, same bot, two opposite answers to "who shares this conversation" — in the same table. → Links to article (the pair of defaults is the entry; the article develops what the asymmetry means for you and the per-surface audit it forces). - Hook type: mechanism. A session key is derived, not chosen*:
platform : chat_type : chat_id[: thread_id][: participant_id], run through two config booleans. So who shares a conversation is decided by where a message came from* plus a default you probably never read — not by what you intended when you set the room up. → Links to article (the mechanism stands alone; the article walks the derivation and the audit). - Hook type: workflow. Run the session-boundary audit per surface: (1) what session does this resolve to (dm/group/thread/Webapp/cron); (2) isolated or shared by default, and did you change it; (3) who else is in it — humans and cron/bots/editors/Webapp; (4) what can a participant do here (browser = shell); (5) what can it spend; (6) how do you rewind/fork/cancel. Never infer sharing from the room — read the default per surface.** → Links to article (the checklist is the actionable unit; the article is why each line holds and the worked examples).
- Hook type: risk.** One gateway owns every session and every surface attaches to it — which is exactly why the client stops being the trust boundary. The vendor's own Desktop doc: "A signed-in Webapp user can run arbitrary commands as the OS account running Hermes… and reach that account's environment and credentials." The surface you open quietly carries the authority you granted. → Links to article (names the limit in one line; the article shows how the boundary moved and how to keep it drawn).
- Hook type: result. The fix is not to distrust the gateway — it is to set the boundaries. Know that groups isolate and threads share** (so a "private" 1:1 in a Discord thread is not private from the other thread participants), keep the Webapp off until you need it and behind a sign-in, and give each session a spend limit that holds even when approvals are off. → Links to article (the reframe is the post; the article carries the audit and the decision rule).
Hook-type map: 1 = proof; 2 = mechanism; 3 = workflow; 4 = risk; 5 = result. All five link, and each link is a bonus — every post carries a claim that stands alone. These are the five entryways the approved angle named; none was invented and none repeats another's hook.