AI:hermes desktop黑屏故障

一句话

不是单一故障,是「nix-ld 缺 Electron 运行库(已在世代层独立证实)」+「gateway 僵尸态重启循环」+「drkonqi 自身崩溃制造噪音」叠加。与克隆操作无因果关系——崩溃比克隆结束晚 26 分钟。当时推断的「盘1 会原样复发」已在盘1 实际启动后否定(见文末)。

时间线(实测,全部可追溯)

时刻事件证据来源
13:31 – 13:43:57克隆盘2→盘1,rsync 29.7 GB / 2,240,069 文件clone-disk1.log
13:39:13盘1 生成 gen48盘1 loader/entries
14:09:46 / 14:09:55 / 14:13:49 / 14:14:11 / 14:22:13Hermes 二进制 SIGILL ×5coredumpctl list
14:22:17drkonqi 列 coredump,自身也 SIGABRT用户 journal
14:22 – 14:26gateway「already owns this host」循环,restart counter → 29用户 journal
14:25:04configuration.nix 被改(补 nix-ld 库)文件 mtime
14:25:58gen47 = fix-hermes-desktop-black-after-clone-nixosprofile link
14:29:38重启/proc/uptime 反推
14:32:32desktop 启动,其后 0 崩溃ps + journal

逐条裁决:报告的 5 层根因

报告的判定裁决实测依据
层1:TMPDIR 残留 Windows 路径 C:\Users\cat\.hermes\tmp方向对,位置判错,且与本次崩溃无关~/.hermes/.env:530 与 profiles/nixos-u533b-u751f/.env:526 都已是 /home/cat/.hermes/tmp。Windows 路径只残留在 profiles/win10-u533b-u751f/.env:526 → 该层不成立为本次病因,但是真隐患(切到 win10 profile 会踩,会在 $HOME 下建出 ~/C:\Users\... 垃圾目录)。已修(见文末)
层2:node-pty 缺 C++ 编译链事实成立,归因不成立gcc/gnumake/python3/pkg-config 确在 configuration.nix 第 180 行;但 desktop 跑的是预编译包(198 MB,mtime 10-06 22:56),不跑 npm ci → 与黑屏无因果
层3:nix-ld 缺 Electron 运行库 → SIGILL采信(已独立硬证实)逐世代对比 <system>/sw/share/nix-ld/lib:gen45/gen46 = 437 个库,缺 libGLX_mesa / libfontconfig / libgdk_pixbuf / libpulse;gen47 起 = 525 个,四个全在
层4:GPU 子进程初始化失败现象采信,机制表述需修正Chromium/Electron 的 SIGILL 不是「跳到非法指令」,而是 IMMEDIATE_CRASH()(x86 的 ud2)——代码主动触发的 CHECK / LOG(FATAL) 自杀;缺库或 GPU 初始化失败只是可能的触发条件之一
层5:sandbox fallback 残留 + transient unit 残留部分采信 / 部分不可证transient unit 确实失败且至今未清:drkonqi-coredump-launcher@… ×3 仍 failed;windows-sandbox-fallback.json 当前是 {"state":"ok"},当时旧值已无法回溯
「gateway 层有僵尸锁」采信(日志实锤)A gateway already owns this host … PID 1101 … its control socket has not answered 每 ~11 秒一次,restart counter is at 27…29
归因「因克隆而起」(重建标签写的是 after-clone-nixos)驳回克隆 13:43:57 结束,崩溃 14:09:46 起,相隔 26 分钟;且崩溃所处的 gen46 建于 12:32(早于克隆)。无因果证据;真实触发点不可考——desktop 的 stderr 走了终端、没进 journal
「libglvnd 不能单独工作」/「drkonqi 崩溃是噪音」采信libglvnd 只是 dispatcher;实测 drkonqi-coredump-launcher 自身 SIGABRT ×6

报告漏掉的(当时新增,最要紧)

  1. 盘1 停在修复之前(当时判断:启动后会原样复发)—— 后经追平解决,见文末。这条后来被实际启动否证了:盘1 以旧的 437 库也能进桌面,说明缺库不是唯一触发条件。
  2. 启动窗口内时钟错了 8 小时。date/timedatectl 正确,但 journal 与 who -b 记成 +8h,systemd 甚至显示 since 22:29:45; 7h left。
  3. 残留 Windows 路径的确切位置:不在 default profile,在 profiles/win10-u533b-u751f/.env:526。
  4. desktop 不参与 Nix 构建:git 安装目录下的预编译产物 ⇒「补编译链、重跑 npm ci」对它无效;真正作用面只有 nix-ld 库集与进程启动环境变量。
  5. 另一处未清失败单元:app-trilium-notes@796a2c2a…service 仍 failed。

已验证有效的修复(按判据计)

动作生效判据(实测)
nix-ld 补 mesa / libGL / libGLU / fontconfig / freetype / gdk-pixbuf / libuuid / libpulseaudio / openssl库数 437 → 525;四个关键库自 gen47 起存在
重启系统desktop 进程环境实测 NIX_LD_LIBRARY_PATH=/run/current-system/sw/share/nix-ld/lib;此后 0 崩溃
gateway 侧处理那次开机后 already owns this host = 0、Scheduled restart = 0
sandbox fallback 重置文件值为 {"state":"ok"}

下次同类故障的判据顺序

  1. coredumpctl list | grep -i Hermes —— 先拿信号与二进制路径。
  2. 信号是 SIGILL ⇒ 直接判为 Chromium IMMEDIATE_CRASH(主动自杀),别去找「非法指令」。
  3. ls $(readlink /nix/var/nix/profiles/system-N-link)/sw/share/nix-ld/lib | wc -l —— 逐世代比库数,最快最硬(437 vs 525 一眼定案)。
  4. tr '\0' '\n' < /proc/<desktop 主进程>/environ | grep NIX_LD —— 看运行进程实际拿到什么,不看配置「应该」给什么。
  5. drkonqi 自身的 SIGABRT 全是噪音,忽略。

遗留待办:已全部处理(2026-10-09 16:57)

待办处置与判据
盘1 追平(同步 /etc/nixos + /nix,重建引导)已完成:盘1 现为 gen50(jmy71df5…),nix-ld 库数 525、nix.gc 已生效;与盘2 的 configuration.nix md5 完全一致(3d751275f650ce4c9af5d556ce2d4566)。
过程中踩到:盘1 root 一旦被以 ro 挂载(僚机的 /mnt/disk1),同一启动周期内无法再 rw 挂载 → 给盘1 写入前必须先停掉这对挂载。
清 profiles/win10-u533b-u751f/.env:526 的 Windows TMPDIR已改:TMPDIR=/home/cat/.hermes/tmp(锚点唯一、CRLF 未动、-3 字节);备份 backups/config-backups/env.bak-20261009-144207。
时钟 8 小时偏差已定论:RTC 里存的是本地时间(Windows 的默认写法),Linux 当 UTC 读 → 开机瞬间 +8h(14:29 记成 22:29,算术吻合),NTP 随后校正。Linux 侧已自愈;根治要在 Windows 侧 reg add "HKLM\SYSTEM\CurrentControlSet\Control\TimeZoneInformation" /v RealTimeIsUniversal /t REG_DWORD /d 1 /f,否则每次启动 Windows 后都会重现。

关于「克隆是否保真」的权限审计(2026-10-09 16:57)

问题:盘1 上从盘2 克隆来的目录,属主是否被改乱?

检查项结果
/ 顶层属主权限(盘1 vs 盘2)18 项完全一致;3 项差异全是挂载态假象:boot(vfat 挂着 ⇒ fmask=0077 显 700;未挂 ⇒ 空目录 755)、proc/sys(虚拟 fs 555 vs 空目录 755)
/home 下 root 属主条目数盘1 129 vs 盘2 128,差的那一条是 Hermes 写的交接说明文件 ⇒ 克隆保真
那些 root 条目哪来的不是克隆造成的——是先前以 root 跑脚本留下的(~/.hermes/cache/scratch/boot-entries-backup-*、~/www/mihomo/data/*、plasma look-and-feel 符号链等),克隆如实复制
统一处置chown -R cat:users 全部 root 属主条目:128 → 0;6 个关键路径以 cat 身份实测均可写

不该改的:/etc /nix /var /usr /root 本就应是 root:root(NixOS 正常布局)。
故意保留 root 的一处:盘2 底层那个真实的 /s500data 保持 root:root 755 —— 平时被 bind 盖住不可见;万一 bind 失败,root 属主能挡住 cat 的静默写入,正是设计要防的「同路径不同内容分叉」。

hermes手册.txt

Hermes 手册(max2-nixos)—— 出异常时怎么恢复使用
============================================================
本机 Hermes 形态速记:
  · 安装方式 = 官方源码链(git):/home/cat/.hermes/hermes-agent
  · 数据目录 HERMES_HOME = /home/cat/.hermes
  · CLI 入口 = /home/cat/.hermes/hermes-agent/.hermes/bin/hermes  (下文直接写 hermes)
  · 两个长驻件:
      桌面 = "hermes desktop"(Electron,预编译包 apps/desktop/release/linux-unpacked/)
      网关 = systemd 用户单元 hermes-gateway.service(Telegram 等平台接入)
  · 声明式设置(要 nixos-rebuild)在 /etc/nixos;本文件只讲「运行时不重建、如何把它救回来」
提示:agent 无 root,提权用 /run/wrappers/bin/sudo -n;脚本里命令一律写绝对路径。

============================================================
0. 黄金判据(先跑这三条,定位到下面哪一节)
============================================================
  systemctl --user status hermes-gateway.service -n0     # 网关在不在
  pgrep -af 'release/linux-unpacked/Hermes'              # 桌面进程在不在
  hermes logs desktop -n 40                              # 桌面最近日志(黑屏/崩溃都看它)

============================================================
1. 【最常见】hermes desktop 出不来 / 黑屏 / 每分钟崩一次
============================================================
症状:
  · 窗口黑屏、进不去 GUI;或
  · 日志每 ~1 分钟一行 render-process-gone reason=crashed exitCode=132;或
  · coredump 里是 SIGILL(信号4),故障点固定 Hermes+0x6e27995(ud2 = Chromium 主动自杀)。
根因(NixOS 特有):
  预编译 Electron 的 chrome-sandbox 不是 setuid(NixOS 没法给 $HOME 里的文件加 setuid)
  → Chromium 沙箱起不来 → 应用降级 --no-sandbox,并把"降级结论"写进两个 sticky marker:
      ~/.config/Hermes/linux-gpu-fallback.json         {"state":"fallback","reason":"gpu-launch-failure",...}
      ~/.config/Hermes/windows-sandbox-fallback.json   {"state":"fallback","reason":"boot-loop",...}
  marker 的 version 记成 0.0.0(永不等于真实版本)→ 永不重探。

判据:
  cat ~/.config/Hermes/linux-gpu-fallback.json ~/.config/Hermes/windows-sandbox-fallback.json
  grep ELECTRON_DISABLE_SANDBOX /home/cat/.hermes/.env        # 应有:ELECTRON_DISABLE_SANDBOX=1
  grep -c 'render-process-gone' /home/cat/.hermes/logs/desktop.log

恢复(让它"确定地不带沙箱"启动):
  1) 若 .env 里没有这行,就把它追加到 /home/cat/.hermes/.env(只加这一行,别动别的):
       ELECTRON_DISABLE_SANDBOX=1
  2) 关掉残留桌面进程(安全做法:按 /proc 精确匹配,避免 pkill -f 把执行它的 shell 一起杀):
       python3 - <<'PY'
       import os,glob
       pat=b'release/linux-unpacked/Hermes'; me=os.getpid()
       for d in glob.glob('/proc/[0-9]*'):
           pid=int(os.path.basename(d))
           try:
               if pat in open(d+'/cmdline','rb').read() and pid!=me: os.kill(pid,15)
           except Exception: pass
       PY
       sleep 2; pgrep -af 'release/linux-unpacked/Hermes' || echo "已清空"
  3) 重新拉起:
       hermes desktop
  4) 验收(三条都要数,等 3~5 分钟):
       grep -c render-process-gone ~/.hermes/logs/desktop.log           # 两次取样不增
       /run/wrappers/bin/sudo -n dmesg | grep -c 'trap invalid opcode'  # 期望 0
       hermes logs desktop -n 20 | grep -E 'backend is ready|published connection=local'

注意:
  · 别把这两个 marker 当敌人去删/改。它们记的是"崩溃结论";修法方向正是让 no-sandbox 成为固定条件
    (.env 那一行)。只移 marker、不加 .env → 崩溃会回来。version=0.0.0 卡着不清是已知小坑,不影响修法。
  · 日志里 "incorrect permissions on /dev/shm" 是假线索(/dev/shm 实测可写、size 约 30G)。
  · 这条修法在本机 2026-10-13 14:25 才真正落到 .env,此后多时零崩溃 —— 初步有效,未到"根治保证"。

============================================================
2. desktop 起来的其它拦路(不是崩溃循环)
============================================================
2.1 后端没起(桌面白屏/转圈)
    日志特征:Could not connect to Hermes gateway (WebSocket error before open) / ECONNREFUSED 127.0.0.1:<port>
    处置:桌面在等它自己的本地 serve 后端。等 30s 重开;仍不行按第 1 节关进程再 hermes desktop。
      hermes gateway status
2.2 应用页加载失败(黑窗口)
    日志特征:Renderer failed to load: ERR_FAILED (-2) loading 'file://.../dist/index.html'
    处置:桌面包损坏/半更新。先 hermes doctor --fix;再不行 hermes update 重装(桌面会重建)。
2.3 从无图形会话被拉起(直接退出)
    日志特征:Missing X server or $DISPLAY → The platform failed to initialize. Exiting.
    处置:必须在该桌面会话里跑 hermes desktop。要给别的上下文临时配显示变量,照抄正在跑的 plasmashell:
      tr '\0' '\n' < /proc/$(pgrep -x plasmashell | head -1)/environ \
        | grep -E 'DISPLAY|XAUTHORITY|DBUS_SESSION_BUS_ADDRESS|WAYLAND_DISPLAY'

============================================================
3. 网关(hermes-gateway.service)异常
============================================================
症状:日志刷 "A gateway already owns this host ... its control socket has not answered"(僵尸锁),
      restart 计数一直涨;或 Telegram 收不到回复。
判据:
  hermes gateway status
  systemctl --user status hermes-gateway.service -n30
  hermes logs gateway -n 50
恢复(按顺序):
  hermes gateway restart                 # 首选
  hermes gateway stop ; sleep 3 ; hermes gateway start   # 停干净再起
  hermes gateway migrate                 # 若一直刷僵尸锁:把各 profile 收敛到"一个主机网关"
  hermes gateway list                    # 看每个 profile 的网关状态

============================================================
4. 启动即退、报缺库(nix-ld)
============================================================
症状:hermes desktop 立刻退出;报 /lib64/ld-linux-x86-64.so.2 不存在,或缺 libGLX/libfontconfig/libgdk_pixbuf/libpulse。
判据:
  L=$(readlink -f /nix/var/nix/profiles/system)/sw/share/nix-ld/lib
  ls "$L" | wc -l                                            # 本机应约 525
  ls "$L" | grep -E 'libGLX_mesa|libgdk_pixbuf|libpulse'    # 关键库应在
修法:属于声明式——补 /etc/nixos 里 programs.nix-ld 的库列表后 nixos-rebuild switch(本文件不展开)。
提醒:这条治的是"启动即退/缺库",不要拿它解释"每分钟 SIGILL 崩溃"——那是第 1 节。

============================================================
5. config.yaml 损坏(改了配置没生效 / 直接报错)
============================================================
症状:日志 "Your settings file (...) has a formatting error at line N ... running on previous settings"。
处置:
  hermes config check
  hermes config edit
  # 坏文件副本:~/.hermes/backups/config/config.yaml.corrupt.<时间戳>
  # 回退:      ls -t ~/.hermes/config.yaml.bak-* | head   (取最近一份覆盖回去)
铁律:改配置一律用 hermes config set <key> <val>,别手改(缩进错 = 整个配置不生效)。

============================================================
6. 会话 / 数据库异常
============================================================
症状:报 "another process holds an old copy of the session database's write-ahead log",或某会话读不出。
处置:先关占用进程(网关 + 桌面)再重开;state.db 的 -wal/-shm 不要手删。
  hermes sessions list
  hermes sessions show <完整id>          # id 形如 YYYYMMDD_HHMMSS_xxxxxx,别用截短前缀

============================================================
7. 全量备份 / 还原(重装或换机前的保命符)
============================================================
  hermes backup -o "/s500data/软件数据备份/hermes备份/hermes-backup-$(date +%Y%m%d-%H%M%S).zip"
  hermes import <zip>                    # 还原;还原前先给现状再备一份
不含代码与运行时(hermes-agent、tools、installs);还原后 hermes update 补齐。

============================================================
8. 应急刹车
============================================================
  hermes pause            # 暂停 cron / kanban 派发 / 新的网关回合
  hermes resume           # 解除
关桌面:见第 1 节的安全 kill 脚本。关网关:hermes gateway stop。

============================================================
9. 日志与诊断位置速查
============================================================
  hermes logs <name> [-f] [-n N]     # name: agent(默认) errors gateway gui desktop update handoff
  /home/cat/.hermes/logs/            # 上述文件 + desktop-chromium.log(含 Missing X server / FATAL 等)
  /home/cat/.config/Hermes/          # 桌面用户数据:Crashpad/(崩溃转储)、两个 *-fallback.json
  coredumpctl list | grep -i Hermes ; coredumpctl info <pid>
  /run/wrappers/bin/sudo -n dmesg | grep -iE 'trap invalid opcode|segfault'
  hermes doctor ; hermes doctor --fix ; hermes doctor --live

============================================================
10. 一句话对照:三种"桌面坏"别互相套错
============================================================
  · 启动即退 / 报缺 .so     → 第 4 节  nix-ld(声明式补库 + rebuild)
  · 黑屏 + 每分钟 SIGILL 崩溃 → 第 1 节  沙箱降级 marker(.env ELECTRON_DISABLE_SANDBOX=1)
  · 白屏 / 连不上后端        → 第 2.1  后端未就绪(等待或重启网关)

(手册日期 2026-10-13;与 nixos 台账 docs/hermes-desktop-crash-diagnosis.md 同源。)