Hermes 安装问题记录

记录范围

本文只覆盖三件事:在 NixOS 上安装 Hermes、构建并启动 Hermes Desktop、以及过程中 Hermes 自身遇到的问题(现象 → 根因 → 修法 → 客观验证)。

本次会话另行处理的若干与本主题无关的事项不在本文范围内。

环境

项值
系统NixOS 26.05 (Yarara) 26.05.11045.774debe7a0d1,内核 7.2.8
机型GPD G1619-04(GPD Win Max 2),Ryzen 7 7840U,核显 Radeon 780M
Hermes 版本v0.21.5+7696.g35a2a31(2026.9.24),上游 commit 35a2a31fa6
安装目录/home/cat/.hermes/hermes-agent,来源 git clone https://github.com/NousResearch/hermes-agent.git
CLI 入口~/.local/bin/hermes(70 字节 shim)→ $HERMES_HOME/hermes-agent/.hermes/bin/hermes
网络前提本机直连 GitHub / npm 不通,只能经 HTTP 代理出网(127.0.0.1:7890)—— 安装脚本要下载预编译 uv,构建 Desktop 要装 npm 依赖,两者都依赖这条通路

一、NixOS 上安装 Hermes 的完整步骤

1. NixOS 侧前置(声明式,写进 /etc/nixos/configuration.nix)

配置项作用为什么在 NixOS 上必须
programs.nix-ld.enable = true;让非 Nix 打包的预编译 ELF 可执行关键:安装脚本会从 GitHub 下载固定版 uv(预编译二进制),Desktop 是预编译 Electron 二进制 —— 没有 nix-ld,这两者都直接因找不到动态库而失败
programs.nix-ld.libraries = pkgs.lib.mkAfter (with pkgs; [ … ]);给 nix-ld 补 Electron 运行时库默认库集只有 systemd / gcc / openssl,跑 Electron 远远不够,见第二节
environment.localBinInPath = true;把 ~/.local/bin 加进 PATHHermes 的 CLI 包装器就装在那里,否则 hermes 命令找不到
users.users.<用户>.linger = true;用户级 systemd 常驻gateway 与定时任务依赖 user systemd 常驻运行
environment.systemPackages = with pkgs; [ git curl gcc gnumake python3 pkg-config ];安装与构建前置安装脚本的 prerequisites 阶段硬性检查 git 与 curl(缺失直接 fail);Python 依赖树与原生模块编译需要 gcc / gnumake / pkg-config
virtualisation.docker.enable = true;(可选)容器化 MCP / 沙箱只有用容器型 MCP 服务或 docker 插件时才需要
nixpkgs.config.allowUnfree = true;(可选)允许非自由软件包依赖里含 unfree 时必需
nix.settings.experimental-features = [ "nix-command" "flakes" ];(可选)启用 flake 路线只有走 nix run / Nix 模块安装时才需要

2. 跑官方安装脚本

Hermes 官方安装器是 scripts/install.sh,分 9 个阶段依次执行:

prerequisites  repository  venv  python-deps  config  products  setup  gateway  complete

# 实际用法(仓库已 clone 的情况下)
cd /home/cat/.hermes/hermes-agent
./scripts/install.sh

脚本按平台自动挑 uv 的预编译包(linux-x64 / linux-arm64,以及 glibc / musl 变体,本机固定 uv 0.12.3),这一步正是 nix-ld 必须开启的原因。脚本对 NixOS 没有任何专门分支(仓库里 grep 不到 nix-ld / nixos),所以上面第 1 步的前置全靠 NixOS 配置自己提供。

3. 验证安装

hermes --version          # 期望:Hermes Agent v0.21.5+…(2026.9.24)
which hermes              # 期望:/home/cat/.local/bin/hermes
ls "$HERMES_HOME"         # config.yaml / cron / skills / hermes-agent 等

若报缺 libatomic.so.1,是 glibc 版 Node 的常见依赖 —— nix-ld 默认库里已含 stdenv.cc.cc,确认它没被写覆盖即可。

二、Hermes Desktop 在 NixOS 上起不来(nix-ld 缺库,三轮才修完)

Desktop 不是官方分发的产物,而是本机构建:hermes desktop 走 apps/desktop 的 electron-builder(Electron 40.10.2 / electron-builder 27.0.0-alpha.6),产物在 apps/desktop/release/linux-unpacked/。构建文档明确写:macOS 出 DMG/ZIP、Windows 出 MSIX、Linux 的官方发布支线是关闭的(本地 builder 可出 AppImage),Node / npm / uv 不需要自己预装(由 PM 准备)。

构建成功、启动却立刻因缺共享库退出,分三轮才修完,每轮暴露的层面不同:

轮次报错根因修复
1libglib-2.0.so.0: cannot open shared object file(实测 27 个库全部 not found)nix-ld 虽已启用,但默认库集只有 systemd / gcc / openssl,完全没有 GTK / X11 运行时库pkgs.lib.mkAfter 往 programs.nix-ld.libraries 追加 glib / nss / nspr / dbus / atk / at-spi2-atk / at-spi2-core / cups / cairo / gtk3 / pango / libX11 系列 / libxcb / libxkbcommon / alsa-lib / libsecret / libXtst
2只剩 libgbm.so.1libgbm 是 nixpkgs 的独立属性;mesa 的 outputs 是 out / opencl / spirv2dxil / cross_tools / debug,不含 libgbm把无用的 mesa 换成 libgbm(其 lib/libgbm.so.1 已核实存在)
3程序已能启动,但 Chromium / ANGLE 报 Could not dlopen libGL.so.1,GPU 进程反复退出libGL / libEGL 是运行时 dlopen 加载的,不是 DT_NEEDED 链接依赖 —— 任何链接期分析都查不到补 libglvnd(一次覆盖 libGL.so.1 / libEGL.so.1 / libGLX.so.0 / libGLdispatch.so.0)

关键坑(容易反复踩)

  1. ldd 对这个二进制不可信。它的 ELF 解释器是 nix-ld 的桩(PT_INTERP=/lib64/ld-linux-x86-64.so.2),ldd 会把所有库都误报成 not found —— 第一轮就是因此误判。要查链接期依赖必须自己解析 ELF 的 DT_NEEDED(脚本见附录)。
  2. programs.nix-ld.libraries 必须用 mkAfter 追加。nixos 的 nix-ld 模块对该选项是直接赋值,列表类型选项两个普通赋值会冲突报错;pkgs.lib.mkAfter (...) 才是在默认集后面追加、不替换原有库。
  3. dlopen 类缺口只能从运行日志发现。第 3 轮就是靠运行时那两段报错才定位的;静态扫描(包括自写的 ELF 解析器)结构上不可能发现它。
  4. NixOS 的 libglvnd 已被打过补丁:内建 vendor 目录包含 /run/opengl-driver/share/glvnd/egl_vendor.d;本机存在 50_mesa.json 且指向 mesa 的 libEGL_mesa.so.0 绝对路径 —— 所以补上 libglvnd 后不需要再手动设 __EGL_VENDOR_LIBRARY_FILENAMES。

最终配置(本机已生效)

programs.nix-ld.libraries = pkgs.lib.mkAfter (with pkgs; [
  glib nss nspr dbus atk at-spi2-atk at-spi2-core cups cairo gtk3 pango
  libglvnd        # libGL.so.1 / libEGL.so.1 —— 运行时 dlopen 的目标
  libgbm          # 独立属性,不属于 mesa
  libdrm expat libxcb libxkbcommon alsa-lib libsecret libXtst
  libx11 libxcomposite libxdamage libxext libxfixes libxrandr libxcursor libxi
]);

验证方法(三层,缺一不可)

# 1) 链接期依赖:自写 ELF DT_NEEDED 解析器(ldd 不可信)
python3 /home/cat/.hermes/cache/scratch/elf-needs.py     # 期望:仍然缺的 soname: 0 个

# 2) nix-ld 库目录是否到位(条目数会从 124 涨到 437)
ls /run/current-system/sw/share/nix-ld/lib/ | grep -E '^lib(GL|EGL|GLX|gbm|glib)'

# 3) 运行时:应用自己写的状态文件才是硬证据
cat ~/.config/Hermes/linux-gpu-fallback.json              # 期望 {"state":"ok"}
cat ~/.config/Hermes/window-state.json                    # 有几何尺寸 = 窗口真的被创建过

判定成功的客观证据(本次实测):三个 fallback 状态文件全部为 {"state":"ok"};window-state.json 记录了 1439×899 的窗口几何;journal 显示 app-org.chromium.Chromium-22845.scope: Consumed 8.018s CPU over 23.536s, 529.9M memory peak —— 程序正常运行了 23.5 秒,不是秒崩。

残留的无害日志:UnitExists: Unit app-org.chromium.Chromium-<pid>.scope was already loaded。原因是 Chromium 对自己的 pid 命名 scope 调了两次 StartTransientUnit,journal 里能看到该 scope 随后被正常创建并统计到 CPU / 内存,功能不受影响。

三、trilium MCP 在 NixOS 上不注入

现象:会话里 mcp__trilium__* 工具完全没有出现。根因在 config.yaml 的 mcp_servers 配置 —— command 与 args 都是 Windows 路径,在 NixOS 上进程起不来,工具自然不注入:

trilium:
  command: C:/Users/cat/scoop/apps/nodejs/current/node.exe
  args:
    - C:/Users/cat/AppData/Local/hermes/trilium-mcp/dist/index.js

修法:把 command 与 args 改成 NixOS 上的实际路径(node 与 trilium-mcp 的实际位置),重启 Hermes 后确认工具重新出现。

临时兜底(MCP 不可用时的唯一授权路径:ETAPI 一次性 curl)。此处有个血泪点 —— ETAPI 的认证头不带 Bearer:

# 正确:Authorization: <token>
# 错误:Authorization: Bearer <token>   → 稳定 401 NOT_AUTHENTICATED(看起来像令牌失效)
curl -H "Authorization: $TRILIUM_ETAPI_TOKEN" "$TRILIUM_ETAPI_URL/notes/<id>/content"

# 改标题没有 PUT /title 端点(0.63.7 返回 404 Router not found),用 PATCH:
curl -X PATCH -H "Authorization: $TRILIUM_ETAPI_TOKEN" -H "Content-Type: application/json" \
     --data '{"title":"新标题"}' "$TRILIUM_ETAPI_URL/notes/<id>"

四、待办(Hermes 相关)

    • 已完成:三轮补齐(glib/gtk3 系列 → libgbm → libglvnd),已写入 /etc/nixos/configuration.nix 并 rebuild 生效
    • 证据:三个 fallback 状态文件 {"state":"ok"},窗口几何 1439×899 被记录
    • 动作:command 改本机 node 路径,args 改本机 trilium-mcp/dist/index.js 实际位置
    • 复核:重启 Hermes 后 mcp__trilium__* 工具出现在工具列表里
    • 现状:electron-builder 的 linux target 是 AppImage,但官方 Linux 发布支线关闭,本机 hermes desktop 只跑本地构建产物

附录:相关文件

路径用途
/etc/nixos/configuration.nixHermes 前置与 nix-ld libraries(第 143–150 行一带)
/etc/nixos/configuration.nix.bak-2026-10-06nix-ld 修改前的配置备份
/home/cat/.hermes/cache/scratch/nixos-nixld-stage.py幂等生成 nix-ld 修复后的 configuration.nix(先剥旧块再注入)
/home/cat/.hermes/cache/scratch/elf-needs.py自写 ELF DT_NEEDED 解析器,一次算出 Electron bundle 的全部缺失 soname
~/.config/Hermes/Desktop 自己的状态文件(linux-gpu-fallback.json / window-state.json 等)
/home/cat/.hermes/hermes-agent/scripts/install.sh官方安装脚本(9 阶段)
/home/cat/.hermes/hermes-agent/apps/desktop/BUILDING.mdDesktop 构建文档(平台产物与前置)