Skip to main content

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: 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:

KindWhat it isAuth
LocalThe runtime this app manages on your machineautomatic
Remote gatewayA hermes serve backend reachable over HTTP(S) — LAN, Tailscale, VPSsession token or OAuth
SSHA Hermes install reached over SSH; the app opens the tunnel and starts the dashboard for youSSH key + adopted token
Hermes CloudA hosted instance discovered through your Nous accountportal 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) render:

  • When the same profile name exists on several sources, handles disambiguate as @name-deviceresearch 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 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).