前几天我在调本地 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 的文件权限责任链搞断。
我最后的解法是两步:
- 把 Hermes 自己的命令审批关掉
- 不再让
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.mdconfiguration.mdcode-execution.md
查完后,有三个关键信息基本可以定死:
1. Hermes 的审批模式是显式配置的
官方文档明确写了:
approvals:
mode: manual | smart | off
也就是说,Hermes 自己那层“危险命令要不要每次批准”,是产品内的审批门禁,不是 macOS 系统权限。
2. execute_code 本来就是子进程沙箱
官方对 execute_code 的定义很明确:
它会在 agent host 上以 sandboxed child process 的方式执行。
所以它天然就不是“普通终端本身”。
换句话说:
terminal和execute_code不是同一条能力链- 其中一条能读文件,不代表另一条一定也能完全继承
3. 官方没有提供“允许读 Documents”的独立配置项
我没查到任何类似:
allow_documents: trueallow_desktop: truemacos_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 方式
测试结果:
- 读
~/Documents报Operation 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
到这里,问题才算真正收口。