Hermes 在 macOS 上反复要文档授权,真正的问题不是 AI,是启动方式

1 阅读8分钟

前几天我在调本地 Hermes Agent。

表面现象很烦人:

  • ~/Documents/memory 要授权
  • ~/Desktop/company 也要授权
  • 有时候 terminal 能跑
  • 有时候 execute_code 又继续报错
  • Hermes 自己还会一本正经地说:“沙箱有两层”

一开始特别容易把问题想歪。

比如你会怀疑:

  • 是不是没给 Full Disk Access
  • 是不是 macOS 把 AI 工具都沙箱化了
  • 是不是 SIP 要关
  • 是不是 Hermes 本身有隐藏配置

我后来把这件事从头拆开查,才发现真正的问题根本不在“模型”上,也不在“你会不会点授权弹窗”上。

真正的根因,是 Hermes 在 macOS 上的启动责任链,决定了它能不能稳定拿到 Documents/Desktop 的访问权限。

这篇就把整个排查过程和最后的解决方案写清楚。


先说结论

一句话版本:

Hermes 反复要 Documents/Desktop 授权,不只是权限没开,而是它原来那条 launchd 直接后台拉 Python gateway 的启动方式,会把 macOS 的文件权限责任链搞断。

我最后的解法是两步:

  1. 把 Hermes 自己的命令审批关掉
  2. 不再让 launchd 直接后台拉 Python,而是改成 Terminal 宿主启动 gateway

做完之后,Hermes 读取:

  • ~/Documents
  • ~/Documents/memory
  • ~/Desktop
  • ~/Desktop/company

都恢复正常了,而且不会再动不动要求我重复确认。


最开始看到的症状,非常像“权限没开”

Hermes 当时返回过几类典型报错:

ls: /Users/webkubor/Documents/: Operation not permitted
Failed to read skill ... Operation not permitted: '/Users/webkubor/Documents/CortexOS/skills/...'
PermissionError: [Errno 1] Operation not permitted

而且有一个特别迷惑人的点:

  • terminal 这条链有时能动
  • execute_code 这条链还是会炸

这会让你直觉上觉得:

嗯,可能就是 AI 工具沙箱两层套两层,没办法。

但如果你停在这里,后面只会陷入无限授权地狱。


我先去查了 Hermes 官方 GitHub

这个问题如果只靠猜,很容易越猜越偏。

所以我先去对了官方仓库:

重点查了三份文档:

  • security.md
  • configuration.md
  • code-execution.md

查完后,有三个关键信息基本可以定死:

1. Hermes 的审批模式是显式配置的

官方文档明确写了:

approvals:
  mode: manual | smart | off

也就是说,Hermes 自己那层“危险命令要不要每次批准”,是产品内的审批门禁,不是 macOS 系统权限。

2. execute_code 本来就是子进程沙箱

官方对 execute_code 的定义很明确:

它会在 agent host 上以 sandboxed child process 的方式执行。

所以它天然就不是“普通终端本身”。

换句话说:

  • terminalexecute_code 不是同一条能力链
  • 其中一条能读文件,不代表另一条一定也能完全继承

3. 官方没有提供“允许读 Documents”的独立配置项

我没查到任何类似:

  • allow_documents: true
  • allow_desktop: true
  • macos_tcc_bypass: ...

这种东西。

这非常关键。

因为这说明问题大概率不在 Hermes 某个业务配置里,而是在 宿主进程如何启动 这一层。


真正让我定位到根因的,是一组对照实验

我做了一次特别简单、但特别关键的对照。

Hermes 当前 gateway 的实际启动方式是这样的:

/Users/xxx/.local/share/uv/tools/hermes-agent/bin/python -m hermes_cli.main gateway run --replace

然后我做了两组测试。

方案 A:让这套 Python 在当前终端里直接读目录

测试结果:

  • 能读 ~/Documents
  • 能读 ~/Desktop

方案 B:让它继续走原来的后台 daemon 方式

测试结果:

  • ~/DocumentsOperation not permitted
  • ~/Desktop 同样可能报 Operation not permitted

这一下就把问题钉死了。

不是 Hermes 不会读,也不是 Python 二进制本身没权限,而是 被 launchd 直接后台拉起时,这条进程责任链拿不到稳定的 TCC 文件夹访问能力。

这就是整个问题最容易被忽略的地方。

很多人会把“同一个程序”想成同一种权限状态,但在 macOS 里,谁启动你、以什么宿主启动你,会直接影响 Documents/Desktop 这类受保护目录的访问行为。


为什么会出现“看起来授权了,实际上还是不稳定”

因为这里其实混着两层完全不同的问题。

第一层:Hermes 自己的审批门禁

这是产品内逻辑。

配置文件里原来是:

approvals:
  mode: manual

这意味着只要命令被判定为危险操作,它就会继续向你要批准。

这和 macOS 文档权限不是一回事。

第二层:macOS 对 Documents/Desktop 的受保护目录访问

这是系统权限链问题。

Hermes 之前真正卡住的,是这层。

也就是说:

  • 你把 Hermes 的 approvals.mode 改了,最多只是“不再每次弹内部批准”
  • 但如果后台 Python 这条启动链还在,读 Documents/Desktop 仍然可能继续报 Operation not permitted

所以只解决其中一层,是不够的。


我最后是怎么修的

我最后做的是一个组合修复。

第一步:关掉 Hermes 自己的命令审批

把配置从:

approvals:
  mode: manual

改成:

approvals:
  mode: off

这一步解决的是:

  • 不再每次危险命令都停下来问你
  • Hermes 自己的交互门禁关闭

但这一步只解决“批准疲劳”,还没解决 Documents/Desktop 的根因。

第二步:不再让 launchd 直接后台拉 Python gateway

原来的问题链路是:

launchd -> python -m hermes_cli.main gateway run --replace

我把它改成:

launchd -> open Terminal -> Terminal 执行 hermes gateway

也就是让 Terminal 成为 Hermes gateway 的宿主

为什么这招有效?

因为在我本机实测里,同样那套 Hermes Python:

  • 放在当前终端上下文里,能正常读 Documents/Desktop
  • 放在 launchd 后台 daemon 上下文里,就可能被 TCC 拒绝

所以与其继续和后台 Python 的权限责任链硬碰硬,不如直接切回一个 macOS 更愿意赋权、行为也更稳定的宿主:

Terminal

这不是“优雅的理论最优解”,但它是这台机器上 最可靠、最少反复授权、最少惊喜 的解法。


我没有做的事

这点也很重要,因为很多人一着急就会往系统危险区走。

我这次没有做这些事情:

  • 没有关 SIP
  • 没有做任何系统完整性破解
  • 没有去改什么奇怪的底层安全策略
  • 没有伪造 Hermes 的 TCC 数据库记录

也就是说,这不是那种“为了让 AI 读文件,把系统安全全拆了”的方案。

我做的只是:

  • 调整 Hermes 自己的审批模式
  • 调整 Hermes gateway 的启动宿主

这个问题最容易误导人的地方

如果让我总结一句最核心的经验,那就是:

macOS 上 AI 工具的权限问题,经常不是“有没有授权”本身,而是“谁在托管这个进程”。

很多时候我们会把问题理解成:

  • 权限没给够
  • 再点一次允许
  • 再加一个 Full Disk Access

但这次真正决定结果的,是:

  • 同一个 Hermes
  • 同一套 Python
  • 同一个用户
  • 只是换了一个宿主

结果就完全不一样。

这说明:

在 macOS 的 TCC 世界里,启动责任链本身就是权限设计的一部分。


如果你也遇到 Hermes 反复请求文档授权,可以怎么排查

我建议按这个顺序排:

1. 先分清两层问题

先问自己:

  • 这是 Hermes 的内部审批提示?
  • 还是 macOS 返回的 Operation not permitted

这两层不要混在一起。

2. 看 Hermes 当前 approvals.mode

如果还是:

approvals:
  mode: manual

那它当然还会继续审批。

3. 不要只看“能不能跑”,要看“是谁启动的”

重点检查:

  • Hermes gateway 是不是被 launchd 直接后台拉起
  • 还是由 Terminal / 你当前终端宿主启动

4. 做一次最小对照实验

直接用 Hermes 实际那套 Python 二进制,在你当前终端里读一次:

  • ~/Documents
  • ~/Desktop

如果这里能读,而后台 daemon 不能读,问题就基本定位了。

5. 优先改宿主,不要先碰系统危险设置

如果能通过更换宿主解决,就别先去碰:

  • SIP
  • TCC 数据库手改
  • 各种激进安全绕过

最后的判断

这次我对 Hermes 授权问题最大的体会是:

很多 AI 工具的“权限问题”,表面看像模型问题,实际上是操作系统进程模型问题。

你不把这层拆开,后面只会一直在“再授权一次”“再试一次”“怎么还是不行”里打转。

而一旦你把问题拆成:

  • Hermes 自己的审批门禁
  • macOS 的文件权限责任链

这件事就会突然变简单。

对我这次来说,真正解决问题的不是某个神奇开关,而是这句判断:

Hermes 不是不能访问文档,是它原来的启动方式不该继续用。


这次实际落地的关键改动

最后留一个极简清单,方便以后自己回看:

  • 官方仓库确认:approvals.mode 支持 off
  • 确认 execute_code 本来就是子进程沙箱
  • 验证同一 Hermes Python 在终端里可读 Documents/Desktop
  • 验证后台 launchd 直拉 Python 时会触发 Operation not permitted
  • 把 Hermes gateway 从后台 Python 宿主切到 Terminal 宿主
  • 把内部审批从 manual 改成 off

到这里,问题才算真正收口。