关于 proof
proof 是面向人类与 Agent 的协作式 Markdown 编辑器技能,支持通过 Web API 共享编辑,也可驱动 macOS Proof 应用。它提供评论、建议修改及带身份标记的变更流程。
主要功能
- 01通过 Web API 创建和编辑共享文档
- 02连接 macOS Proof 应用本地桥接
- 03评论、回复及处理评论
- 04提交、接受或拒绝修改建议
- 05文档操作附带 Agent 身份
适用场景
- 01邀请他人审阅共享 Markdown 文档
- 02收集结构化反馈并同步回本地文件
- 03在协作编辑中跟踪建议与评论
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ everyinc/ compound-engineering-plugin --skill proof安装后在 Claude Code 中输入/proof确认已加载。
附带文件references/hitl-review.md
详细介绍
Proof - 协作式 Markdown 编辑器
Proof 是一款供人类和 Agent 使用的协作文档编辑器。它支持两种模式:
- Web API - 通过 HTTP 创建和编辑共享文档(无需安装)
- 本地桥接 - 通过 localhost:9847 操控 macOS Proof 应用
身份与署名
对 Proof 文档的每次写入都必须注明身份。以下两个字段承载 Agent 的身份信息:
- 机器 ID(每个操作中的
by、X-Agent-Id标头):ai:compound-engineering— 稳定、采用小写连字符格式,且可由机器解析。显示在标记、事件和 API 响应中。 - 显示名称(
POST /presence中的name):Compound Engineering— 便于人类阅读,显示在 Proof 的在线状态标签和评论作者徽章中。
通过携带 X-Agent-Id 标头向在线状态接口发送请求,为每个文档会话设置一次显示名称。Proof 会在该会话中将名称绑定到对应的 Agent ID。这些值是使用此技能的所有调用方的默认值;运行 HITL 审核(references/hitl-review.md)的调用方可传入不同的 identity 对,以便由不同的子 Agent 负责文档。请勿使用 ai:compound 或其他临时变体,除非调用方明确覆盖,否则身份应保持统一。
Human-in-the-Loop 审核模式
当调用方(例如 ce-brainstorm、ce-plan)需要上传本地 Markdown 文档、在 Proof 中收集结构化的人类反馈,并将最终文档同步回磁盘时,请加载 references/hitl-review.md,查看完整的流程规范:调用约定、标记分类(修改 / 问题 / 异议 / 模糊)、幂等摄取流程、基于异常的终止报告,以及最终同步时的原子写入。
Web API(共享文档的首选方式)
创建共享文档
无需身份验证。返回包含访问令牌的可分享 URL。
curl -X POST https://www.proofeditor.ai/share/markdown \
-H "Content-Type: application/json" \
-d '{"title":"My Doc","markdown":"# Hello\n\nContent here."}'
响应格式:
{
"slug": "abc123",
"tokenUrl": "https://www.proofeditor.ai/d/abc123?token=xxx",
"accessToken": "xxx",
"ownerSecret": "yyy",
"_links": {
"state": "https://www.proofeditor.ai/api/agent/abc123/state",
"ops": "https://www.proofeditor.ai/api/agent/abc123/ops"
}
}
使用 tokenUrl 作为可分享链接。_links 中提供了准确的 API 路径。
读取共享文档
curl -s "https://www.proofeditor.ai/api/agent/{slug}/state" \
-H "x-share-token: <token>"
编辑共享文档
所有操作均发送到 POST https://www.proofeditor.ai/api/agent/{slug}/ops
注意: 使用 /api/agent/{slug}/ops 路径(来自创建响应中的 _links),而不是 /api/documents/{slug}/ops。
受保护文档的身份验证:
- 请求头:
x-share-token: <token>或Authorization: Bearer <token> - Token 来自 URL 参数:
?token=xxx,或来自创建响应中的accessToken - 请求头:
X-Agent-Id: ai:compound-engineering(presence 必需;在 ops 请求中也包含此项,以确保归属信息一致)
线路格式提醒。 /api/agent/{slug}/ops 使用顶层 type 字段;/api/agent/{slug}/edit/v2 使用 operations 数组,其中每个条目都有 op。不要混用——向 /ops 发送 op 会返回 422。
每次修改都需要 baseToken。 在每次写入之前,立即从 /state.mutationBase.token(或 /snapshot.mutationBase.token)读取,并将其包含在请求正文中。遇到 BASE_TOKEN_REQUIRED 或 STALE_BASE 时,重新读取并重试一次。请参阅 references/hitl-review.md 中的 baseToken 操作方法。
Idempotency-Key 请求头 建议用于每次修改,以便安全地自动重试;当 /state.contract.idempotencyRequired 为 true 时则为必需。
对文本发表评论:
{"type": "comment.add", "quote": "text to comment on", "by": "ai:compound-engineering", "text": "Your comment here", "baseToken": "<token>"}
回复评论:
{"type": "comment.reply", "markId": "<id>", "by": "ai:compound-engineering", "text": "Reply text", "baseToken": "<token>"}
解决 / 取消解决评论:
{"type": "comment.resolve", "markId": "<id>", "by": "ai:compound-engineering", "baseToken": "<token>"}
{"type": "comment.unresolve", "markId": "<id>", "by": "ai:compound-engineering", "baseToken": "<token>"}
提出替换建议(待处理——用户必须接受或拒绝):
{"type": "suggestion.add", "kind": "replace", "quote": "original text", "by": "ai:compound-engineering", "content": "replacement text", "baseToken": "<token>"}
提出并立即应用(有记录但已提交——用户可以拒绝以撤销):
{"type": "suggestion.add", "kind": "replace", "quote": "original text", "by": "ai:compound-engineering", "content": "replacement text", "status": "accepted", "baseToken": "<token>"}
status: "accepted" 会在一次调用中创建建议标记并提交更改。该标记会作为审计记录保留,其中包含每次编辑的归属信息,并提供拒绝以撤销的选项。适用于 kind: "insert" | "delete" | "replace"。
接受或拒绝现有建议:
{"type": "suggestion.accept", "markId": "<id>", "by": "ai:compound-engineering", "baseToken": "<token>"}
{"type": "suggestion.reject", "markId": "<id>", "by": "ai:compound-engineering", "baseToken": "<token>"}
不支持 suggestion.resolve——请改用接受或拒绝。
批量重写(替换整个文档):
{"type": "rewrite.apply", "content": "full new markdown", "by": "ai:compound-engineering", "baseToken": "<token>"}
通过 /edit/v2 进行块级编辑(独立端点,格式独立):
curl -X POST "https://www.proofeditor.ai/api/agent/{slug}/edit/v2" \
-H "Content-Type: application/json" \
-H "x-share-token: <token>" \
-H "X-Agent-Id: ai:compound-engineering" \
-H "Idempotency-Key: <uuid>" \
-d '{
"by": "ai:compound-engineering",
"baseToken": "mt1:<token>",
"operations": [
{"op": "replace_block", "ref": "b3", "block": {"markdown": "Updated paragraph."}},
{"op": "insert_after", "ref": "b3", "block": {"markdown": "## New section"}}
]
}'
operations 中支持的 op 类型:replace_block、insert_before、insert_after、delete_block、replace_range(使用 fromRef + toRef)、find_replace_in_block(接受 occurrence: "first" | "all")。读取 /snapshot 以获取稳定的块 ref ID 和 mutationBase.token。
客户端已连接时可以编辑。 /edit/v2、suggestion.add(包括 status: "accepted")以及所有评论操作都可以在协作进行期间使用。只有 rewrite.apply 会因 LIVE_CLIENTS_PRESENT 而被阻止——它会覆盖正在进行的 Yjs 编辑。
循环中断时。 如果修改在重新读取并重试一次后仍持续失败,或多次读取到的状态看起来不一致,请调用 POST https://www.proofeditor.ai/api/bridge/report_bug,并提供失败请求 ID、slug 和原始响应。服务器会补充信息并提交问题。
已知限制(Web API)
- Bridge 风格的端点(
/d/{slug}/bridge/*)需要客户端版本请求头(x-proof-client-version、x-proof-client-build、x-proof-client-protocol);如果缺少这些请求头,则会返回 426 CLIENT_UPGRADE_REQUIRED。请改用/api/agent/{slug}/ops。
本地 Bridge(macOS 应用)
需要运行 Proof.app。Bridge 位于 http://localhost:9847。
必需的请求头:
X-Agent-Id: claude(用于 presence 的身份标识)Content-Type: application/jsonX-Window-Id: <uuid>(同时打开多个文档时需要)
主要端点
| 方法 | 端点 | 用途 |
|---|---|---|
| GET | /windows | 列出已打开的文档 |
| GET | /state | 读取 Markdown、光标位置和字数 |
| GET | /marks | 列出所有建议和评论 |
| POST | /marks/suggest-replace | {"quote":"old","by":"ai:compound-engineering","content":"new"} |
| POST | /marks/suggest-insert | {"quote":"after this","by":"ai:compound-engineering","content":"insert"} |
| POST | /marks/suggest-delete | {"quote":"delete this","by":"ai:compound-engineering"} |
| POST | /marks/comment | {"quote":"text","by":"ai:compound-engineering","text":"comment"} |
| POST | /marks/reply | {"markId":"<id>","by":"ai:compound-engineering","text":"reply"} |
| POST | /marks/resolve | {"markId":"<id>","by":"ai:compound-engineering"} |
| POST | /marks/accept | {"markId":"<id>"} |
| POST | /marks/reject | {"markId":"<id>"} |
| POST | /rewrite | {"content":"full markdown","by":"ai:compound-engineering"} |
| POST | /presence | {"status":"reading","summary":"..."} |
| GET | /events/pending | 轮询用户操作 |
在线状态
thinking、reading、idle、acting、waiting、completed
工作流:审阅共享文档
收到 Proof URL(如 https://www.proofeditor.ai/d/abc123?token=xxx)时:
- 从 URL 中提取 slug(
abc123)和 token - 通过 API 读取文档状态
- 使用 ops 端点添加评论或提出编辑建议
- 作者会实时看到更改
# Read
curl -s "https://www.proofeditor.ai/api/agent/abc123/state" \
-H "x-share-token: xxx"
# Get baseToken for the next mutation
BASE=$(curl -s "https://www.proofeditor.ai/api/agent/abc123/state" \
-H "x-share-token: xxx" | jq -r '.mutationBase.token')
# Comment
curl -X POST "https://www.proofeditor.ai/api/agent/abc123/ops" \
-H "Content-Type: application/json" \
-H "x-share-token: xxx" \
-H "X-Agent-Id: ai:compound-engineering" \
-d "$(jq -n --arg base "$BASE" '{type:"comment.add",quote:"text",by:"ai:compound-engineering",text:"comment",baseToken:$base}')"
# Suggest edit (tracked, pending)
curl -X POST "https://www.proofeditor.ai/api/agent/abc123/ops" \
-H "Content-Type: application/json" \
-H "x-share-token: xxx" \
-H "X-Agent-Id: ai:compound-engineering" \
-d "$(jq -n --arg base "$BASE" '{type:"suggestion.add",kind:"replace",quote:"old",by:"ai:compound-engineering",content:"new",baseToken:$base}')"
# Suggest and immediately apply (tracked, committed)
curl -X POST "https://www.proofeditor.ai/api/agent/abc123/ops" \
-H "Content-Type: application/json" \
-H "x-share-token: xxx" \
-H "X-Agent-Id: ai:compound-engineering" \
-d "$(jq -n --arg base "$BASE" '{type:"suggestion.add",kind:"replace",quote:"old",by:"ai:compound-engineering",content:"new",status:"accepted",baseToken:$base}')"
工作流:创建并分享新文档
# 1. Create
RESPONSE=$(curl -s -X POST https://www.proofeditor.ai/share/markdown \
-H "Content-Type: application/json" \
-d '{"title":"My Doc","markdown":"# Title\n\nContent here."}')
# 2. Extract URL and token
URL=$(echo "$RESPONSE" | jq -r '.tokenUrl')
SLUG=$(echo "$RESPONSE" | jq -r '.slug')
TOKEN=$(echo "$RESPONSE" | jq -r '.accessToken')
# 3. Bind display name via presence
curl -s -X POST "https://www.proofeditor.ai/api/agent/$SLUG/presence" \
-H "Content-Type: application/json" \
-H "x-share-token: $TOKEN" \
-H "X-Agent-Id: ai:compound-engineering" \
-d '{"name":"Compound Engineering","status":"reading","summary":"Uploaded doc"}'
# 4. Share the URL
echo "$URL"
# 5. Make edits using the ops endpoint (baseToken required)
BASE=$(curl -s "https://www.proofeditor.ai/api/agent/$SLUG/state" \
-H "x-share-token: $TOKEN" | jq -r '.mutationBase.token')
curl -X POST "https://www.proofeditor.ai/api/agent/$SLUG/ops" \
-H "Content-Type: application/json" \
-H "x-share-token: $TOKEN" \
-H "X-Agent-Id: ai:compound-engineering" \
-d "$(jq -n --arg base "$BASE" '{type:"comment.add",quote:"Content here",by:"ai:compound-engineering",text:"Added a note",baseToken:$base}')"
工作流:将 Proof 文档拉取到本地
将当前 Proof 文档状态同步到本地 Markdown 文件。适用于:
- 本地文件创建的文档在 HITL 审阅结束时同步(
references/hitl-review.md第 5 阶段) - 将 Proof 文档临时快照保存到磁盘(关闭标签页、归档或交接前)
- 根据实时 Proof 版本刷新本地工作副本
SLUG=<slug>
TOKEN=<accessToken>
LOCAL=<absolute-path>
# One read to a temp file — avoids passing markdown through $(...), which would strip trailing newlines.
STATE_TMP=$(mktemp)
curl -s "https://www.proofeditor.ai/api/agent/$SLUG/state" \
-H "x-share-token: $TOKEN" > "$STATE_TMP"
REVISION=$(jq -r '.revision' "$STATE_TMP")
# Atomic write: stream .markdown bytes directly to a temp sibling, then rename.
TMP="${LOCAL}.proof-sync.$$"
jq -jr '.markdown' "$STATE_TMP" > "$TMP" && mv "$TMP" "$LOCAL"
rm "$STATE_TMP"
jq -jr(-j 不添加末尾换行符,-r 输出原始字符串)会将 Markdown 字节直接写入临时文件,而不经过 shell 变量,因此末尾换行符会完整保留。同一文件系统内的 mv 操作具有原子性——即使写入时发生崩溃,也会保留原文件,而不会留下只写入一半的文件。
如果拉取并非用户直接要求,请先确认再写入。 如果某个工作流因其他操作而顺带执行拉取(例如 HITL 审阅完成),请用简短提示说明即将进行的写入,例如“将已审阅的文档同步到 <localPath>?”静默覆盖会令人意外——用户可能忘记当前会话中存在本地文件,也可能希望 Proof 在明确要求拉取之前始终作为权威版本。
安全
- 编辑前,以
/state的内容为准 - 协作期间使用
edit/v2(直接修改区块)或suggestion.add(跟踪更改);仅在没有客户端连接时使用rewrite.apply,因为只要有人连接,该操作就会被LIVE_CLIENTS_PRESENT阻止 - 单次替换不要跨越多个表格单元格
- 每个 op 都必须包含
by: "ai:compound-engineering",并在请求头中包含X-Agent-Id: ai:compound-engineering,以确保归属信息一致 - 每次修改前都读取最新的
baseToken;如果遇到STALE_BASE,重新读取并重试一次