自带 CLI:如何用手机监控自定义 ACP 会话

一份实用指南:在电脑上运行你自己的 ACP 兼容 CLI,同时保留适合手机的查看、审批和后续消息工作流。

基于版本
CLI
0.2.17
预览 ref
a2c45c8

一旦你不再使用“默认”提供商,就会遇到一个熟悉的问题:

你可以在电脑上运行自己喜欢的 CLI。

但手机工作流消失了。

这份指南就是要把手机工作流找回来:

  • 在本地运行你自己的 ACP 兼容 CLI
  • 仍然能用手机监控会话
  • 仍然能处理审批和后续消息

简要总结

  1. 选一个你想在本地运行的 ACP 兼容 CLI。
  2. 把它定义为自定义 ACP(Custom ACP)后端(命令、检测、认证探测)。
  3. 在主机电脑上让它的行为确定可控:
    • 验证可执行文件路径
    • 验证工作目录规则
    • 验证检测和认证命令
  4. 使用紧凑的手机循环:查看 → 审批 → 一条后续消息 → 离开。

问题所在

自定义集成会因为一些实际原因失败:

  • 可执行文件路径错误
  • 工作目录错误
  • 认证没有落在正确的电脑上

所以第一个目标是让集成的行为确定可控。

常见做法及其权衡

  • SSH/tmux:可行,但会变成“在手机上做真正的终端工作”。
  • 远程桌面:笨重又麻烦。
  • 等待:安全,但慢。

真正好用的是一个专门的手机控制界面。

  • Happier:你的自定义 ACP CLI 仍然在电脑上运行,但你可以用手机界面查看进度、处理审批和发送后续消息。 权衡:它仍然依赖运行代理的电脑保持在线。

如果你第一次接触 Happier(它是什么,在哪里获取)

如果你之前没见过 Happier:它是一款面向编码会话的开源配套应用(移动端/网页/桌面)。

开始设置:

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 代理属于以下认证模式之一:

  1. 环境变量认证

    • 客户端带着环境变量启动代理
    • 简单,也便于自动化
  2. 终端登录认证

    • 你在终端里运行一次 <cli> login
    • 代理使用本机的认证状态
  3. 在界面中进行 OAuth(在以 CLI 为主的工具中较少见)

ACP 的认证设计刻意保持谨慎:代理不应能诱导客户端为认证运行任意命令。

第 3 步:手机工作流

2 分钟循环

  1. 打开会话
  2. 检查审批
  3. 发送一条后续消息
  4. 离开

三条可直接复制的后续消息

  1. 检查点

完成下一步后停下来,并总结:

  • 你改了什么
  • 你没改什么
  • 你接下来想做什么
  1. 约束

不要碰迁移和认证代码。如果你觉得必须改,先停下来问我。

  1. 依据

继续之前,把你接下来要运行的确切命令贴出来,并解释原因。

各客户端的配置示例(可复制)

一旦你的代理符合 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 是一款配套应用,用于在你信任的电脑上运行会话,并用手机监控。

开始设置:

acpcustommobileworkflows
最后更新: 2026-10-26