From 12859e9eb555f0e69eadca69f8b528e7856d75a6 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Sat, 15 Aug 2026 04:08:59 -0700 Subject: [PATCH] docs: add Connecting Desktop to Many Hermes Instances guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New user-guide page for the multi-connection registry (Settings → Connections): connection kinds + auth table, unique device names, v1 migration, union agent roster with @name-device handles, lazy sockets / ssh connect-on-demand, fleet-wide updates (cloud excluded), plugin SDK surface (host.connections/agents/ensureAgent/warmAgent, Bot Mode as reference consumer), troubleshooting. Registered in sidebars.ts; cross-linked from desktop.md and multi-profile-gateways.md. Docusaurus build validated. --- website/docs/user-guide/desktop.md | 2 +- .../user-guide/multi-connection-desktop.md | 119 ++++++++++++++++++ .../docs/user-guide/multi-profile-gateways.md | 4 +- website/sidebars.ts | 1 + 4 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 website/docs/user-guide/multi-connection-desktop.md diff --git a/website/docs/user-guide/desktop.md b/website/docs/user-guide/desktop.md index e46839937f..68de972a12 100644 --- a/website/docs/user-guide/desktop.md +++ b/website/docs/user-guide/desktop.md @@ -230,7 +230,7 @@ Connection modes are configured **per profile** — a per-profile override can p ### Settings → Connections: the multi-connection registry -Alongside the per-profile connection mode above, **Settings → Connections** manages a named registry of every agent source the app knows about — the local runtime, any number of remote gateways (LAN, Tailscale, internet), Hermes Cloud instances, and SSH hosts — all persisted together in one place. +Alongside the per-profile connection mode above, **Settings → Connections** manages a named registry of every agent source the app knows about — the local runtime, any number of remote gateways (LAN, Tailscale, internet), Hermes Cloud instances, and SSH hosts — all persisted together in one place. The full guide, including the union agent roster, `@name-device` handles, fleet-wide updates, and the plugin SDK surface, is at [Connecting Desktop to Many Hermes Instances](./multi-connection-desktop.md). - **Every connection needs a unique name** (a device name such as "Homelab" or "Work laptop"). When the same profile name exists on several registered sources, surfaces disambiguate it as `@profile-device` (e.g. `@research-homelab`). - **Add / edit / remove / test** connections from the panel. The local entry is managed by the app and cannot be removed. **Test** probes the connection's own HTTP and WebSocket legs directly. diff --git a/website/docs/user-guide/multi-connection-desktop.md b/website/docs/user-guide/multi-connection-desktop.md new file mode 100644 index 0000000000..8af9f9ba9f --- /dev/null +++ b/website/docs/user-guide/multi-connection-desktop.md @@ -0,0 +1,119 @@ +--- +sidebar_position: 5 +--- + +# Connecting Desktop to Many Hermes Instances + +Register every Hermes backend you own — the local runtime, remote gateways on +your LAN or VPS, SSH hosts, and Hermes Cloud instances — in one desktop app, +and use the agents on all of them side by side. + +This is the desktop-side complement to +[Running Many Gateways at Once](./multi-profile-gateways.md): that page is +about hosting several gateways on one machine; this one is about one desktop +app talking to several machines. + +## The connection registry + +**Settings → Connections** manages a named registry of agent sources. Each +entry is a *connection*: + +| Kind | What it is | Auth | +|---|---|---| +| **Local** | The runtime this app manages on your machine | automatic | +| **Remote gateway** | A `hermes serve` backend reachable over HTTP(S) — LAN, Tailscale, VPS | session token or OAuth | +| **SSH** | A Hermes install reached over SSH; the app opens the tunnel and starts the dashboard for you | SSH key + adopted token | +| **Hermes Cloud** | A hosted instance discovered through your Nous account | portal sign-in | + +Rules worth knowing: + +- **Every connection needs a unique device name** ("Homelab", "Work laptop"). + The name shows up everywhere the instance appears — roster badges, handles, + update results. +- The **local** entry is managed by the app and cannot be removed. Removing + any other connection tears down its live backends and tunnels; the instance + itself is untouched. +- **Test** probes the connection's own HTTP *and* WebSocket legs, so a pass + means chat will actually work — not just that the host pinged. +- Cloud entries come from the Hermes Cloud sign-in/discovery flow, not a + hand-typed URL. +- Tokens are encrypted with the OS keyring (same plain-text opt-in as + Settings → Gateway on keyring-less Linux), and never leave the Electron + main process. + +### Migrating from the single-connection settings + +The first launch of a registry-capable build imports your existing settings +automatically: the global connection mode and any per-profile overrides from +Settings → Gateway become named registry entries (deduplicated by URL/host). +The legacy settings file is left untouched, so older builds on the same +machine keep working. + +## Agents across sources + +Every profile on every registered connection is an *agent*. The union roster +is what multi-source surfaces (and plugins like +[Bot Mode](https://github.com/NousResearch/Hermes-Bot-Mode)) render: + +- When the same profile name exists on several sources, handles disambiguate + as **`@name-device`** — `research` on your Homelab renders as + `@research-homelab`, while a profile unique across all sources keeps its + bare name. +- Enumeration is eager but sockets are lazy: the app lists agents over REST + without dialing every source's WebSocket. An unreachable source reports + per-row instead of breaking the roster; SSH sources stay connect-on-demand + until you first open an agent on them (no surprise tunnels). +- Opening an agent dials **its own source** — chats, sessions, and memory + live on the machine that owns the profile, exactly as if you were using + that instance directly. + +Each `(connection, profile)` pair gets its own backend and socket, pooled +with the same idle-reaping as local per-profile backends — background agents +keep streaming while you look at another source. + +## Updating every instance at once + +**Settings → Connections → Update all instances** dispatches `hermes update` +to every eligible connection in parallel: + +- **Local** updates through the app's own update pipeline (the same flow as + Settings → Updates). +- **Remote and SSH** connections are told to update themselves via their own + backend — the update runs on *that* machine. +- **Hermes Cloud** instances are skipped: the platform manages their + versions. + +Each instance reports independently, so one unreachable box never wedges the +batch. Backends that manage updates externally (Docker, Nix) refuse politely +with their own message, per row. + +## For plugin authors + +The Desktop [plugin SDK](../developer-guide/desktop-plugin-sdk.md) exposes the +multi-source surface directly: + +- `host.connections()` — the registered connection list (labels, kinds, + primary; never token bytes). +- `host.agents()` — the union roster: one row per `(source, profile)` with + the precomputed `@name-device` handle. +- `host.ensureAgent(connectionId, profile)` — activate an agent's gateway so + subsequent `host.request` calls hit its backend. +- `host.warmAgent(connectionId, profile)` — fire-and-forget socket pre-warm + (hover-intent). + +All four are feature-detected: on an older Desktop build they're absent and a +plugin should fall back to the single-source `profiles.list` flow. Bot Mode's +multi-source roster is the reference consumer. + +## Troubleshooting + +- **An agent shows but won't open** — run **Test** on its connection. The + WebSocket leg failing while HTTP passes usually means a proxy, firewall, or + gateway auth/origin guard is blocking `/api/ws`. +- **A remote source is missing from the roster** — its backend is down or + unreachable; the roster lists it under sources with the error. SSH sources + show *connect-on-demand* until first use — that's by design, not a failure. +- **"Update Hermes Desktop to chat with agents on other connections"** — the + app predates the multi-connection stack; update the desktop app itself. +- **Duplicate device names** — not possible; names are enforced unique at + save time. If a migrated name collided, it was suffixed (`Homelab 2`). diff --git a/website/docs/user-guide/multi-profile-gateways.md b/website/docs/user-guide/multi-profile-gateways.md index b73d184595..7feddd069a 100644 --- a/website/docs/user-guide/multi-profile-gateways.md +++ b/website/docs/user-guide/multi-profile-gateways.md @@ -11,7 +11,9 @@ across profiles, preventing the host from sleeping, and recovering from common launchd/systemd quirks. If you only run one Hermes agent, you don't need this page — see -[Profiles](./profiles.md) for the basics. +[Profiles](./profiles.md) for the basics. And if your instances live on +*different* machines that one desktop app should reach simultaneously, see +[Connecting Desktop to Many Hermes Instances](./multi-connection-desktop.md). ## When to use this diff --git a/website/sidebars.ts b/website/sidebars.ts index 0839f3bbe6..d857d33ed6 100644 --- a/website/sidebars.ts +++ b/website/sidebars.ts @@ -53,6 +53,7 @@ const sidebars: SidebarsConfig = { 'user-guide/profiles', 'user-guide/profile-distributions', 'user-guide/multi-profile-gateways', + 'user-guide/multi-connection-desktop', 'user-guide/git-worktrees', 'user-guide/docker', 'user-guide/security',