OpenClaw ACP 实战指南:从踩坑到全通¶
作者
飞马 | 2026-04-23
今天花了几个小时验证和调试 OpenClaw 的 ACP(Agent Control Protocol)功能,把 Codex 和 Claude Code 的 ACP 调用全部跑通了。过程中踩了不少坑,这篇记录核心发现。
ACP 是什么¶
ACP 是 OpenClaw 调用外部 coding agent(Codex、Claude Code、Copilot 等)的统一协议。相比直接 exec 运行 CLI,ACP 提供结构化通信、自动回调、session 管理等能力。
调用方式:
{
"runtime": "acp",
"agentId": "codex",
"mode": "run",
"task": "你的任务描述",
"cwd": "/workspace/project-dir",
"runTimeoutSeconds": 900
}
踩坑 1:heartbeat.target 未配置导致回调不投递¶
问题¶
exec background=true 完成后,agent 生成了回复,但 Discord 上看不到。
根因¶
heartbeat.target 默认是 "none",导致两层阻断:
- Prompt 层:生成的 prompt 是 "Handle the result internally. Do not relay it to the user"
- 路由层:
OriginatingChannel为空,reply 无处投递
解法¶
设成 "last" 后,completion wake 会路由到最后交互的 channel。不会串频道——exec completion 自带 deliveryContext,优先使用发起时的 channel。
踩坑 2:Claude Code ACP 进程不退出¶
问题¶
通过 ACP 调用 Claude Code 后,claude 和 claude-agent-acp 进程不退出,累积僵尸进程。Codex 没有这个问题。
根因¶
两个原因叠加:
- npm exec 包装层:
claude-agent-acp没有本地安装时,acpx 通过npm exec启动,产生三层进程树(npm → claude-agent-acp → claude)。child.kill()只杀了 npm 进程,内层变成孤儿。 - oneshot close 缺陷:
manager.core.ts的runTurn()调用runtime.close()时没传discardPersistentState,导致不发session/closeACP 消息,adapter 的 teardown 不触发。
Codex 没问题是因为 codex-acp 是单进程,检测到 stdin 断开后自行退出。
解法¶
全局安装 claude-agent-acp,让 acpx 走 installed 路径而不是 npm exec 包装:
踩坑 3:subagent 里 background exec 回调丢失¶
问题¶
在 subagent 里用 exec background=true,exec 完成后回调丢失。
根因¶
subagent 是短生命周期 session。background exec 完成时,subagent session 已经不存在了,回调无处投递。
正确做法¶
| 场景 | 做法 |
|---|---|
| Interactive session | exec background=true 或 ACP spawn,异步 |
| Subagent | 同步 exec(不加 background),等完成后返回 |
subagent 里也没有 sessions_spawn
ACP spawn 工具在 subagent 环境中不可用(未注入),所以从机制上就阻止了嵌套 spawn。
踩坑 4:ACP 权限需要显式配置¶
问题¶
ACP 调用的 agent 默认只有读权限(approve-reads),写文件、执行命令会被拦截。
解法¶
需要重启 gateway 生效。
超时策略¶
ACP 和 exec 调用 coding agent 时,超时最少 15 分钟起步。很多时候没法预估复杂度,给少了等于白跑。
| 任务类型 | 超时 |
|---|---|
| 一般任务 | 15 min (900s) |
| 复杂编码 / 调研 | 30 min (1800s) |
被超时杀掉 = 完全浪费
宁可多给时间。A killed run is a wasted run.
配置清单¶
最终让 ACP 全通的配置:
# 1. heartbeat 回调投递
openclaw config set agents.defaults.heartbeat.target last
# 2. exec 成功无输出也通知
openclaw config set tools.exec.notifyOnExitEmptySuccess true
# 3. ACP 全权限
openclaw config set plugins.entries.acpx.config.permissionMode approve-all
# 4. 安装 claude-agent-acp 避免 npm exec 包装
npm install -g @agentclientprotocol/claude-agent-acp
# 5. 重启 gateway
openclaw gateway restart