- CLI
- 0.2.17
- 预览 ref
- a2c45c8
一旦你不再使用“默认”提供商,就会遇到一个熟悉的问题:
你可以在电脑上运行自己喜欢的 CLI。
但手机工作流消失了。
这份指南就是要把手机工作流找回来:
- 在本地运行你自己的 ACP 兼容 CLI
- 仍然能用手机监控会话
- 仍然能处理审批和后续消息
简要总结
- 选一个你想在本地运行的 ACP 兼容 CLI。
- 把它定义为自定义 ACP(Custom ACP)后端(命令、检测、认证探测)。
- 在主机电脑上让它的行为确定可控:
- 验证可执行文件路径
- 验证工作目录规则
- 验证检测和认证命令
- 使用紧凑的手机循环:查看 → 审批 → 一条后续消息 → 离开。
问题所在
自定义集成会因为一些实际原因失败:
- 可执行文件路径错误
- 工作目录错误
- 认证没有落在正确的电脑上
所以第一个目标是让集成的行为确定可控。
常见做法及其权衡
- SSH/tmux:可行,但会变成“在手机上做真正的终端工作”。
- 远程桌面:笨重又麻烦。
- 等待:安全,但慢。
真正好用的是一个专门的手机控制界面。
- Happier:你的自定义 ACP CLI 仍然在电脑上运行,但你可以用手机界面查看进度、处理审批和发送后续消息。 权衡:它仍然依赖运行代理的电脑保持在线。
如果你第一次接触 Happier(它是什么,在哪里获取)
如果你之前没见过 Happier:它是一款面向编码会话的开源配套应用(移动端/网页/桌面)。
开始设置:
- GitHub: https://github.com/happier-dev/happier
- 安装/下载: https://github.com/happier-dev/happier#how-it-works
- Discord: https://discord.gg/W6Pb8KuHfg
90 秒了解 ACP(帮助理解本指南的其余部分)
ACP(Agent Client Protocol)是以下两者之间的协议:
- 客户端(应用、IDE、仪表盘)
- 代理进程(你的 CLI)
默认传输方式是 stdio:以换行分隔的 JSON-RPC 消息。
主要的实际影响是:
- 代理的 stdout 就是协议本身
- 日志必须输出到 stderr
如果把日志混进 stdout,客户端就无法解析数据流,一切看起来都“坏了”。
ACP 与 MCP(为什么两者都会出现)
- ACP 是客户端与代理会话通信的方式。
- MCP 是代理与工具服务器(GitHub、浏览器自动化等)通信的方式。
ACP 会话可以带着 mcpServers 列表启动,所以你可以同时拥有:
- 一个自定义代理 CLI
- 一套一致的工具
决定自定义 ACP 成败的规则(stdio 约定)
这些是常见的集成杀手:
- stdout 中只能有 ACP 协议消息
- 日志必须输出到 stderr
- 消息以换行分隔,所以单条 JSON 消息内部不能有换行
- 不要美化输出 JSON(
indent=2会导致出错)
如果你想快速测试“我的代理是否兼容”:
- 以 ACP 模式运行它,确认它能在不打印横幅的情况下响应
initialize
第 1 步:定义你的自定义 ACP 后端
很多人卡在这里,因为这是细致的配置工作。
你需要定义:
- 名称/ID(你如何识别它)
- 命令(如何启动它)
- 检测命令(安全地探测“是否已安装”)
- 认证探测(可选,只在安全时使用)
- 工作目录预期(它是否假定在仓库根目录)
一个省时的规则:先只做检测,之后再加认证探测。
能力协商(不要假定方法存在)
ACP 从 initialize 开始。
代理会返回它的能力。
客户端不应调用代理没有声明支持的方法。
如果不支持“恢复/加载”,你会看到这样的症状:
- 本想恢复会话,却启动了新会话
- 历史记录缺失
所以对于自定义 ACP,先发布一个最小化的代理(新会话和提示),之后再添加生命周期方法,是很正常的。
第 2 步:先在一台电脑上让集成行为确定
在尝试多电脑工作流之前,先让它在一台电脑上跑通。
“在我的终端里能用”和“由客户端启动时能用”的差别就出在这里。
检查清单:
- 命令能否在预期的工作目录中运行?
- 它是否依赖 shell 初始化文件(
.zshrc、nvm、asdf)? - 它是否需要环境变量或密钥?
- 它是否向 stdout 打印横幅或进度条?
如果 CLI 需要凭据,不要把它们粘贴到后端定义里。使用环境变量或已保存的密钥机制。
常见的认证模式
大多数 ACP 代理属于以下认证模式之一:
-
环境变量认证
- 客户端带着环境变量启动代理
- 简单,也便于自动化
-
终端登录认证
- 你在终端里运行一次
<cli> login - 代理使用本机的认证状态
- 你在终端里运行一次
-
在界面中进行 OAuth(在以 CLI 为主的工具中较少见)
ACP 的认证设计刻意保持谨慎:代理不应能诱导客户端为认证运行任意命令。
第 3 步:手机工作流
2 分钟循环
- 打开会话
- 检查审批
- 发送一条后续消息
- 离开
三条可直接复制的后续消息
- 检查点
完成下一步后停下来,并总结:
- 你改了什么
- 你没改什么
- 你接下来想做什么
- 约束
不要碰迁移和认证代码。如果你觉得必须改,先停下来问我。
- 依据
继续之前,把你接下来要运行的确切命令贴出来,并解释原因。
各客户端的配置示例(可复制)
一旦你的代理符合 ACP,下一个痛点就是客户端配置格式。
常见的几种:
- 通过
acp.json配置的 JetBrains 自定义代理 - Zed 设置 JSON
- Neovim CodeCompanion ACP 客户端(有明确的限制)
没有统一的通用文件格式。
规则是:先选一个客户端并让它在那里跑通,再扩展到其他客户端。
调试步骤(在怪罪代理之前)
1) 证明代理的 stdout 是干净的
如果出现解析错误,80% 的情况是 stdout 里有不是 JSON-RPC 的内容。
把所有日志都输出到 stderr。
2) 避免消息内换行
不要美化输出 JSON 消息。一条消息必须是一行。
3) 证明工作目录符合你的预期
很多自定义代理看似“能用”,但因为 cwd 不对,操作的是错误的仓库。
故障排查
检测正常,但会话无法启动
通常意味着:
- 缺少环境变量
- 工作目录错误
- CLI 向 stdout 打印横幅或日志
- CLI 需要 TTY(与 stdio ACP 不兼容)
代理启动了,但工具没有出现
这通常是 MCP 配置不匹配:
- stdio 与 http/sse 字段不一致
- 缺少请求头或环境变量
认证显示“未知(Unknown)”
如果你的认证探测不安全(或没有定义),显示未知(Unknown)是预期行为。
把它理解为“不知道”,而不是“已登出”。
常见问题
我需要实现完整的 ACP 规范吗?
不需要。
一个“最小可用”的代理支持:
- initialize
- session/new
- session/prompt
其余的(加载/恢复、丰富的工具、附件)都可以以后再加。
为什么在终端里能用,在 IDE 或应用里却不行?
几乎总是以下之一:
- PATH 或环境变量不一致
- 工作目录错误
- stdout 被污染
让代理控制认证命令安全吗?
ACP 明确针对这一点做了防护:终端认证流程应运行同一个可执行文件,代理不应能指定任意命令。
如果你第一次接触 Happier
Happier 是一款配套应用,用于在你信任的电脑上运行会话,并用手机监控。
开始设置: