CodeBuddy 在 ACP(Agent Client Protocol)上的全部私有扩展清单:_meta 扩展键 + _codebuddy.ai/* 扩展方法。
面向两类读者:
第三方 ACP 客户端(Zed 等)——想知道哪些扩展可以读、哪些绝不该自己造;
CodeBuddy / WorkBuddy 内部开发者——改准入链路时,需要知道哪条键属于标准面、哪条属于多租户私有通道。
_meta 可用cbc --acp 的 initialize / session/new / session/prompt 全链路,客户端可以一个 codebuddy.ai/*_meta
都不带,且必须完整可用。 这是硬契约,不是“目前碰巧能跑”。
机制上由 process-login 组合根保证(profile cbc-tui / cbc-headless / agent-sdk-js-single):
src/node/session/process-login-admission-authority.ts —— 进程内自持 transport credential 与 principal,issueMainAdmission() 在同一处同时构造准入 envelope 与其 grant;
src/node/session/process-login-acp-admission-service.ts:60-84 —— admitAndActivate() 里整体替换metadata 为本进程自产的 ticket。原文注释即为契约:“客户端 _meta 完全不参与身份决策”。
外部 ACP 客户端既不可能、也不应该构造 runtime 准入 envelope,因此这条零 meta 路径是标准面的唯一正确形态。
常驻防线:src/e2e/acp-zero-meta-contract.spec.ts —— 裸 stdio NDJSON 驱动 bin/codebuddy --acp,
全程零 meta 跑 initialize → session/new → session/prompt,并对“missing … metadata”类错误直接判红。
对照面:multi-owner-headless 走的是 session-payload 组合根,它的 session/new
强制显式携带 _meta['codebuddy.ai/sessionAdmissionV2'](见 runtime-admission-acp-adapter.ts:47-48
抛 ACP Session request is missing sessionAdmissionV2 metadata)。那是私有通道,不是 ACP 协议要求——
两条组合根的差别只在“envelope 的生产者是谁”,与标准面无关。
C3 变更(workbuddy-single 形态正名 B1):WorkBuddy 桌面端(workbuddy-single)与
workbuddy-completion-warm 已从“per-session wire 身份 envelope”改为进程级身份注入——
daemon 在 initialize 之后经 _codebuddy.ai/activateWorkbuddyOwnerRuntime
(warm 侧是 _codebuddy.ai/activateCompletionRuntime)注入一次 owner 授权,此后 CLI 进程内
自产 envelope。这两条面的 session/new不再携带 sessionAdmissionV2 / authSession,
只保留 launcher 的 runtimeTransportCredential(transport 认证不变式,自签之前逐次校验)
与两个非身份业务授权键 sessionGrantV1 / completionDispatchGrantV1(§3.1)。
sessionAdmissionV2 的生产面收敛为三处,只有第一处仍过 daemon→CLI 的 wire:
host control sidecar(daemon 侧 workbuddy-host-control-authority.ts);
teammate leader 进程内自签、经 bootstrap channel 下发给 child(workbuddy-admission-security.tsissueTeammateAdmissionMetadata);
C3 后 workbuddy-single / completion-warm 进程内自签的主 envelope(同文件 issueMainAdmissionMetadata / issueCompletionDispatchMetadata)。
标注 | 含义 |
公共 | 公共可选扩展。标准 ACP 面( |
私有 | 多租户私有通道,仅 session-payload 组合根(WorkBuddy daemon ↔ CLI、multi-owner-headless)生产与消费。第三方 ACP 客户端不得生产这些键;标准面永远不会要求它们。 |
方向记法:A→C = Agent 发给 Client(响应 / 通知);C→A = Client 发给 Agent(请求参数);双向 = 两个方向都出现。
行号锚点免责:本文档所有 文件:行号 锚点对应撰写(及最近一次校对)时点的源码,仅供快速定位;
源码演进后行号必然漂移。以“文件 + 引用文案 / 符号”grep 为准,行号只作辅助。
canonical grep(可复核):
# 在 genie 仓根执行;git grep 天然排除 node_modules / dist / lib / out-tsc 等构建产物git grep --untracked -hoE "codebuddy\.ai/[A-Za-z0-9_.-]*" -- 'packages/**/*.ts' 'packages/**/*.tsx' | sort -u | wc -l# => 195(去重后的 token 数)
--untracked 是必须的:不带它只统计已跟踪文件,任何尚未提交的新增源文件都会
被漏掉,对账数字随提交时机漂移。只对账 token 数,不对账命中行数 —— 行数对
无关的注释改动都敏感,做不成稳定锚点。
注意:
-oE 的字符类不含 /,所以 _codebuddy.ai/foo 会被切出 token codebuddy.ai/foo(丢掉前导下划线),
_codebuddy.ai/session/rollback 会被切成 codebuddy.ai/session。195 是 token 数,不是 key 数,
需要按下表四分后才等于真实清单。
195 = 142 + 44 + 3 + 6,逐项在本文档内可查:
桶 | 数量 | 是什么 | 落在本文档 |
A | 142 | 真正的 | §3(全部列出) |
B | 44 | JSON-RPC 扩展方法/通知名( | §4(全部列出) |
C | 3 | 命名空间前缀 / 通配写法,不是独立键 | §5.1 |
D | 6 | 产品站 URL 路径伪命中( | §5.2 |
C3 对账变更(194→195):A 桶净额不变(删 completionDispatchId /
completionExecutionDigest,加 sessionGrantV1 / completionDispatchGrantV1);
B 桶 43→44(新增 _codebuddy.ai/activateWorkbuddyOwnerRuntime)。
判别方法(可复现):对每个 token,看它在源码里出现时前一个字符——_ ⇒ 扩展方法(B),
. 或 / ⇒ URL(D),其余 ⇒ _meta 键(A);再把“后面还能接 / 或 *”的通配前缀挑出来(C)。
_meta 扩展键全清单(142 条)本组是“公共 vs 私有”分界最要紧的地方。
键 | 方向 | 分类 | 生产者 | 消费者 | 语义 |
| A→C | 公共 | CLI, | session-payload 侧的 daemon(据此构造 envelope);标准面客户端可忽略 | 进程准入握手: |
| C→A | 私有 | multi-owner issuer(进程外签发);WorkBuddy 家族现仅剩 host control sidecar( |
|
|
| C→A | 私有 | daemon, |
| 身份撤出 |
| C→A | 私有 | daemon, |
| completion warm 的 per-dispatch 执行授权: |
| C→A | 私有 | daemon(session-payload 身份种子) |
|
|
| C→A | 私有 | daemon( |
| per-session 产品配置注入: |
| 双向 | 私有 | 准入核心( | 同上 | 绑定 transport 的一次性凭据,用于 admit 时证明连接身份 |
| A→C | 私有 |
| daemon | 准入成功后回带的 exact binding 投影:ownerId / ownerGeneration / canonicalSessionId / sessionGeneration / resourceId |
| C→A | 私有 | daemon |
| wire 请求的 binding token;非空字符串否则 |
| 双向 | 私有 | daemon / CLI |
| wire fencing 权威快照(processIncarnation / connectionEpoch / owner / session / run 各代际),失配抛 |
| C→A | 公共 | leader 启动 teammate 时注入( | teammate 子进程 | team 命名空间激活声明。两条组合根共用,不是 session-payload 独有;第三方客户端不会遇到。限定:唯一消费通道是 teammate bootstrap 启动链( |
| A→C | 公共 |
| 客户端 UI | 登录用户信息:userId / userName / userNickname / enterpriseId / enterpriseName / authType |
| - | 私有 | 无生产者(协议上不存在) | - | 仅出现在日志脱敏覆盖用例( |
| - | 公共 | 已退役 | - | 已退役死字段,生产与消费两侧代码均已物理删除(D6-7):全仓唯一命中是反向门禁用例 |
全部 公共:Agent 在响应 / 通知的 _meta 上回带,客户端可选消费;requestId / messageRequestId /
userMessageId / messageId 也接受客户端在 session/prompt 上先行下发(acp-agent.ts:2925-2938),缺省则由 CLI 自产。
键 | 方向 | 生产者 | 语义 |
| 双向 |
| 一次模型请求的全链路关联 ID(命中数最高的键) |
| 双向 |
| 消息级 ID |
| 双向 |
| 消息 ↔ 请求的关联 ID |
| 双向 |
| 用户消息 ID( |
| 双向 |
| Renderer 每次 send/resend 生成的业务关联 ID,供 Desktop 埋点 + Galileo 串联 |
| C→A | 客户端 | 工具调用上的客户端自定义关联 ID( |
| A→C |
| 模型侧请求 ID |
| A→C |
| CLI 侧 trace ID |
| A→C |
| W3C traceparent 回传,使 renderer 的 stream_render span 能挂到 prompt.send 下 |
| A→C |
| SessionRunStateMachine 的 run ID |
| A→C |
| run 状态快照 revision |
| A→C |
| Agent 执行阶段( |
| A→C |
| 时间戳(归一化时会删除该扁平键,统一走规范位置) |
| C→A | Renderer | 用户点击发送的时间戳,供 message 维度用户视角 TTFT 计算( |
| A→C | 上游 | LF 会话 ID(扁平透传, |
| A→C | 上游 | LF 会话请求 ID(同上) |
键 | 方向 | 分类 | 生产者 → 消费者 | 语义 |
| 双向 | 公共 |
| 场景模式(scene mode) |
| C→A | 公共 | Renderer → | 埋点 / trace attribute 用的用户 ID(不参与身份决策,身份只认 JWT) |
| 双向 | 公共 |
| 上游会话 ID |
| C→A | 公共 |
| 语言 / 区域 |
| 双向 | 公共 |
| 专家(expert)ID |
| A→C | 公共 |
| 专家选择提醒块标记 |
| A→C | 公共 |
| 子代理会话的父 session ID |
| A→C | 公共 |
| 是否子代理会话(注意与下面 |
| A→C | 公共 |
| 工具调用维度“是否子代理调用” |
| A→C | 公共 |
| 子代理类型(默认 |
| A→C | 公共 |
| 是否后台执行 |
| A→C | 公共 |
| 是否 playground 场景 |
| C→A | 公共 |
|
|
| 双向 | 公共 |
| 会话控制指令载荷 |
键 | 方向 | 分类 | 生产者 | 语义 |
| A→C | 公共 |
| 与 |
| A→C | 公共 |
| 模型 finish reason |
| A→C | 公共 |
| prompt 结果判定( |
| A→C | 公共 |
| 业务失败标记,供 UI renderer 与传输失败区分 |
| A→C | 公共 |
| 取消原因 |
| A→C | 公共 |
| prompt result 上的取消成因(automation 优先读它) |
| A→C | 公共 |
| 终止原因(如 |
| A→C | 公共 |
| prompt 失败发生的阶段 |
| A→C | 公共 | 同上 | prompt 失败原因 |
| A→C | 公共 | 同上 | 该次失败是否可安全重放 |
| A→C | 公共 |
| 传输连接丢失标记 |
| A→C | 公共 | 同上 | 传输错误码(如 |
全部 公共,绝大多数由 acp-agent.ts:5013-5064 一段集中从 provider data 复制到 toolCallMeta。
键 | 生产者 | 语义 |
|
| 工具名 |
|
| 关联的工具调用 ID |
|
| 父工具调用 ID(子代理嵌套) |
|
| 工具取消原因( |
|
| 工具失败原因分类 |
|
| 工具结果标题(转写投影用) |
|
| 工具调用描述 |
|
| 操作类型(如 |
|
| 操作目标(如 MCP server 名) |
|
| 关联文件名 |
|
| 图片载荷 |
|
| 工具原始结构化结果,透传给 UI renderer(如 web-search) |
|
| 批量删除信息 |
|
| 旁路提示 |
|
| 拦截类型 |
|
| 沙箱拦截标记 |
|
| 沙箱审批模式 |
|
| MCP-UI 反向调用拦截标记 |
|
| Hook 结构化阻断信息 |
|
| 事件补充明细 |
全部 公共。
键 | 生产者 | 语义 |
|
| 权限决策结果 |
|
| 权限已解决通知 |
|
| ExitPlanMode 的计划正文 |
|
| 目标进度 |
|
| 目标回顾 |
|
| 目标状态 |
|
| 中断(HITL)请求载荷 |
|
| Prompt 建议 |
键 | 方向 | 分类 | 生产者 | 语义 |
| A→C | 公共 |
| 历史回放边界标记( |
| A→C | 公共 |
| 回放总条目数(仅 |
| A→C | 公共 |
| 渲染层回放标记 |
| A→C | 私有 |
| owner 快照回放标记——owner 概念只在 session-payload 多租户下成立 |
| A→C | 公共 |
| 会话分隔帧标记 |
| A→C | 公共 | 同上 | 分隔帧附加信息 |
| A→C | 公共 | 同上 | 帧创建时间 |
| A→C | 公共 |
| 转写源 offset(旧键) |
| A→C | 公共 |
| 转写源 offset(新键,优先于 |
| A→C | 公共 |
| 转写截断前的原始字节数 |
全部 公共,走 session_info_update._meta。
键 | 生产者 | 语义 |
|
| 压缩类型,desktop adapter 据此决定呈现 |
|
| 压缩状态 |
|
|
|
|
|
|
|
| 该帧在压缩中被截断 |
|
| 该 prompt 是 compact 内部触发(不计入用户可见轮次) |
键 | 方向 | 分类 | 生产者 | 语义 |
| A→C | 公共 |
| Team 状态事件(成员状态变更等) |
| A→C | 公共 |
| 成员流式消息的归属标签(成员名) |
| A→C | 公共 |
| 工具调用所属成员名 |
| A→C | 公共 |
| 该工具调用来自 team 成员 |
| A→C | 公共 |
| 成员展示色 |
| A→C | 公共 |
| 合成的 teammate 消息(非模型直出) |
| A→C | 公共 | 同上 | teammate 摘要文本 |
全部 公共,由 src/node/workflow/acp/workflow-acp-bridge.ts:146-190 一处集中生产,键空间统一为 codebuddy.ai/workflow*。
键 | 行 | 语义 |
|
| 事件类型 |
|
| 运行 ID |
|
| 工作流名 |
|
| 运行状态 |
|
| agent 总数 |
|
| 命中缓存的 agent 数 |
|
| 阶段总数 |
|
| 运行级错误 |
|
| 当前阶段 |
|
| agent key |
|
| agent 展示名 |
|
| agent 阶段 |
|
| agent 级错误 |
|
| agent token 消耗 |
全部 公共,由 acp-utils.ts:481-491 生产、Web UI use-acp.ts:202-213 消费。承载企业微信等外部渠道的来源信息。
键 | 语义 |
| 渠道来源标识 |
| 发送者 ID |
| 发送者展示名 |
| 会话 ID |
| 会话类型( |
| 命令种类( |
键 | 方向 | 分类 | 生产者 | 语义 |
| C→A | 公共 | MCP-UI widget( | widget 回写消息的行为路由: |
| A→C | 公共 |
| 消息队列增量更新 |
| A→C | 公共 |
| 命令触发新建会话后的新 sessionId |
| A→C | 公共 |
| 会话被重置(如 |
键 | 方向 | 分类 | 生产者 | 语义 |
| A→C | 公共 |
|
|
| A→C | 公共 |
| 内容过滤提示( |
| C→A | 公共 |
| 该 prompt 块是隐藏上下文,不在 UI 呈现 |
| A→C | 公共 |
|
|
| A→C | 公共 |
| 该 update 的来源事件客观描述(facets),供 adapter 分流 |
全部 公共,acp-agent.ts:3437-3447 集中回填。
键 | 语义 |
| 请求所用模型 ID |
| 请求所用模型名 |
| 实际响应模型 ID |
| 实际响应模型名( |
C3 变更:completionDispatchId / completionExecutionDigest 两个扁平键已随
buildEphemeralMetadata 一并物理删除,其语义并入 §3.1 的
completionDispatchGrantV1(结构化的 per-dispatch 执行授权)。
键 | 方向 | 分类 | 生产者 | 语义 |
| A→C | 公共 |
|
|
| A→C | 公共 |
| 扁平模型名(span 归因用) |
私有键小计(10 条):sessionAdmissionV2、sessionGrantV1、completionDispatchGrantV1、
authSession、productConfig、runtimeTransportCredential、runtimeSessionBindingV2、
runtimeBindingToken、runtimeAuthority、ownerSnapshotHistoryReplay
—— 再加上“无生产者但归属凭据面”的 accessToken,共 11 条在标准 ACP 面永远不出现。
其余 131 条为公共可选扩展。
_codebuddy.ai/* 扩展方法 / 通知全清单(44 条)ACP 规定自定义方法以下划线前缀 + 反向域名命名空间。这些不是 _meta 键,但共享同一命名空间,
第三方客户端同样需要知道它们的公共 / 私有归属。清单入口:packages/agent-client-protocol/src/common/types.ts:25-35。
方法名 | 方向 | 分类 | 语义 |
| A→C(request) | 公共 | HITL 提问,等待客户端应答( |
| C→A(request) | 公共 | 客户端回答中断请求( |
| A→C(notify) | 公共 | 产物推送( |
| A→C(notify) | 公共 | 命令事件( |
| A→C(notify) | 公共 | checkpoint 事件( |
| C→A(request) | 公共 | 会话回滚( |
| C→A(request) | 公共 | 文件级回滚 |
| C→A(request) | 公共 | 回滚预览 |
| A→C(notify) | 公共 | 文件历史快照( |
| A→C(notify) | 公共 | 文件树变更(须带 filePath) |
| A→C(notify) | 公共 | 登录跳转 URL( |
| C→A(request) | 公共 | 拉取用户信息( |
| A→C(request) | 公共 | UI 控制指令( |
| A→C(notify) | 公共 | 系统初始化通知 |
| A→C(request) | 公共 | 工具输入征询( |
| A→C(request) | 公共 | 工具代理执行( |
| C→A(notify) | 公共 | 客户端可代理工具集变更( |
| C→A(request) | 公共 | 请求刷新插件( |
| A→C(notify) | 公共 | 插件集变更 |
| A→C(notify) | 公共 | MCP server 集变更 |
| A→C(notify) | 公共 | 模型列表变更 |
| A→C(notify) | 公共 | 产品配置变更 |
| A→C(notify) | 公共 | 身份变更广播(主进程写入后广播到所有 live session) |
| A→C(notify) | 公共 | 队列状态变更 |
| A→C(notify) | 公共 | 消息队列快照变更 |
| A→C(notify) | 公共 | automation 快照 |
| A→C(notify) | 公共 | 交互超时( |
| A→C(notify) | 公共 | Team SSE 事件( |
| A→C(notify) | 公共 | 会话事件( |
| C→A(request) | 公共 | MCP-UI 反向 tools/call |
| C→A(request) | 公共 | MCP-UI 读资源 |
| C→A(request) | 公共 | MCP-UI 更新模型上下文 |
| C→A(request) | 公共 | MCP-UI 请求显示模式 |
| C→A(request) | 公共 | MCP-UI 资源释放 |
| C→A(request) | 公共 | 应答沙箱拦截( |
| C→A(request) | 私有 | control Session 准入。process-login 组合根直接 |
| C→A(request) | 私有 | per-session exact 凭据更新( |
| C→A(request) | 私有 | control binding 凭据更新( |
| C→A(request) | 私有 | owner 级批量凭据更新( |
| C→A(request) | 私有 | C3 新增:向 workbuddy-single 进程注入一次 owner 授权(authSession + product 材料 + 凭据句柄),此后 |
| C→A(request) | 私有 | 激活 completion warm 运行时;**C3 起 claims 追加 |
| C→A(request) | 私有 | 分发一次 completion( |
| C→A(request) | 私有 | completion 运行时诊断( |
| C→A(request) | 私有 | 销毁 ephemeral session( |
| C→A(request) | 私有 | 销毁 persistent session( |
| —— | —— | 测试用占位方法名,仅出现在 |
表内 46 行 = 44 个 grep token + session/rollbackFiles / session/previewFileRollback 两个子路径(它们与 session/rollback 共享 token codebuddy.ai/session,grep 只算一次)。
token | 出现形态 | 说明 |
|
| 命名空间前缀本身。守卫点: |
| 注释里的 | 键空间通配写法( |
| 注释里的 | 5 个 MCP-UI 扩展方法的通配写法( |
以下 token 出自 https://www.codebuddy.ai/... / https://code.codebuddy.ai/... 这类 URL,与协议无关:
token | 出处 |
|
|
|
|
|
|
|
|
|
|
|
|
6.1 不要生产任何 codebuddy.ai/*_meta 键来做身份或准入。§3.1 标注为“私有”的键由 CodeBuddy 内部组合根签发,客户端自造只会被拒(envelope 校验、digest 比对、fencing 全都过不去)。
6.2 可以安全读取所有“公共”键,并按需忽略。它们全部是可选增量信息,语义变化不会破坏基础 ACP 流程。
6.3 session/prompt 上可选携带的关联 ID(requestId / messageId / messageRequestId /userMessageId / promptRequestId / clientRequestId / sendTime / traceparent)是唯一推荐客户端主动生产的一组——它们只影响埋点与链路串联,不参与任何鉴权判断。
6.4 _codebuddy.ai/* 扩展方法:§4 里标注“私有”的 9 个(admitControl + 三个 runtime*CredentialUpdate
completion 三件套 + dispose 两件套)只在 WorkBuddy 内部通道出现,标准面调用会被拒绝。
ACP 协议集成:--acp 启动方式、Zed 配置、协议特性
零 _meta 常驻 e2e:src/e2e/acp-zero-meta-contract.spec.ts
准入契约实现:src/node/session/runtime-admission-acp-adapter.ts、src/node/session/process-login-acp-admission-service.ts、src/node/session/multi-owner-acp-admission-service.ts
profile 注册表:packages/runtime-admission-protocol/src/runtime-admission-contract.ts