Bot 屏幕
在无头 Linux 网关机(服务器、云 VM、Hermes Cloud)上,每个 bot 都有自己的桌面:一个 Xfce 屏幕,bot 的 computer_use 和有头浏览器在其上操作,并实时串流进 Hermes 桌面端。旁观 bot 的所作所为,在它遇到登录、两步验证、CAPTCHA 或付款步骤时接管,然后交还控制,让它带着你刚登录的会话继续。你关闭应用或合上笔记本后 bot 仍继续工作;屏幕活在网关机上,而非你的机器上。若网关在沙箱(terminal.backend: docker、ssh 或 singularity)中运行其 terminal,屏幕则活在该沙箱内部,与 shell 并列,因此 bot 的 computer_use 和浏览器绝不会在你划定的边界之外操作(见屏幕在哪里运行)。
每个 Hermes profile("bot")有自己的屏幕、自己的浏览器 profile 和自己的 cookie。屏幕是工作面,而非安全边界:bot 共享主机的用户账户、文件和网络(与其他托管 agent 产品同一模型)。
威胁模型。 屏幕的 RFB 套接字、X display、浏览器 profile 和控制租约文件都属于网关的 OS 用户。以该用户运行的任何进程——同一主机上的另一个 bot,以及 bot 自己的 terminal 工具——都能直接触及它们,绕过窗格和租约。租约是 computer_use 和浏览器工具上的工具级栅栏,而非 OS 级。有一个边界比 OS 用户更宽:Chromium 的 DevTools 端口(Dock 的 Browser 和每次 agent-browser 启动都在环回口上通告一个,以便 agent 挂载)可被主机上任何本地用户触及,而 Chromium 不对其提供按用户限制。让每个 bot 以独立 OS 用户运行超出范围;若这种隔离对你重要,或主机上有不可信本地用户,请把 bot 放到不同主机上。两个值得知道的时序细节:WebSocket 桥在两次重读租约文件之间缓存其租约决定最多 250 ms,因此另一进程做出的接管在该窗口内生效(无论窗口如何,bot 的工具结果都会被租约纪元作废)。而查看器的一次性、30 秒 display_ticket 刻意以 URL 查询参数传递——noVNC 无法协商 WebSocket 子协议,因此用 header 不是选项——这意味着反向代理的访问日志可能记录一个已用完的 ticket。
要求
-
网关机运行 Linux。macOS 和 Windows 主机已有真实显示器;那里不提供此窗格。
-
主机上已安装 TigerVNC 的
Xvnc和 Xfce 核心组件。没有任何东西静默安装它们:hermes update和全新安装都保持每台机器原样。缺失时,Hermes 桌面端的屏幕窗格显示在主机上安装——一键在网关机上运行包管理器(它在一张遮罩卡片中索要该主机的 sudo 密码;密码只去那台主机,绝不存储)并串流日志。当 Hermes 自身以 root 运行(容器中的常见情况),安装器直接运行包管理器,无 sudo、无密码卡片。当它不是 root、且主机完全没有sudo时,窗格和 CLI 打印确切安装命令供你在主机上运行,而非显示卡片。官方 Docker 镜像(nousresearch/hermes-agent,也驱动 Hermes Cloud)即属第二种情况:网关以非特权用户运行,镜像无sudo,因此窗格显示apt-get一行,由运维在容器中以 root 运行一次(docker exec -u 0 <container> apt-get install -y …)。若你想要 Dock 的 Browser 图标,把chromium加到那一行;见下文交接后仍存活的浏览器会话。从 shell 运行hermes computer-use screen status打印确切一行,hermes computer-use screen install执行它:发行版 包 Debian / Ubuntu tigervnc-standalone-server xfce4-panel xfwm4 xfdesktop4 xfce4-settings xfce4-terminal dbus-x11 x11-xserver-utils x11-utils xauth fonts-dejavu-coreFedora tigervnc-x11-server xfce4-panel xfwm4 xfdesktop xfce4-settings xfce4-terminal dbus-daemon xsetroot xset xdpyinfo xprop xorg-x11-xauth setxkbmap dejavu-sans-fontsArch tigervnc xfce4-panel xfwm4 xfdesktop xfce4-settings xfce4-terminal xorg-xsetroot xorg-xset xorg-xdpyinfo xorg-xprop xorg-xauth xorg-setxkbmap ttf-dejavuFedora 上
Xvnc二进制在tigervnc-x11-server(而非tigervnc-server-minimal),dbus-run-session来自dbus-daemon。刻意不用xfce4元包:它会拉入锁定或提示无头桌面的屏保、电源管理和 polkit agent。 -
为 bot 启用了Computer Use(已安装 cua-driver)。
-
内存。在官方镜像中实测:网关空闲约 300 MB,Xvnc + Xfce 增加约 220 MB,接管时人打开的有头 Chromium 增加 0.5–1 GB(一个页面约 550 MB)。按每个打开的屏幕带浏览器约 1.1–1.5 GB 规划;桌面本身很便宜,浏览器才是成本。CPU 不是约束(空闲桌面 ≈ 0.01 核,实时串流 ≈ 0.03 核)。这些包在 Debian 13 上占约 930 MB 磁盘。
开启屏幕前,Hermes 检查主机——或其容器 cgroup,取更紧者——有
bot_desktop.min_free_memory_mb空闲(默认 1536;0禁用检查)。低于此,窗格就地显示原因而非开启屏幕,hermes computer-use screen start拒绝;已在运行的屏幕绝不会被此检查关闭。无人使用的屏幕在bot_desktop.idle_stop_minutes(默认 30)后停止,下次使用时再起来,因此一个实例只在屏幕上有东西时才为桌面付费。小实例的实用建议:4 GB 跑桌面,8 GB 时带浏览器接管才舒适。
把包烤进容器镜像
托管或非特权部署的镜像不能在运行时安装任何东西,因此包必须预先构建进去。CI 为每个版本发布两种变体:不带包的无后缀标签(:latest、:v*),和带包的 -desktop 标签(:latest-desktop、:v*-desktop)。托管部署(Fly Machines、Azure 容器实例)通过拉取带后缀标签获得 Bot 屏幕;构建参数也无法触达它,因为它从不运行构建。目前 provisioner 中尚无东西选择 -desktop,因此托管实例仍以精简形态启动;你今天自己拉取带后缀标签即可。
只有当你想在自定义镜像中带这些包时才自行构建。官方 Dockerfile 有一个可选构建参数,默认关闭,使普通 docker build . 保持精简:
docker build --build-arg HERMES_BOT_DESKTOP=1 -t hermes-agent:screen .
它加入 TigerVNC、Xfce 组件和发行版 chromium(浏览器会话中所述的沙箱回退)——该 apt 层在 Debian 13 上实测约 930 MB。它不加入第二个 Playwright 浏览器:每个镜像,无论精简还是 -desktop,都已带 PM 固定的完整 Chromium,能开窗口。没有东西在启动时运行;这样构建的镜像在屏幕开启前不耗内存。
使用
每个 bot 的电脑在 Hermes 桌面端的三处都一键可达:
- Bots → 某 bot → Scheduled Jobs:bot 的屏幕作为主视觉位于窗格最顶部,在标题和例程之上:桌面的实时预览(窗格可见时每隔几秒刷新),并显示谁持有控制;点击图片展开为实时访问。屏幕关闭或未安装时同一方框会说明并提供 开启 / 安装。
- Bots → 右键某 bot → Open Screen。同一菜单有 Open Screen when the bot uses it:勾选后,在 bot 一次运行的首个
computer_use或浏览器调用时,屏幕标签页前置,让你看着它工作,而非事后才发现。默认关闭,按 bot 设置。它抬起标签页但不抢占你的键盘焦点,对重放历史从不触发,最多每 30 秒一次;若你在运行中途关闭标签页,它保持关闭直到 bot 下次运行。 - Sessions 侧边栏,按网关 / profile 分组:同一个 Screen 方框位于每个 profile 头部之下,因此一个 profile 的机器也可从其对话中触及。
- 用上述任一入口打开屏幕。屏幕默认关闭,没有东西替你启动它:在窗格中点击开启屏幕,在主机运行
hermes computer-use screen start,或设bot_desktop.auto_start: true——若你想让无头主机在 bot 首次computer_use调用或首次有头浏览器使用(browser.headed: true)时自行开启屏幕。它默认关闭,使安装 TigerVNC 绝不产生一个没人要的屏幕。有头浏览器在屏幕运行后即在其上打开。 - 窗格串流 bot 的桌面。头部芯片显示谁在控制:默认 Bot is in control。
- 点击 Take over。边框变红,你的键盘和鼠标现在驱动 bot 的屏幕。登录、解 CAPTCHA、批准付款。
- 点击 Hand back。bot 重新获得控制,并在继续前重新捕获屏幕。关闭窗格也交还控制。断开连接则不同:若你持有时笔记本合盖或 Wi-Fi 掉线,你保持控制——bot 被锁在屏幕之外,而你可能正登录到一半——直到你重连并交还。若你在重载后回来,窗格仍显示人类持有控制,会出现 Hand back (force) 按钮清除它。
你持有控制期间,bot 的 computer_use 和浏览器工具以 human_has_control 被拒绝,包括捕获。这是工具级栅栏,而非 OS 级:bot 以与其屏幕相同的用户运行。不要在一个你不信任的 bot 里输入机密。
当 bot 遇到不应自己做的步骤(登录、两步验证、CAPTCHA、付款),它在回复中说明并结束回合;请求到达你所在的任何聊天。你准备好时接管,完成该步骤,交还,并让 bot 继续。bot 等待期间没有东西阻塞在它那侧:接管永远由你发起,bot 绝不会为等你而把工具调用挂起。
一个屏幕上两个查看器:最近的 Take over 胜出;先前的控制者退回旁观。
交接后仍存活的浏览器会话
屏幕运行期间,bot 的浏览器工具和 Dock 的 Browser 图标是同一个浏览器:Chromium agent-browser 驱动,每个 bot 一个持久 user-data-dir(<HERMES_HOME>/bot-desktop/browser-profile;设 AGENT_BROWSER_PROFILE 固定你自己的——~ 会展开,相对路径如 pin 相对于该 bot 的 HERMES_HOME 解析,即 <HERMES_HOME>/pin)。接管期间点击 Browser,你就进入 bot 自己的窗口和 cookie 罐;你登录的东西就是 bot 之后及每个后续会话使用的东西,直到站点使登录过期。设 browser.headed: true,让 bot 自己的浏览也在屏幕上可见。
Dock 只播种一次,即某 profile 首次开启屏幕时。护栏是面板布局文件
<HERMES_HOME>/bot-desktop/xdg/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml:只要它存在,启动器就不碰面板,因此改 AGENT_BROWSER_EXECUTABLE_PATH 或 AGENT_BROWSER_PROFILE 并重启屏幕不会重新固定 Browser 图标。删除该文件,Dock 就在下次 screen start 时按当时安装的任何东西重建。
Dock 和 bot 用哪个 Chromium:显式 AGENT_BROWSER_EXECUTABLE_PATH 优先;否则 Hermes 用 PM 管理的 Chromium,并回退到系统 chromium / google-chrome。在有 kernel.apparmor_restrict_unprivileged_userns=1(Ubuntu 23.10 及更高)的主机上,非 root 用户得到相反顺序,因为那里管理的构建无法建立沙箱并以 FATAL: No usable sandbox! 退出,而发行版的 Chromium 带允许它的 AppArmor profile。若选错不适合你的主机,在网关环境中设 AGENT_BROWSER_EXECUTABLE_PATH=/usr/bin/chromium(或你的 Chrome 路径)。官方 Docker 镜像把 AGENT_BROWSER_EXECUTABLE_PATH 指向 PM 固定的完整 Chromium,能画窗口,因此 Dock 的 Browser 图标用它;-desktop 标签还带发行版 chromium——在拒绝固定构建沙箱的主机上设 AGENT_BROWSER_EXECUTABLE_PATH=/usr/bin/chromium。图标从不使用 Playwright headless shell:当它是唯一浏览器时,窗格 / screen status 报告无有头浏览器,直到你安装一个有头的(apt-get install chromium)。Dock 图标以 agent-browser 在该容器中使用的相同沙箱设置启动浏览器,因此人的 Browser 和 bot 的浏览器是同一个。
CLI
hermes computer-use screen status # 已安装?运行中?谁持有控制?
hermes computer-use screen start # 开启本 profile 的屏幕
hermes computer-use screen stop # 停止;人类持有时拒绝
hermes computer-use screen stop --force # ……除非你明说(也释放卡住的租约)
hermes computer-use screen install [-y] # apt/dnf/pacman 安装包
hermes -p research computer-use screen start # 另一个 bot 的屏幕
屏幕在哪里运行
computer_use、bot 的浏览器和它们操作的屏幕总在同一处运行。bot_desktop.placement 决定在哪里:
terminal.backend | placement: auto(默认) | 含义 |
|---|---|---|
local | 网关机 | 终端、屏幕、浏览器和 computer_use 都共享运行网关的机器。 |
docker、ssh、singularity | 沙箱内部 | Xvnc + Xfce、Chromium 和 cua-driver 运行在容器 / SSH 主机上,通过终端所用的同一 docker exec / ssh 通道生成。窗格串流沙箱的屏幕;主机桌面的任何东西都不可达。 |
modal、daytona、vercel_sandbox | 拒绝 | 这些后端尚不能托管显示器。Start 不会静默地在沙箱旁的主机上跑屏幕,而是解释并指向 placement: gateway。 |
placement: gateway 强制既有行为(即使终端在沙箱中,屏幕也在网关机上)作为显式选择;placement: terminal 强制沙箱,在无法托管屏幕时报错(用 local 后端时终端就是网关机,因此解析到那里)。
放置是策略,而非对恰好正在运行之物的快照。当屏幕放在沙箱中,首次浏览器或 computer_use 调用会按需在那里拉起它(无需 auto_start 选择:沙箱是你选的边界,其中的屏幕不触及外部任何东西);无法拉起时调用带原因失败。主机绝不会作为屏幕宕掉的沙箱的回退。网关重启也不丢屏幕:主机侧标记记录哪个容器拥有它,因此重启后的网关重新挂载到仍在运行的沙箱,Stop 在屏幕实际运行处关闭它,即便你期间改了 placement。
沙箱镜像
沙箱需要桌面栈。nousresearch/hermes-sandbox:desktop 是每个容器后端(Docker、Modal、Daytona、Singularity)的默认镜像:nikolaik/python-nodejs 基础(Python 3.13 / Node 26)加 TigerVNC、Xfce 组件、有头 Chromium、agent-browser、cua-driver 以及基础镜像缺少的日常工具(jq、ripgrep、fd、tmux、rsync、供镜像 pn 用户用的 sudo)。其默认用户是 root,像旧默认一样,因此 shell 工作流不变。你自己固定的镜像保持不动,屏幕会告诉你它需要这个镜像或 bot_desktop.placement: gateway:
terminal:
backend: docker
docker_image: nousresearch/hermes-sandbox:desktop
用普通镜像时,屏幕窗格报告缺失的二进制并点名此标签。
在 Singularity/Apptainer 下,同一镜像转换为 SIF(docker://nousresearch/hermes-sandbox:desktop);Dockerfile ENV 在转换后保留,镜像的 USER 不保留:一切以你运行,因此浏览器 profile 落在容器内你的 $HOME,默认即持久 overlay。实例运行 --containall,因此其临时目录(屏幕运行时状态所在)是 Apptainer 的会话 tmpfs,64 MiB,除非你的管理员调高 sessiondir max size。此路径对照 Apptainer 文档验证,未实测运行。
SSH 主机是你把后端指向的任何机器,因此它自己携带栈:相同二进制(TigerVNC、Xfce、cua-driver、带它能找到的 Chromium 的 agent-browser),可从非交互登录会话触及。最后一点是用桌面镜像构建的主机与 docker exec 的差异:Dockerfile ENV 永远到不了 ssh 会话,因此镜像还把 PLAYWRIGHT_BROWSERS_PATH 写入 /etc/environment 供 PAM 应用。你自己的主机需要等价配置,否则 agent-browser 会在 ssh 上报 "Chrome not found",而在本地 shell 中正常工作。
从先前默认升级。 你已有的 Docker 沙箱保留,不替换:当 docker_image 未设置、且一个持久容器运行着另一个镜像(旧默认 nikolaik/python-nodejs:python3.11-nodejs20),终端继续用那个容器,由你决定切换。交互式 CLI 启动时问一次;屏幕窗格以切换镜像 / 保留当前镜像显示同一选择;hermes config set terminal.docker_image nousresearch/hermes-sandbox:desktop 是任何 shell 的同一答案。任一答案都会写入 terminal.docker_image,而写入的镜像即一个决定:只有你选了新镜像,容器才在下次终端调用时重建,且只在新镜像拉取后(私有或拼错的标签、或注册表故障,都让你当前容器继续运行,而非让你一无所有)。切换意味着:/root 和 /workspace 下的文件保留(它们是 ~/.hermes/sandboxes/ 下的主机目录),容器内用 apt/pip/npm -g 安装的包按需重装,Python 3.11 虚拟环境需在 3.13 上重建。网关和 cron 从不决定;它们保留沙箱并记录通知。字面持有旧默认的配置在升级时被取消设置(那个值是复制来的模板,而非固定)。Modal 恢复其快照、Daytona 复用其打标沙箱,与配置的镜像无关,因此那里既有沙箱不受影响,只有新沙箱用新镜像。桌面进程以镜像的非特权 pn(uid 1000)运行;容器内 Chromium 得 --no-sandbox(Docker 的 seccomp profile 拒绝其自身沙箱所需的用户命名空间;容器就是沙箱)。
沙箱内的运行时状态(X 套接字、cookie、启动器日志)位于 <sandbox tmp>/hermes-bot-desktop/<profile>/;主机只在 <HERMES_HOME>/bot-desktop/ 下保留一个标记。浏览器 profile(登录、cookie)位于沙箱内桌面用户主目录 ~/.hermes/bot-desktop/browser-profile,由 agent 的浏览器和 Dock 的 Browser 图标共享。它跟随容器自身的持久性:跨持久容器的停止和重启保留,随临时容器消失,或在你批准镜像切换时消失(切换替换的是容器可写层)。它刻意不放在容器临时目录下——Docker 把那里挂为小型 tmpfs,每次停止清空。浏览器工具截的屏拷回主机,使 MEDIA: 路径继续工作;窗格缩略图在沙箱内抓取;browser_exec / 保险库自动填充通过同一 docker exec / ssh 通道转发的端口触及沙箱的 Chromium。
配置
bot_desktop:
geometry: "1440x900" # 屏幕尺寸;查看器缩放以适应窗格
auto_start: false # 设 true 则在首次 computer_use 调用或有头浏览器使用时开启
min_free_memory_mb: 1536 # 低于此空闲内存拒绝开启(0 = 永不检查)
idle_stop_minutes: 30 # 停止无人使用这么久的屏幕(0 = 保持开启)
placement: auto # auto | terminal | gateway——见"屏幕在哪里运行"
auto_start 默认关闭。从桌面的屏幕窗格(开启屏幕)、hermes computer-use screen start 开启屏幕,或为无头主机把标志设 true——当 bot 首次调用 computer_use 或打开有头浏览器(browser.headed: true)且无显示器可用时开启屏幕。
状态按 profile 位于 <HERMES_HOME>/bot-desktop/ 下(RFB Unix 套接字、Xauthority、启动器日志、按 profile 的 xfconf)。
工作原理
- TigerVNC
Xvnc是同一进程中的 X 服务器和 RFB 服务器,按 profile,只监听0600Unix 套接字。无 TCP 端口、无 VNC 密码:只有以网关用户运行的进程能触及它(见上述威胁模型),网关的 WebSocket 桥是经鉴权的入口。 - Xfce 按组件启动(
xfsettingsd、xfwm4 --compositor=off、xfdesktop、xfce4-panel),在私有 D-Bus 会话下,不用xfce4-session,因此没有东西尝试锁屏或触及logind。 - Hermes 桌面端内置 noVNC。它在常规鉴权连接上向网关索要一次性 ticket(
display.observe),并向/api/display/ws打开一个兄弟 WebSocket;网关拼接 RFB 流。没有新东西暴露;窗格在本地、SSH、URL+token 和 Hermes Cloud 连接上都工作。 - 控制租约。 网关在 RFB 字节级别丢弃来自任何不持有租约的查看器的键盘、指针和剪贴板消息;noVNC 的 view-only 标志只是 UI 提示。同一租约门控
computer_use和浏览器工具。它是<HERMES_HOME>/bot-desktop/下的一个文件:无文件意味着 bot 持有控制(新 profile);文件存在但无法读取或解析则失败关闭——bot 被视为锁出,直到下次成功交还重写它。Xvnc 从不把屏幕剪贴板推给查看器(-SendCutText=0),因此旁观的人收不到控制者复制的内容;粘贴进屏幕仍正常。 - 显示绑定。 启动器发布
DISPLAY、XAUTHORITY和 D-Bus 地址;该 profile 的每个 cua-driver 和有头浏览器生成都继承它们,因此 bot 绝不会在人正坐在的显示器上操作。
故障排查
- "Screen packages missing"——在窗格中点击在主机上安装,或在网关机上(而非运行 Hermes 桌面端的机器上)运行打印出的安装行。窗格在一个安装进行时拒绝第二次安装。
- 屏幕开启后又停止——读
<HERMES_HOME>/bot-desktop/launcher.log。 - 接管期间打字出错字符——屏幕运行 US 键位,使 RFB keysym 和 cua-driver 一致,且 noVNC 在 Xvnc 提供后发送原始 keycode(QEMU 扩展键事件),因此在非 US 物理键盘上,布局相关的键(Y/Z、符号)在你持有时以其 US 对应物落下。输入密码时记住这一点,或在那个
DISPLAY上用setxkbmap改布局。 - 你离开后 bot 报
human_has_control——在窗格中点击 Hand back(或重载后点 Hand back (force))。从 shell,hermes computer-use screen stop --force释放租约并停止屏幕(不带--force时命令在人类持有时拒绝,因此 runbook 永远不能夺走进行中的接管);hermes computer-use screen start以 bot 控制恢复它。
WSL 下测试
WSL2 算作受支持的 Linux 主机:screen status 如此报告,并提供窗格。一个 WSLg 怪癖会妨碍首次开启:WSLg
以只读挂载 /tmp/.X11-unix,因此 Xvnc 无法创建其显示套接字,并在 launcher.log 中以 Cannot establish any listening sockets 死掉。开启屏幕前把挂载替换为可写目录:
sudo umount /tmp/.X11-unix # no-tmp: ok — X11 套接字目录,由协议固定
sudo mkdir -p /tmp/.X11-unix && sudo chmod 1777 /tmp/.X11-unix # no-tmp: ok — 同上
该挂载在下次 WSL 重启后回来;那时重复这两条命令。