把 Agent 挂成开机自启+自愈的常驻服务:launchd+watchdog+supervisor(丢 repo 给 AI 就行,GitHub 开源)
-
前言
我把 Hermes Agent 的网关挂后台跑了一两个月(default + trade 两个 profile 7×24 常驻),中间踩了不少坑:网关卡死没自动恢复、launchd 没托管导致重启后进程消失、日志静默被误判成故障导致无限重启循环、Telegram API 抖动时明明没事却被反复 kickstart 把正在跑的任务打断。
现在这套「launchd 托管 + watchdog 探活 + supervisor 兜底」的三层方案跑了一两个月,我把整套源码开源在 GitHub。你不用手动抄那几个脚本——clone 下来交给你的 AI,跟它说一句「按我机器环境装上」,它就帮你改路径、生成配置、载入、验证,全自动。
一、三层架构(先说清楚是干嘛的)
你的 Agent 若是跑一下退出,launchd 一条
KeepAlive就够。但挂后台一直等消息的网关,真正的问题不是「进程挂了」,而是:进程活着但断线卡死、机器离线时所有探针失败、日志安静了你却以为它挂了。所以关键不是「重启」,是**「判断什么是真故障才动手」**。层 谁负责 频率 干嘛 托管层 launchd (LaunchAgents) 开机/常驻 保证进程活着,崩溃自动拉起 探活层 autoheal-watchdog.sh每分钟 每分钟查 3 个信号,确认是真健康 兜底层 autoheal-supervisor.sh60s 循环 兜底加载/重启,处理僵尸连接 二、最省事:把 repo 丢给你的 AI(推荐)
整套在 GitHub:https://github.com/Wang200935/hermes-autoheal-launchd
git clone https://github.com/Wang200935/hermes-autoheal-launchd.git cd hermes-autoheal-launchd把整个目录丢给你的 agent,跟它说这一段(把尖括号换成你的信息):
用这个 hermes-autoheal-launchd 套装,按我本机环境把 <我要守护的进程,比如 Hermes 网关> 挂成开机自启 + 自愈的常驻服务。帮我改
deploy-autoheal.sh里的SERVICES(我的路径是 <你的绝对路径>、我的进程命令是 <你的命令>、我有/没有状态文件 gateway_state.json),然后跑起来,验证 watchdog 每分钟打出ok pid。你的 agent 会自动帮你:改
SERVICES→ 生成 plist → 拷贝脚本 → bootstrap 载入 → 验证。你只需要告诉它守护谁、路径在哪。三、这套东西是啥(三个文件)
文件 角色 要不要改 deploy-autoheal.sh生成器(生成 plist + conf + 拷贝脚本 + 载入) 只改它里面的 SERVICES数组autoheal-watchdog.sh探活层,每分钟 不用改 autoheal-supervisor.sh兜底层,60s 循环,防误重启 不用改 各自干啥:
deploy-autoheal.sh— 你要碰的就这一个。里头改SERVICES数组,跑./deploy-autoheal.sh,它帮你干剩下的:建 plist + conf、拷贝 watchdog/supervisor 到~/.hermes/scripts/、launchctl bootstrap载入。不联网、不跑 daemon——纯生成器,run 完就退。autoheal-watchdog.sh— 真干活的探活层。被 launchd 1 分钟拉一次,读autoheal-services.conf,逐项判「进程活 + 命令匹配 + 状态文件正常」,不健康就launchctl kickstart -p。啥都没干就别瞎重启(这条是踩坑 #1 的根因)。autoheal-supervisor.sh— launchdKeepAlive常驻的兜底层。每 60s 检查:plist 都在 loaded、进程都在 pid、telegram 连接没卡住、顺手跑一遍 watchdog。它管的是「上一层都坏了还有没有救」,用 stale-lock 防自锁。
SERVICES格式:"label|workdir|state_file|command",一行一个进程,state_file没有就填空串''(会自动退化成只看进程+命令)。
️ command这一栏最容易踩:不要在SERVICES行里用|(会被 zsh 当管道)。 空格分隔是可的(脚本会把它当数组),但别写含|的复合命令——真有需要就在脚本里另起一行调用,别塞 SERVICES 行。四、真跑的环境
PID 55346 是 default 网关、42888 是 trade 网关,每只每分钟被 watchdog 标记一次
ok:
$ launchctl list | grep hermes 42888 1 ai.hermes.gateway-trade 23527 0 application.com.nousresearch.hermes... 55346 -15 ai.hermes.gateway 50602 75 com.hermes.dashboard 959 0 com.hermes.dashboard-proxy - 0 autoheal.watchdogwatchdog 日志(真跑的,每分钟一条
ok pid=):2026-08-27 18:32:59 ai.hermes.gateway: ok pid=55346 2026-08-27 18:34:01 ai.hermes.gateway: ok pid=55346 2026-08-27 18:35:05 ai.hermes.gateway: ok pid=55346五、坑(让 AI 读 repo README 也能避开)
- 「日志静默」不能当健康信号 — 健康网关等消息时几小时不写日志,拿它当判据会让你每 10 分钟 kickstart 一次,不停弹「shutting down」把跑一半的任务打断。只认状态文件 + API 心跳。
- Telegram API 抖动别盲目重启 —
getMe探针连不上 ≠ 网关挂了,可能是网络/API 抖动;探针失败就跳过重启。 - network fallback — 机器离线时 HTTP 探针会失败但进程没事;先 curl Telegram,失败再 ping 1.1.1.1/8.8.8.8,确认只是离线就保留。
- launchd 用
bootstrap不是load— 先bootout再bootstrap,否则报already loaded。 - stale lock — 锁目录崩溃后会残留,5 分钟以上 + 确认没在跑才删锁重拿。
SERVICES里state_file那栏别留空格 — 留了空格会被当成文件路径判断,把健康的进程误判成 unhealthy。
最后
三层的好处是每层只干一件事、判断标准单一:launchd 只管进程在不在,watchdog 管「是不是真健康」,supervisor 管「兜底 + 防僵尸连接」。这套不用 GPU,纯 CPU,就三个文件,仓库已开源。
装完立刻验(不用等一两周)
# watchdog 干没干活(看到 'ok pid=' 才算成) sleep 65 && tail -5 ~/.hermes/logs/autoheal-watchdog.log # supervisor 有没在跑、加载了哪些 tail -10 ~/.hermes/logs/autoheal-supervisor.log launchctl list | grep -E 'autoheal|gateway'第一条日志应该在 1 分钟内出现
xxx: ok pid=<数字>。没出现就回去查 plist 是否真 bootstrap 进 gui/<uid> 下——这是另一个常见坑:plist 拷到~/Library/LaunchAgents/但bootstrap的 domain 写错(比如写成system而不是gui/501),它会「装上但从不跑」。想省事就 clone 下来丢给你的 agent,让它在你的机器上把活干完。