终端里突然 command not found:Hermes 修好了 PATH 被登录 shell 重置的老坑

你让 agent 在终端里跑一句 hermes cron list,想让它自己看看定时任务为什么没触发。它回你一行 bash: hermes: command not found。你切到自己的 SSH 窗口敲同一个命令,一切正常;再切回来,让它 command -v node,也是空的——可你明明用 nvm 装了 node。
这不是权限问题,也不是 Hermes 没装好。原因很朴素:有一个东西把 PATH 重置了,而且重置得毫无声息。
谁动了 PATH
Hermes 的终端工具背后是一个 bash。为了让你自己装的 nvm、asdf、pyenv 能在 agent 的命令里生效,它建会话时会先以“登录 shell”的方式跑一次,把 ~/.profile、~/.bash_profile、~/.bashrc 里追加的路径吃进环境快照——这一步本来是好意。
问题出在 Debian / Ubuntu 的 /etc/profile:它会直接把 PATH 重写成一套固定目录(通常是 /usr/local/bin:/usr/bin:/bin 加上几个 games 目录)。登录 shell 一跑完,快照就把这份被重置过的 PATH 钉死了。于是 Hermes 自己启动时的那些目录全丢了:~/.local/bin、/opt/hermes/bin、/opt/hermes/.venv/bin,还有 nvm 塞进去的 shims。
在 Docker 镜像里这个症状最刺眼:容器里 bash -l 或者 docker exec ... bash -l 一进去,hermes 就退出码 127。背景命令更麻烦——它走的是 bash -lic,同样会被重置。
现在的补法:把掉队的目录追加到末尾
修复没有选择“盖掉登录 shell 的结果”,而是补差集,顺序很讲究:
- 登录 profile 跑完之后,把启动 Hermes 时那份 PATH 里“现在没了”的目录,按它原本的顺序追加到末尾;
- 已经在 PATH 里的目录不重复添加;
- 只有绝对路径会被检查存在性——相对路径是按 shell 当前目录解析的,检查了也没意义;
- 不存在的目录直接跳过,不会塞一堆死路径进去。
把补回的目录放在末尾而不是开头,是关键取舍:你 nvm / pyenv 决定的优先级一个字都不动,原本能解析的命令仍然解析到同一个二进制;只有那些“谁都找不到”的命令,才因为这次补齐被找到。
后台命令(process_registry 的 spawn_local、bash -lic)用的是同一段前置脚本,所以前台和后台不会出现“一个能用、一个不能用”的分裂。
Docker 镜像还多一层保险:镜像里装了一个 /etc/profile.d/hermes.sh,登录 shell 每次都会读到它,把镜像自带的三个目录补回去——已经存在的保持原位。
# /etc/profile.d/hermes.sh(镜像内)
for __hermes_p in /opt/data/.local/bin /opt/hermes/.venv/bin /opt/hermes/bin; do
case ":$PATH:" in
*":$__hermes_p:"*) ;;
*) PATH="$__hermes_p:$PATH" ;;
esac
done
unset __hermes_p
export PATH
自己确认一下 PATH 到底长什么样
在 agent 的终端里跑这三行,一眼就能看出差在哪:
echo $PATH # agent 实际拿到的 PATH
command -v hermes # 为空就是没找到
bash -lc 'echo $PATH' # 登录 shell 重置后的 PATH,用来对比
常见症状对照:
| 症状 | 真实原因 | 怎么处理 |
|---|---|---|
Docker 里 hermes: command not found |
登录 shell 重置 PATH,镜像缺少 profile.d 补丁 | 升级到包含修复的版本或重建镜像 |
node / python 找不到,但宿主上都装了 |
~/.profile 里的 nvm/pyenv 初始化被 /etc/profile 冲掉 |
新版会自动补回;旧版把初始化文件显式写进配置 |
| 只有后台命令失败,前台正常 | 旧版后台路径没有复用同一段前置脚本 | 升级;临时可用前台命令代替 |
| 你自己写的脚本找不到 | 脚本依赖了某条只在交互 shell 存在的 PATH | 在脚本里显式用绝对路径,或写进 shell_init_files |
如果你有自定义的环境文件(比如一套公司内部的工具链),可以明确告诉 Hermes 去 source 哪些文件,而不是靠猜:
terminal:
auto_source_bashrc: true # 默认值;显式列了 shell_init_files 时以列表为准
shell_init_files:
- ~/.profile
- ~/.config/hermes/env.sh
几个边界,避免误会
- 补的只是“启动 Hermes 时那份 PATH 里有、登录 shell 后没了”的目录。你父进程本来就没有的目录,不会被凭空加进去。
- 如果你在 profile 里故意把某个目录从 PATH 里删掉,但它仍出现在启动 Hermes 的 PATH 中,它会被补回来——这是本次修复的既定行为,取舍是“让原本能用的命令继续能用”。
- Windows 不受影响:原生 PATH 用分号拼接,bash 看到的是一份转换后的副本。
- 顺序就是优先级。补回末尾意味着系统目录仍在你自定义目录之前,别把可写目录放到 PATH 前部来“修”问题——那是另一个安全隐患。
想让 agent 自己体检环境,可以跑 hermes doctor;终端沙箱和临时目录的行为分别在终端临时目录和共享容器模式里讲过,容器里换终端后端看终端后端插件。
版本状态
这个修复在 2026 年 10 月 29 日合并进 main(PR #146080)。当前最新正式版 v0.22.5(2026-10-23)还不含它,所以旧版本上你仍可能撞见 command not found。
PATH 这类问题的麻烦之处在于它从不报错,只是悄悄少几个目录。现在至少它会把缺的那几个补回原位。