把桌面端连接到多个 Hermes 实例
在一个桌面应用里注册你拥有的每个 Hermes 后端——本地运行时、LAN 或 VPS 上的远程网关、SSH 主机、以及 Hermes Cloud 实例——并并排使用它们上面的 agent。连接是持久的:每个已注册网关按需拨号自己的后端和 WebSocket,后台 agent 在你看另一个网关时继续流式输出。
本页是同时运行多个网关的桌面端对应篇:那页讲在一台机器上托管多个网关;本页讲一个桌面应用连多台机器。
在哪里找到它
一切都在统一的 Settings → Gateways 页(旧构建有分开的 Gateway 和 Connections 页;旧 Connections 深链重定向到这里)。三条门通向它:
- Settings → Gateways——页面本身(Cmd/Ctrl+,,然后设置导航里选 Gateways)。连接注册表是该页机器级连接模式控件下方的一个区段。
- 侧边栏 profile 栏——栏右端的插头按钮(tooltip:"Connect another Hermes gateway…")深链直达 Gateways 页。它始终可见,甚至在你创建第二个 profile 或第二条连接之前。
- 命令面板——Cmd/Ctrl+K,然后输入 Gateways(也匹配 connections、add gateway、remote、ssh、instances)。
网关注册表
Settings → Gateways 的 Registered gateways 区段管理一个具名的 Hermes 网关列表。它的介绍写得很明白:"管理这台设备以及它能通过远程、SSH 或 Cloud 连接到达的每个 Hermes 网关。" 每个条目是一条连接:
| 种类 | 是什么 | 认证 |
|---|---|---|
| Local | "由本应用托管的 Hermes 运行时。" | 自动 |
| Remote gateway | "通过 HTTP(S) 可达的 Hermes 网关——LAN、Tailscale 或公网。" | 会话 token 或 OAuth |
| SSH | "通过 SSH 可达的 Hermes 安装。"应用替你开隧道并启动仪表盘 | SSH 密钥 + 采纳的 token |
| Hermes Cloud | "通过你的 Hermes Cloud 账号发现的托管实例。" | 门户登录 |
值得知道的规则:
- 每条连接需要唯一的设备名("Homelab"、"Work laptop")。这个名字出现在该实例出现的每个地方——名册徽章、手柄、更新结果。唯一性不区分大小写,因此
Homelab和homelab不能共存。 - local 条目由应用管理(带 App-managed 徽章),不能删除。删除其他连接会拆掉它活跃的后端和隧道;实例本身不动。
- 总有一条连接是 Primary(其行上有徽章):它是未点名网关的多网关调用的注册表回退。Make primary 不切换当前 Sessions 工作区;删除 primary 回退到 local 条目。
- At startup, return to Sessions on the last-used gateway 控制完整重启后 Sessions 打开哪个网关。默认关闭,因此 Sessions 打开在 Primary。打开它可恢复上次成功连接的网关。失败的切换永不被记住;被删或不可达的已存网关回退到 Primary。
- Test 同时探测连接自己的 HTTP 和 WebSocket 两段,因此通过("Reachable" 提示)意味着聊天真的能用——不只是主机 ping 通了。
- 保存时拒绝重复:永远只有一个 local 条目;remote 和 cloud 条目按规范化 URL 去重(trim、去尾斜杠、小写——且跨两类,因此 cloud 条目和 remote 条目不能指向同一 URL);SSH 条目按规范化
user@host:port加远程 profile 去重。 - Cloud 条目通常来自 Gateways 页顶部的 Hermes Cloud 登录/发现流程——添加连接编辑器里的 Hermes Cloud 种类会把你导向那里。
从 Sessions 侧边栏切换网关。Profiles、聊天、消息和 cron 都保持在该网关作用域内;应用托管的窗口后端仍由上面的连接模式控件选择。Primary 是注册表回退,不切换当前工作区。
组织会话分组
在 Sessions 侧边栏的视图菜单里,查看所有 profile 时选 Gateway & profile。每个网关有自己可折叠的区段,profile 子区段包含它们的会话。两个带 default profile 的网关保持分开。网关头部以已存连接名开头;profile 头部显示 profile 名。
用网关或 profile 区段的菜单 Rename group、Reset name、Move up 或 Move down。改名只改侧边栏标签,不改网关或 profile。网关作为完整区段重排,profile 在自己网关内重排。把区段头拖到任何地方(图标、名字或空白处)重排,或聚焦头部用 Space、方向键、再 Space 放置。名字、顺序和折叠状态记在这台桌面机上。折叠网关保留其 profiles 各自的折叠状态。每个 profile 的新建会话动作指向其所属网关的该 profile。
门户发现未登录时,Hermes Cloud 面板也列出 Saved Cloud gateways。Use gateway 选择一个已有已存连接而不改默认网关;Active in this window 标识当前那个。添加新实例用其友好 Cloud 名,而已有自定义连接名保留。已存连接仍需有效的网关认证;从已注册连接控件管理登录。
逐步添加连接
- 打开 Settings → Gateways,滚到连接注册表(或点 profile 栏的插头)。
- 点 Add connection。
- 选种类:Local、Hermes Cloud、Remote gateway 或 SSH。(Local 在应用托管的 local 条目存在时禁用——几乎总是如此;Hermes Cloud 把你导向上面的 cloud 登录/发现流程。)
- 填字段:
- Name——必填、唯一;该实例出现处显示的"设备名"(占位符:
Homelab)。最多 64 字符。 - 仅 Remote gateway:
- Gateway URL——运行中的
hermes serve后端 base URL,如http://homelab.lan:9119。反向代理路径前缀可用。 - Authentication——选 Session token 或 OAuth:
- Session token——粘贴远程网关的仪表盘会话 token。编辑时 "Leave blank to keep the saved token."
- OAuth——通过 Nous Portal 浏览器流程登录;无需粘贴 token。
- Gateway URL——运行中的
- 仅 SSH:
- SSH host——一个
user@host:22形式的组合字段(user 和端口可选)。用你的 SSH 密钥;应用经隧道采纳一个仪表盘 token。远程探测在账号登录 shell 下运行;在zsh登录 shell 上探测看门狗无法杀掉整个进程组,因此挂起探测的孙进程可能在远程滞留(bash/sh 远程会回收它们)。 - Hermes path(可选)——远程上
hermes可执行文件的完整路径(如/opt/hermes/bin/hermes)。留空自动检测。当远程非交互 shell 的PATH上没有hermes且 Test 报 "Hermes is not installed on the remote host" 时设置它;清空字段恢复自动检测。
- SSH host——一个
- Name——必填、唯一;该实例出现处显示的"设备名"(占位符:
- 点 Save connection(或 Cancel)。
- 在新行点 Test,等 "Reachable"。
之后用铅笔按钮编辑任何非 local 条目,或用垃圾桶按钮删除——删除要求确认并提醒你 "The instance itself is not touched — you can add it again any time."
这里一切都要后端在那台机器上真的起来且可达才工作。桌面应用附上去;它不替你启动(SSH 连接除外,应用按需经隧道启动仪表盘)。后端侧设置见连接到远程后端——认证提供商、绑定非环回地址和 Tailscale 指引。
从单连接设置迁移
带注册表的构建首次启动会自动导入你已有设置:全局连接模式和 Settings → Gateway 中任何遗留的按 profile 覆盖,变成具名注册表条目(按 URL/host 去重)。(更新构建不再在 Gateways 设置页提供按 profile 覆盖——网关连接是机器级的,profile 从你连接的网关发现。)遗留设置文件原样保留,因此同机旧构建继续工作。如果迁移的名字冲突,会加后缀(Homelab 2)。
跨网关的 agent
每条已注册连接上的每个 profile 都是一个 agent。合并名册就是多网关界面(以及内置 Bot Mode 名册)渲染的:
- 当同一 profile 名存在于多个网关时,手柄消歧为
@name-device——你 Homelab 上的research渲染为@research-homelab,而在所有网关间唯一的 profile 保持裸名。 - 枚举是热切的,但 socket 是懒的:应用经 REST 列出 agent,不拨号每个网关的 WebSocket。不可达网关逐行报告而非破坏名册;SSH 连接保持按需连接,直到你首次打开其上的某个 agent(无意外隧道)。
- 打开一个 agent 拨号它自己的网关——聊天、会话和记忆都在拥有该 profile 的机器上,就像你直接用那个实例。
每个 (connection, profile) 对有自己的后端和 socket,按与本地按 profile 后端相同的空闲回收池化——后台 agent 在你看另一个网关时继续流式。
审批按钮路由回会话所属后端,而非当前选中的任何 profile。对于本地次要 profile,即使缓存的会话绑定缺失,Desktop 也能用投递请求的 socket。已存会话归属仍优先,删除或重命名那个本地 profile 会清除这条临时路由,而不是重连一个过时后端。
切换与作用域
侧边栏脚遵循一个层级:gateway → profile → sessions。网关是机器或托管后端;profile 是住在一个网关上的隔离 Hermes agent。
- 只有一个已注册网关时,不加网关控件。仅本地 Desktop 保持与之前相同的 profile 栏和键盘流程。
- 有多个网关时,侧边栏显示一个具名网关选择器。其设备、cloud、网络或终端图标标识连接类型;profile 头像在分隔符后作为单独控件。同一选择器从两个网关扩展到更大机群,不把后端变成 profile 样的字形,也不把 profile 动作挤出栏外。
- 选一个网关恢复那里上次用的 profile。home 药丸回到它的默认 profile,layers 药丸显示 All profiles on this gateway。Cmd/Ctrl+1–9 在没有窗格抢到它们时,继续在活跃网关内切 profile。
- 有多个网关时,profile 栏是一个机群栏:每条已注册网关的 profiles 排在同一条栏上,每组以该网关的种类字形(设备、网络、终端、cloud)打头——与网关选择器用的是同一字形。活跃网关的方块看起来与单网关 Desktop 完全一样;其他网关的方块变暗("at rest")。悬停 at-rest 方块显示其机器名(
omer · This device),因此不同机器上两个同名 profile 读起来绝不相同。 - 点 at-rest 方块执行与网关选择器相同的切换,落到那个确切的
(gateway, profile):目标拨号时方块转圈,前一个网关保持绘制直到目标应答,死目标以消息让点击失败,而不是让窗口半切换。无论哪个网关活跃,组保持注册表顺序,因此方块绝不会在点击它的指针下移动。右键 at-rest 方块提供 Switch to、Color、Rename、Edit SOUL.md 和 Delete,都在方块自己的网关上执行;删除确认会点名机器。 - 上次枚举够不到的网关保留其方块,字形上标一个琥珀点——一个睡着的盒子仍是你的。一个后端的两次注册折叠成单组。机群上超过 13 个方块时,栏折叠成一个按网关分段的菜单。
- 所选网关只有在 Settings → Gateways → At startup, return to Sessions on the last-used gateway 开启时,才跨退出重启保留。该偏好和网关 id 存在应用的用户数据注册表中,因此替换或更新应用包不会重置它们。
- 活跃网关上超过 13 个 profile 时,头像栏折叠成一个具名 profile 选择器。大的网关和 profile 集合可共存而不改变 gateway → profile → sessions 模型。
- 即使远程连接是 Primary,This device 仍是一等网关。远程宕机时它能保持本地会话可用,但应用不叫它"离线模式":所选模型或工具可能仍需联网。
- 会话列表、消息渠道、cron 任务、设置、文件和记忆都作用于活跃
(gateway, profile)。从 Telegram 网关切到 Signal 网关不会把前一个网关的渠道组或会话留在侧边栏。 - Desktop 启动时加载本地连接注册表,即使状态栏隐藏,并在网关保存或移除时保持最新。无需打开 Settings。Simple 模式下,注册了多于一个网关时 profile 栏保持可用,即使只有一个 default profile。加载注册表不连接每个网关;没有周期性机群轮询。
- 悬停一个 agent 预热其后端,切换不用付冷启动代价。SSH agent 是例外:悬停绝不拨号隧道或启动远程后端——只有打开一个才做。
- Capabilities 页(Skills / Tools / MCP)有匹配的作用域:其 Configuring 选择器列出合并名册中每个
(profile, device)agent,选一个就读写那台机器的 skills、工具集和 MCP 服务器,而不切换 Sessions 工作区。Hub 安装、env 键和 MCP 设置都落到所选 agent 的后端。MCP 标签页的热重载进活跃会话按钮只对窗口所连网关上的 agent 出现;其他机器上的编辑在它们下次会话生效。
在 Settings → Gateways 添加、测试、改名或删除网关。profile 动作旁的插头按钮是那个唯一管理主页的快捷方式,不是第二个添加流程。
Sessions 与 Bot Mode
Sessions 刻意一次只显示一个活跃网关:这让文件、工具、渠道、cron 和会话历史处于一个可理解的执行上下文。机群 profile 栏只加宽选择器——每次点击后工作区仍恰好在一个 (gateway, profile) 上。Bot Mode 服务于不同任务,可以呈现按网关分组的合并名册,让用户从一个界面在 NAS 上开一个 agent、在 VPS 上开另一个。打开一个 bot 仍激活它确切的 (gateway, profile) 路由。
直接 bot @提及和委派默认仍是网关本地的。跨越后端边界会改变文件系统、凭据、工具和信任上下文,因此跨网关执行应是显式的桥接,而非共享一个 Desktop 窗口的意外副作用。
一次更新每个实例
Settings → Gateways → Update all instances(注册了多于一条连接时显示)并行向每条合格连接派发 hermes update:
- Local 经应用自己的更新流水线更新(与 Settings → Updates 同一流程)。
- Remote 和 SSH 连接被告知经它们自己的后端自我更新——更新在那台机器上跑。
- Hermes Cloud 实例以 "Managed by Hermes Cloud" 提示跳过:平台管理它们的版本。
每个实例独立报告,因此一个不可达盒子绝不卡死整批。外部管理更新的后端(Docker、Nix)礼貌地逐行以自己的消息拒绝。
不过你很少需要那个 Settings 按钮:一旦存在多于一个更新目标,应用常规的更新入口(About 面板上的 Update now、⌘K Update Hermes、更新就绪提示)自动跑同样的扇出——先活跃后端,再其他每个合格网关,最后才是桌面应用本身。见桌面指南的更新。
安全说明
- token 存哪。 远程网关会话 token(以及按网关 base URL 作键的原生登录 OAuth token)作为属主只读(0600)文件存在应用用户数据目录里,在 Electron 主进程;渲染器和插件永远看不到 token 字节。
- 可选 keychain 加密。 默认 token 不经 OS keychain——尤其在 macOS 上,Electron 的
safeStorage把按应用密钥放在登录 keychain,而锁定或损坏的 keychain 会让每次启动都弹密码提示。如果你想在文件权限之上再加静态加密,打开 Settings → Gateway → "Encrypt saved secrets with the OS keychain";已有存储的机密就地重加密(macOS 用 Keychain,Windows 用 DPAPI,Linux 用 session keyring 后端)。再关掉会解密回来。 - 注册表文件(应用用户数据目录下的
connections.json)存标签、URL 和主机——机密只出现在加密信封内。 - 插件 SDK 的
host.connections()刻意只返回标签、种类和 primary id——绝不返回 token 材料。
给插件作者
桌面插件 SDK 直接暴露多网关界面:
host.connections()——已注册连接列表(标签、种类、primary;绝无 token 字节)。host.agents()——合并名册:每个(gateway, profile)一行,带预计算的@name-device手柄。host.ensureAgent(connectionId, profile)——激活一个 agent 的网关,让后续host.request调用命中其后端。host.warmAgent(connectionId, profile)——即发即忘的 socket 预热(悬停意图)。
这四个都做特性检测:在旧 Desktop 构建上它们缺失,插件应回退到单网关的 profiles.list 流程。Bot Mode 的多网关名册是参考消费者。
故障排查
- "Connection test failed"——后端从这台机器在那个 URL 不可达。确认
hermes serve在远程主机上跑着、端口开着、(token 认证)token 是新的。修好后重跑 Test。 - agent 显示但打不开——在其连接上跑 Test。HTTP 通过而 WebSocket 段失败,通常意味着代理、防火墙或网关认证/来源守卫挡住了
/api/ws。 - 名册里少了一个远程网关——其后端宕了或不可达;名册在带错误的网关下列出它。SSH 连接在首次使用前显示按需连接——这是设计,不是失败。
- "Update Hermes Desktop to chat with agents on other connections"——应用早于多连接栈;更新桌面应用本身。
- 重复设备名——不可能;保存时强制唯一。如果迁移的名字冲突,会加后缀(
Homelab 2)。 - "Could not save the connection"——最常见是缺 Name、名字已被占用、或 Gateway URL / SSH host 格式错;错误消息点名具体违反项。