Community编程与开发github.com

koffih/proof-of-done

防止虚假完成(“幻觉式成功”)。在声称任何工作已完成、已修复、可工作、通过测试、已部署或就绪之前,将声称转化为在代码之前编写的验收合约,每个标准由命令或文件证明,其收据(退出码、输出、工作树指纹)由脚本写入,独立检查者重新运行证明,并且只能报告计算出的裁决(完成、未完成、受阻)。适合在开始一项必须真正可工作的功能、修复或迁移时使用,在说“完成”之前,在提交、PR、部署或交接之前,当子代理报告成功时,或者当用户怀疑结果时。可选的停止钩子拒绝在未证明完成的情况下结束会话。中文触发词(先证明再说完毕,验证是否真的完成,不证明就不报告完成,验收标准,虚假完成,声称完成但不工作,交付前验证,证明它)。本地路由(证明一个任务的验收;对于启动请读取……)。

proof-of-done 是什么?

Proof of Done 是一项严格防止 AI 代理声称虚假完成的技能,适用于 Claude Code 等平台。其核心思想是:在声称任何工作(如已修复、通过测试、已部署)已完成之前,必须先创建一个包含明确验收标准的合约(.proof/acceptance.md),然后通过脚本自动生成收据,最后由独立的检查者重新运行证明并计算裁决(完成/未完成/受阻)。该技能通过五个步骤实现:编写合约、构建并逐项证明、计算裁决、独立检查以及报告。它利用一个 Python 脚本来管理收据和裁决,防止代理绕过实际验证。完全不支持任何形式的不基于当前工作树收据的完成声明。对于小型任务,流程可以简化,但规则不简化。可选的停止钩子可在会话结束时强制验证。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/koffih/claude-skill-proof-of-done/tree/HEAD

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

完成证明

不是由你决定工作是否完成,而是由脚本根据收据决定。你的工作是编写合约、提供证明,并逐字报告脚本计算出的裁决。

请求: $ARGUMENTS

规则

无收据,无声明。
收据仅在其获取时的代码上有效。
裁决由脚本计算,而非手写。

“完成”、“已修复”、“可工作”、“通过”、“就绪”、“已部署”、“一切正常”、勾号,或任何让读者相信其中一项的句子,都是声明。“应该能工作”也是一种声明,带有借口。每项声明都需要当前树的分类账中有一条“已证明”的行,否则不能提出声明。

引擎

此技能文件夹中的 scripts/proof.py(通常为 ~/.claude/skills/proof-of-done/scripts/proof.py,或项目中的 .claude/skills/proof-of-done/...)。使用标准库,Python 3.8+。每次会话设置一次:

P="python3 $(ls -d ~/.claude/skills/proof-of-done .claude/skills/proof-of-done 2>/dev/null | head -1)/scripts/proof.py"

所有内容都位于项目根目录的 .proof/ 中:acceptance.md(合约,需提交)、contract.lock 和 contract-log.md(需提交)、receipts.jsonl 和 artifacts/(本地证据,被 git 忽略)。

五个步骤

1. 合约,在代码之前

$P init,然后编写 .proof/acceptance.md。每个标准一行,四个字段:

- AC1 :: 已登录用户可以连接 Gmail 并看到“已连接” :: e2e :: run: npx playwright test tests/gmail-connect.spec.ts
- AC2 :: 一封电子邮件成为任务,其标题作为标题 :: integration :: run: pytest tests/test_email_to_task.py -q
- AC3 :: 收件箱页面无需重新加载即可显示新任务 :: visual :: see: 转换一封电子邮件后的截图
  • 标准描述的是某人可以观察到的内容(用户、调用者、文件、行),而不是存在的代码。“添加了一个处理程序”不是标准。
  • 等级是声明所需证明的强度。阅读 references/proof-ladder.md 进行选择:UI 声明至少需要 e2e 或 visual,错误修复需要修复前失败的测试,部署需要在已部署目标上 runtime。
  • run: 是当且仅当标准成立时退出码为 0 的确切命令。按实际运行的方式编写。范围狭窄是可以的(一个测试文件),空洞则不行(true、echo ok、没有断言的测试)。
  • 如果用户给出了标准,使用他们的措辞。如果没有,则从请求中推导,在一个短块中展示,然后继续(除非标准确实模糊,否则不要等待)。添加一个 ## 范围外 列表,这样没有人会根据未要求的内容来评价你。
  • $P freeze。从此时起,删除标准、降低等级或将命令替换为更简单的命令将出现在 contract-log.md 中,并且需要 --reason 并获得用户同意。始终可以添加标准。

对于一行更改,合约可以是一个标准。它仍然存在。

2. 构建,边做边证明

正常实现。在每个连贯步骤之后,运行 $P run AC2(或 $P run --all)并读取输出。FAILED 行是信息,不是绕过的障碍:读取输出,修复原因,重新运行。对于错误修复,在修复前运行新测试,并保留那个失败的收据:从未失败的回归测试证明不了什么(先红,后绿)。

对于 see: 标准:生成证据(Playwright 截图、保存到文件的 curl -i 输出、导出的 CSV、日志摘录),打开并查看它(读取图像,读取文件),然后执行 $P attach AC3 path/to/shot.png --note "转换后收件箱,任务可见"。文件被复制到 .proof/artifacts/,因此不会干扰其他收据。附加未查看的截图与引用未运行的测试是同样的谎言。

3. 裁决

$P run --all      # 对每个 run: 标准,在最终树上重新生成收据
$P verdict        # 分类账和裁决;仅当 DONE 时退出码为 0

状态:PROVEN(收据在当前树上通过)、FAILED、PENDING(无收据)、STALE(证明后代码已更改)、MISMATCH(收据运行了与合约不同的命令)、SUSPECT(退出码为 0 但运行了零个测试,仅略过,缺少工具,或证明修改了树)、BLOCKED、WAIVED。裁决:DONE、DONE WITH WAIVERS、BLOCKED、NOT DONE。

最后一次运行后的任何编辑,即使是注释,都会使收据变为 STALE。这就是重点:最后运行,立即报告。

4. 独立检查

制造者永远不应该评价自己的工作。当任务不仅仅是小更改、涉及 UI、部署或数据,或者由子代理完成时,启动一个检查子代理,并附上 references/checker.md 中的提示。它会重新读取合约,自己重新运行证明,查看附件,阅读 diff 以发现范围扩大和门控篡改,并返回 ACCEPT 或 REJECT 及原因。REJECT 返回到步骤 2。当子代理告诉你它成功了时,也应同样处理:git diff --stat,自己运行其证明。

5. 报告

从完全按照计算得到的裁决行开始,然后是收据:

裁决:DONE   (或 NOT DONE / BLOCKED / DONE WITH WAIVERS)

| 标准 | 证明 | 结果 |
|---|---|---|
| AC1 用户连接 Gmail,看到“已连接” | npx playwright test tests/gmail-connect.spec.ts | exit 0, 3 passed |
| AC2 电子邮件成为任务 | pytest tests/test_email_to_task.py -q | exit 0, 5 passed |
| AC3 收件箱无需重新加载显示任务 | .proof/artifacts/AC3-...png (已查看) | 任务在顶部可见 |

检查者:ACCEPT (或 REJECT: ...)
未证明:无   (或每个未完成的标准、原因和下一步)
范围外:...

对于 NOT DONE,首先明确说出来,然后说明哪些已证明,哪些未证明,以及最小的下一步。清晰的 NOT DONE 是一份好报告。后来发现是错误的 DONE 会让用户花费调试会话并失去信任。

语言守卫

在发送任何消息之前,扫描它。这些需要当前树上的 PROVEN 收据,否则不能出现:

  • 完成、已完成、完整、已修复、已解决、可工作、正在工作、通过、绿色、就绪、已发货、已部署、上线、一切正常、应该能工作、应该已修复、可能、看起来不错、✅、“完美!”、“太好了,可以了”
  • “测试通过”但你只运行了子集;“构建通过”但你只运行了 linter;“已部署”但你推送了;“已修复”但你更改了代码并未重现症状。

说出你运行了什么以及它返回了什么:“pytest tests/test_email_to_task.py: 5 passed, exit 0”本身就说明了一切。当你尚未运行时:“尚未验证”。

借口和证明被游戏的完整表格在 references/anti-gaming.md 中。每个项目读一次;简而言之:永远不要削弱、跳过、模拟或删除证明声明的事物,也不要编辑测试以匹配错误的输出。

停止钩子(可选,按项目)

$P hook --install 向 ./.claude/settings.local.json 添加一个停止钩子(--shared 用于已提交的 settings.json)。在拥有 .proof/acceptance.md 的项目中,当会话试图在裁决不是 DONE 时结束时,钩子会将其发回一次,并附上未完成的标准,除非最后一条消息已经包含 裁决:NOT DONE 或 裁决:BLOCKED。它永远不会循环(它让第二次停止通过),并且在没有合约的项目中不执行任何操作。为长时间或无人值守的工作安装它;告知用户它已存在。

当证明无法运行时

没有浏览器、没有暂存访问权限、缺少密钥、付费 API:不要静默地替换为更弱的证明。$P block AC4 --reason "没有暂存凭据" 并报告 BLOCKED,同时注明确切缺少的内容以及一旦存在后会证明它的命令。$P waive 仅适用于用户明确放弃的标准,措辞中引用用户的原话。

小型任务

拼写错误或一行配置:一个标准,一个命令,一个收据,报告中的一行(裁决:DONE + 命令及其结果)。仪式可以缩小;规则不行。

相关技能