协作式人类-Agent 协议(CHAP)
英文标题:🔶 Collaborative Human Agent Protocol (CHAP)
CHAP 是一项面向人类与 Agent 协同工作的协议,旨在把 Agent 草稿、人工编辑、审批与拒绝等决策统一记录为可查询、可回放、可验证的哈希链式 envelope。它将人工修改表示为包含 diff、理由和可控标签的结构化 override,使团队无需跨日志、工单和聊天工具追溯决策。项目提供 TypeScript 与 Python 参考实现,覆盖 Core 与全部 11 个可选 profile、共 39 个方法处理器,并支持 MCP 和 A2A 传输。对开发者而言,CHAP 可将人工纠偏沉淀为可聚合的监督数据,用于识别 Agent 的高频错误模式并迭代提示词、检索和任务上下文。
176.9 KB
45.0 KB
中文
协作式人类-Agent 协议(CHAP)
供人类与 Agent 真正协同完成工作的协议。
当机器人起草内容、而人类进行编辑时,这次编辑存放在哪里?在 CHAP 中,它位于一个 envelope 中;六个月后,你仍可以查询、回放并验证它。
安装 · 90 秒导览 · 十二种场景 · 关于此仓库 · 论文
你已经在让 Agent 处理真实工作:起草代码审查、分流工单、提出和解建议、审查合同。人类会批准、编辑或拒绝其中每一项。现在,这项决策分散在你的应用代码、聊天线程、工单评论和你的脑海里。六周后某件事出错时,重建当时经过需要花 45 分钟,而且一半靠猜。
CHAP 为你提供一个存放这些决策的位置,以及统一的记录形态。Agent 的草稿是一项工件(artefact)。人类的编辑是一项结构化 override,其中包含 diff、理由和你可控制的标签。整个过程通过内容哈希串联。你查询这条链,而不是在四个 UI 中 grep 日志。
这就是全部主张。
一名使用 Cursor 审查 pull request 的独立开发者。机器人标记出一个开发者并不同意的“警告”。以下是完整的端到端交互。下方片段以六个标注步骤在约 23 秒内演示完成;对应代码紧随其后。
以下是全部代码。下方叙述以两种语言讲述同一个连续故事;请选择你实际使用的技术栈。
1. 创建工作区。 一个使用 SQLite 持久化的嵌入式协调器、两名参与者和一个工作区:
| TypeScript | Python |
|---|
import { Coordinator } from "@brightbeamai/chap-coordinator";
import { SqliteStore } from
"@brightbeamai/chap-coordinator/storage/sqlite";
const coord = new Coordinator({
store: new SqliteStore("./chap.db"),
});
coord.api.workspace.create({
workspace: "wsp_pr_reviews",
profiles: ["core/1.0", "review/1.0"],
});
coord.api.participant.join({
workspace: "wsp_pr_reviews",
from: "human:me@local",
type: "human",
});
coord.api.participant.join({
workspace: "wsp_pr_reviews",
from: "agent:cursor#v1",
type: "agent",
});
|
from chap_coordinator import Coordinator
from chap_coordinator.storage.sqlite \
import SqliteStore
coord = Coordinator(store=SqliteStore("./chap.db"))
def send(method, params):
return coord.dispatch({
"jsonrpc": "2.0", "id": method,
"method": method, "params": params,
})
send("workspace.create", {
"workspace": "wsp_pr_reviews",
"profiles": ["core/1.0", "review/1.0"],
})
send("participant.join", {
"workspace": "wsp_pr_reviews",
"from": "human:me@local",
"type": "human",
})
send("participant.join", {
"workspace": "wsp_pr_reviews",
"from": "agent:cursor#v1",
"type": "agent",
})
2. 机器人起草,你进行 override。 将现有的 Cursor 集成接入,使其发出 envelope:
| TypeScript | Python |
|---|
// The bot's review is the output of a task.
const { task_id } = coord.api.task.create({
workspace: "wsp_pr_reviews",
from: "agent:cursor#v1",
assignee: "agent:cursor#v1",
kind: "code_review",
input: { pr_id: "PR-482" },
});
coord.api.task.complete({
workspace: "wsp_pr_reviews",
from: "agent:cursor#v1",
task_id,
output: cursorReview,
});
coord.api.review.request({
workspace: "wsp_pr_reviews",
from: "agent:cursor#v1",
task_id,
artefact: cursorReview,
to: "human:me@local",
});
// You disagree with one comment. Override it.
coord.api.decide.override({
workspace: "wsp_pr_reviews",
from: "human:me@local",
task_id,
intent_preserved: true,
diff: [{ op: "replace",
path: "/comments/0/severity",
value: "info" }],
rationale: "False positive. Framework " +
"convention, not a bug.",
tags: ["false-positive",
"framework-pattern-misread"],
});
|
# The bot's review is the output of a task.
r = send("task.create", {
"workspace": "wsp_pr_reviews",
"from": "agent:cursor#v1",
"assignee": "agent:cursor#v1",
"kind": "code_review",
"input": {"pr_id": "PR-482"},
})
task_id = r["result"]["task_id"]
send("task.complete", {
"workspace": "wsp_pr_reviews",
"from": "agent:cursor#v1",
"task_id": task_id,
"output": cursor_review,
})
send("review.request", {
"workspace": "wsp_pr_reviews",
"from": "agent:cursor#v1",
"task_id": task_id,
"artefact": cursor_review,
"to": "human:me@local",
})
# You disagree with one comment. Override it.
send("decide.override", {
"workspace": "wsp_pr_reviews",
"from": "human:me@local",
"task_id": task_id,
"intent_preserved": True,
"diff": [{"op": "replace",
"path": "/comments/0/severity",
"value": "info"}],
"rationale": "False positive. Framework "
"convention, not a bug.",
"tags": ["false-positive",
"framework-pattern-misread"],
})
关于接口层。 TypeScript 提供了带类型的 facade(
coord.api.*),因此每个方法都能获得完整的自动补全和编译期检查。Python 则在接口层保留 JSON-RPC envelope 形态(coord.dispatch({...})),使用者可按调用位置的需要自行封装;send()helper 是 Python 测试所使用的惯用方式。两条路径发出的 wire bytes 完全一致;无论调用来自哪个客户端,审计链都逐字节相同。
3. 两个月后,分析你一直在做什么。 这正是该协议开始回报价值之处。参考仓库同时提供两种语言的分析脚本,可读取审计链(通过 HTTP 或直接从 SQLite 文件),并对 override 进行分组:
# TypeScript reference, against the SqliteStore from step 1:
$ npm --prefix reference/core-plus-review run analyze -- --db ./chap.db wsp_pr_reviews
# Python reference, same idea:
$ python3 reference/python/analyze_overrides.py --db ./chap.db wsp_pr_reviews
Override Learning Report
========================
Total overrides: 47
By tag:
false-positive ████████████████ 31 (66%)
framework-pattern-misread ███████████ 22 (47%)
cosmetic-pref ████ 8 (17%)
Top file paths:
src/handlers/ 18 overrides
src/components/ 9 overrides
你对 Cursor 的下一次提示词修订不再是猜测,而是可以点名引用这一模式。
Override envelope 详解
Override envelope 是 CHAP 中最重要的单一结构。每个字段都有明确职责:
首次阅读时,大多数人会忽略的两个字段是 intent_preserved 和 tags。
intent_preserved 用于区分细化型(refining) override(人类同意 Agent 的决策,但重写了其表达方式)与替代型(substituting) override(人类得出了不同的决策)。这两者是不同的失败模式,需要不同的修复方式。若某一政策条款周围的细化型 override 比率很高,意味着 Agent 的检索存在偏差;若同一条款的替代型 override 比率很高,则说明政策本身可能含糊,或者 Agent 的任务上下文有误。
tags 是团队共同约定的受控词汇表。应保持精简。你放入其中的任何内容,都会成为三个月后你聚合分析的维度,届时可回答诸如*哪些提示词需要改进?或机器人在哪些路径上持续出错?*这样的问题。
TypeScript / Node:
npm install @brightbeamai/chap-coordinator
Python:
pip install chap-coordinator
无论选择哪条路径,你都会获得 Core、review/1.0 profile 以及可运行的参考实现。TypeScript 参考实现位于 reference/;Python 参考实现位于 reference/python/。TypeScript 库位于 packages/coordinator/;Python 库位于 packages/coordinator-py/。
五分钟实操导览:examples/00-five-minute-start.md。
CHAP 0.2 是一份公开草案。具体而言,此仓库包含:
- 规范。 Core(七个方法、一个 envelope、一种 wire format)以及 11 个可选 profile。可在
SPECIFICATION.md中阅读合并后的单一文档,或分别阅读core/SPEC.md与profiles/。 - 两个参考实现。 两者均覆盖 Core 加上每一个 profile,共计 39 个方法处理器。TypeScript 参考实现位于
packages/coordinator/,其 HTTP 服务器位于reference/core/和reference/core-plus-review/;还提供一个可运行的 playground,包含两个浏览器会话和本地 LLM,位于reference/playground/。Python 参考实现位于packages/coordinator-py/,HTTP 服务器位于reference/python/。两者均在同一条 JSON-RPC 2.0 wire 上通过一致性测试套件。 - 一致性测试套件。 包含 23 个测试向量、签名/规范化/链检查,以及 in-toto 证明输出。目前可声明两个一致性级别(Minimal、Recommended);Full 级别仍等待两个实现之间更广泛的互操作性测试。
- MCP 服务器传输。 CHAP Coordinator 可将自身呈现为一个 MCP 服务器,把每个 CHAP 方法作为工具公开。将 Claude Desktop、Cursor、Claude Code 或任意 MCP 客户端指向它,即可通过自然语言驱动 CHAP 工作区。TypeScript adapter 位于
packages/coordinator-mcp/,Python adapter 位于chap_coordinator.transports.mcp_server,可运行的参考服务器位于reference/mcp-server-ts/和reference/mcp-server-py/。五分钟导览位于examples/drive-chap-from-claude-desktop.md。 - A2A 服务器传输。 CHAP Coordinator 也可以将自身呈现为一个 A2A Agent,在其 Agent Card 上将每个 CHAP 方法声明为独立技能。任意具备 A2A 感知能力的编排器(Azure AI Foundry、Amazon Bedrock AgentCore、Google ADK、自定义多 Agent 系统)都可以通过 URL 注册该协调器,并向其委派工作。TypeScript adapter 位于
packages/coordinator-a2a/,Python adapter 位于chap_coordinator.transports.a2a_server,参考服务器位于reference/a2a-server-ts/和reference/a2a-server-py/。导览位于 [examples/drive-chap-from-an-a2a-orchestrator.md](/BrightbeamAI/ch
English / 原文
Collaborative Human-Agent Protocol (CHAP)
The protocol for humans and agents doing real work together.
When a bot drafts something and a human edits it, where does that edit live? In CHAP, it lives in an envelope you can query, replay, and verify six months later.
Install · The 90-second tour · Twelve scenarios · About this repo · Paper
You have agents doing real work. Drafting code reviews, triaging tickets, suggesting settlements, reviewing contracts. A human approves, edits, or rejects each one. Right now, that decision lives in your application code, your chat threads, your ticket comments, and your head. When something goes wrong six weeks later, reconstructing what happened costs you forty-five minutes and is half guesswork.
CHAP gives you one place to put those decisions and one shape to put them in. The agent's draft is an artefact. The human's edit is a structured override with a diff, a rationale, and tags you control. The whole thing chains together by content hash. You query the chain instead of grepping logs across four UIs.
That's the whole pitch.
A solo developer using Cursor to review pull requests. The bot flags a "warning" the developer disagrees with. Here is the whole exchange, end to end. The clip below runs in about 23 seconds across six labelled steps; the matching code is right underneath.
And here is the code, every line of it. The narrative below is one continuous story in two languages; pick whichever stack you actually use.
1. Spin up a workspace. An embedded coordinator with SQLite persistence, two participants, a workspace:
| TypeScript | Python |
|---|
import { Coordinator } from "@brightbeamai/chap-coordinator";
import { SqliteStore } from
"@brightbeamai/chap-coordinator/storage/sqlite";
const coord = new Coordinator({
store: new SqliteStore("./chap.db"),
});
coord.api.workspace.create({
workspace: "wsp_pr_reviews",
profiles: ["core/1.0", "review/1.0"],
});
coord.api.participant.join({
workspace: "wsp_pr_reviews",
from: "human:me@local",
type: "human",
});
coord.api.participant.join({
workspace: "wsp_pr_reviews",
from: "agent:cursor#v1",
type: "agent",
});
|
from chap_coordinator import Coordinator
from chap_coordinator.storage.sqlite \
import SqliteStore
coord = Coordinator(store=SqliteStore("./chap.db"))
def send(method, params):
return coord.dispatch({
"jsonrpc": "2.0", "id": method,
"method": method, "params": params,
})
send("workspace.create", {
"workspace": "wsp_pr_reviews",
"profiles": ["core/1.0", "review/1.0"],
})
send("participant.join", {
"workspace": "wsp_pr_reviews",
"from": "human:me@local",
"type": "human",
})
send("participant.join", {
"workspace": "wsp_pr_reviews",
"from": "agent:cursor#v1",
"type": "agent",
})
2. The bot drafts, you override. Wire your existing Cursor integration to emit envelopes:
| TypeScript | Python |
|---|
// The bot's review is the output of a task.
const { task_id } = coord.api.task.create({
workspace: "wsp_pr_reviews",
from: "agent:cursor#v1",
assignee: "agent:cursor#v1",
kind: "code_review",
input: { pr_id: "PR-482" },
});
coord.api.task.complete({
workspace: "wsp_pr_reviews",
from: "agent:cursor#v1",
task_id,
output: cursorReview,
});
coord.api.review.request({
workspace: "wsp_pr_reviews",
from: "agent:cursor#v1",
task_id,
artefact: cursorReview,
to: "human:me@local",
});
// You disagree with one comment. Override it.
coord.api.decide.override({
workspace: "wsp_pr_reviews",
from: "human:me@local",
task_id,
intent_preserved: true,
diff: [{ op: "replace",
path: "/comments/0/severity",
value: "info" }],
rationale: "False positive. Framework " +
"convention, not a bug.",
tags: ["false-positive",
"framework-pattern-misread"],
});
|
# The bot's review is the output of a task.
r = send("task.create", {
"workspace": "wsp_pr_reviews",
"from": "agent:cursor#v1",
"assignee": "agent:cursor#v1",
"kind": "code_review",
"input": {"pr_id": "PR-482"},
})
task_id = r["result"]["task_id"]
send("task.complete", {
"workspace": "wsp_pr_reviews",
"from": "agent:cursor#v1",
"task_id": task_id,
"output": cursor_review,
})
send("review.request", {
"workspace": "wsp_pr_reviews",
"from": "agent:cursor#v1",
"task_id": task_id,
"artefact": cursor_review,
"to": "human:me@local",
})
# You disagree with one comment. Override it.
send("decide.override", {
"workspace": "wsp_pr_reviews",
"from": "human:me@local",
"task_id": task_id,
"intent_preserved": True,
"diff": [{"op": "replace",
"path": "/comments/0/severity",
"value": "info"}],
"rationale": "False positive. Framework "
"convention, not a bug.",
"tags": ["false-positive",
"framework-pattern-misread"],
})
About the surfaces. TypeScript ships a typed facade (
coord.api.*) so every method gets full autocomplete and compile-time checks. Python keeps the JSON-RPC envelope shape on the surface (coord.dispatch({...})) and consumers wrap it however suits the call site; asend()helper is the idiom the Python tests use. Both paths emit identical wire bytes; the audit chain is byte-for-byte the same regardless of which client made the call.
3. Two months in, analyse what you have been doing. This is where the protocol pays you back. The reference repo ships an analytics script in both languages that reads the audit chain (over HTTP or directly from your SQLite file) and groups overrides:
# TypeScript reference, against the SqliteStore from step 1:
$ npm --prefix reference/core-plus-review run analyze -- --db ./chap.db wsp_pr_reviews
# Python reference, same idea:
$ python3 reference/python/analyze_overrides.py --db ./chap.db wsp_pr_reviews
Override Learning Report
========================
Total overrides: 47
By tag:
false-positive ████████████████ 31 (66%)
framework-pattern-misread ███████████ 22 (47%)
cosmetic-pref ████ 8 (17%)
Top file paths:
src/handlers/ 18 overrides
src/components/ 9 overrides
Your next prompt revision for Cursor is no longer a guess. It cites the pattern by name.
The override envelope, in detail
The override envelope is the single most important shape in CHAP. Every field has a job:
The two fields most people miss on first read are intent_preserved and tags.
intent_preserved distinguishes a refining override (the human agreed with the agent's decision but rewrote how it was expressed) from a substituting override (the human reached a different decision). These are two different failure modes and they want different fixes. A high refining rate around one policy clause means the agent's retrieval is off; a high substituting rate on the same clause means the policy itself is ambiguous, or the agent's task context is wrong.
tags is the controlled vocabulary your team agrees on. Keep it small. Whatever you put there is the dimension you will aggregate on three months from now, when you are answering questions like which prompts need work? or which paths is the bot getting consistently wrong?
TypeScript / Node:
npm install @brightbeamai/chap-coordinator
Python:
pip install chap-coordinator
Either path gets you Core plus the review/1.0 profile and a runnable reference. The TypeScript reference is in reference/; the Python reference is in reference/python/. The TypeScript library lives at packages/coordinator/; the Python library at packages/coordinator-py/.
Five-minute hands-on walkthrough: examples/00-five-minute-start.md.
CHAP 0.2 is a public draft. Concretely, this repo contains:
- The specification. Core (seven methods, one envelope, one wire format) plus eleven optional profiles. Combined into a single document at
SPECIFICATION.md, or read individually fromcore/SPEC.mdandprofiles/. - Two reference implementations. Both cover Core plus every profile, 39 method handlers in total. The TypeScript reference is at
packages/coordinator/, with HTTP servers atreference/core/andreference/core-plus-review/and a runnable playground with two browser sessions and a local LLM atreference/playground/. The Python reference is atpackages/coordinator-py/with an HTTP server atreference/python/. Both pass the conformance harness on the same JSON-RPC 2.0 wire. - A conformance harness. 23 test vectors, signing/canonicalisation/chain checks, in-toto attestation output. Two conformance levels are claimable today (Minimal, Recommended); Full waits on broader interop testing across the two implementations.
- MCP server transport. A CHAP Coordinator can present itself as an MCP server, exposing every CHAP method as a tool. Point Claude Desktop, Cursor, Claude Code, or any MCP client at it and drive a CHAP workspace from natural language. TypeScript adapter at
packages/coordinator-mcp/, Python adapter atchap_coordinator.transports.mcp_server, runnable reference servers atreference/mcp-server-ts/andreference/mcp-server-py/. Five-minute walkthrough atexamples/drive-chap-from-claude-desktop.md. - A2A server transport. A CHAP Coordinator can also present itself as an A2A agent, advertising every CHAP method as a discrete skill on its Agent Card. Any A2A-aware orchestrator (Azure AI Foundry, Amazon Bedrock AgentCore, Google ADK, custom multi-agent systems) can register the coordinator by URL and delegate work to it. TypeScript adapter at
packages/coordinator-a2a/, Python adapter atchap_coordinator.transports.a2a_server, reference servers atreference/a2a-server-ts/andreference/a2a-server-py/. Walkthrough atexamples/drive-chap-from-an-a2a-orchestrator.md. - Inward wrap helpers. Small library utilities that turn an external MCP tool call or A2A exchange into a CHAP
task.create+task.completepair, with hashes of the input/output canonicalisations recorded as citations on the resulting artefact. The library counterpart to the citation patterns inintegrations/CHAP-with-{MCP,A2A}.md. Available aswrapMcpToolCall/wrapA2aMessageExchangefrom@brightbeamai/chap-coordinator, and aswrap_mcp_tool_call/wrap_a2a_message_exchangefromchap_coordinator.transports.wrap. - Framework bridges. Thin Python adapters that connect a real agent framework's human-in-the-loop mechanism to CHAP's
review/decidemethods, so an approval, edit, or denial in the framework becomes adecide.approve/decide.override/decide.rejecton the audit chain. Five today, each with its own examples and tests, each framework an optional dependency:chap-langgraph(LangGraph),chap-pydantic-ai(Pydantic AI),chap-ag2(AG2 / AutoGen),chap-llama-index(LlamaIndex Workflows), andchap-google-adk(Google ADK). - Twelve worked scenarios.
IN_PRACTICE.mdwalks through real cases from a solo developer with Cursor up to GMP-regulated fill-finish manufacturing. Runnable implementations live inscenarios/, one folder per story (three implemented so far), open to community contributions.
Breaking changes follow Semantic Versioning. Profile surfaces will move faster than Core. Production deployments needing strict stability should wait for 1.0. The longer status statement and the contribution path are in ABOUT.md.
What you get when you adopt this
-
An audit chain that survives key rotation, log expiry, and people leaving. Every envelope links to the previous by content hash. One
audit.readcall returns the whole thing. -
Structured supervision data as a side effect of normal work. No separate annotation pipeline. The overrides you are already making become a dataset you would otherwise have to commission.
-
Signed, non-repudiable approvals when you need them. Opt into
security-signed/1.0for OIDC-bound signatures with asignature_meaningyou define. Opt intoaudit-scitt/1.0for an external transparency-log anchor, verifiable without trusting your servers. -
Composability with what you have already built. CHAP does not replace MCP or A2A. It sits next to them: your agent uses MCP for tools, A2A for other agents, and CHAP to record the shared work with humans.
-
IN_PRACTICE.md. Twelve real-world scenarios from solo dev to GMP-regulated manufacturing. The most useful next read. -
ABOUT.md. What is in this repo, how CHAP relates to MCP and A2A, the standards it reuses, and how to contribute. -
core/SPEC.md. The seven Core methods. The whole protocol surface fits on one screen. -
Technical report on arXiv. The full paper. Architecture, design rationale, profile semantics, threat model, and a worked appendix with the twelve scenarios as JSON traces. For readers who want the protocol grounded in its design choices.
If you reference CHAP in academic or technical work, please cite the technical report:
@techreport{chap2026,
author = {Shahid, Arsalan and Suttie, Gordon and Black, Philip},
title = {Collaborative Human-Agent Protocol (CHAP): An open protocol for auditable, structured multi-human and multi-agent collaboration},
institution = {Brightbeam AI},
year = {2026},
type = {Technical Report},
number = {arXiv:2606.09751},
url = {https://arxiv.org/abs/2606.09751}
}
CC-BY 4.0 (specification) · Apache 2.0 (code) · Royalty-free, any language, any deployment.
