ESC
开源 1 分钟阅读

forward-implementation-first:阻止编码代理陷入自造簿记,先交付再验证

开源技能 forward-implementation-first 发布,专为 Claude Code、Codex 等编码代理设计,防止代理在长流水线中陷入自造的哈希、锁文件、回执等簿记工作。它要求代理每次操作前先分类为语义实现、聚焦验证或行政簿记,只执行前两类,同时保留产品级校验、输入版本标识等关键例外规则,采用 MIT 许可证。

来源:GitHub

先实现后验证(Forward implementation first)

一个阻止编码代理陷入为自身“文书工作”服务的 Agent Skill。

长时间运行的代理流水线会不断累积簿记工作:内容哈希、锁文件、用于“证明某个阶段已运行”的回执、认证标记、仪表盘行、进度元数据。这些都不是产品本身,但模型很容易把它们误当成产品。一旦发生这种情况,代理就不再交付成果,而是开始“打理”这些记录,而你却以全额成本养着一个没有产出任何你所要求东西的代理。

这个技能让代理在每次行动前做一次分类,并列出一份它绝不允许做的事情的简短清单。它大约只有 150 行 Markdown,与模型无关、与工具无关、与领域无关。

失败模式

你有一个按阶段排序的流水线。阶段 40 产出一个文件,阶段 41 消费它。流水线编排器还会写一条小的 JSON 记录,声明阶段 40 已完成,并附上其输入的哈希。

然后你修改了一个生产者,哈希不再匹配。没有这个技能时,代理会这样做:

  • 它注意到不匹配,并将其视为正确性失败,因为不匹配看起来就像一个错误。
  • 它将阶段 12 到 40 全部标记为失效,因为它无法证明哪些阶段受到了影响,而失效更多阶段“感觉更安全”。
  • 它拒绝手动运行阶段 41,因为流水线“无法为手动运行签发回执”。
  • 它在接下来的几个小时里为那些输出从未改变、从未出错的阶段重新生成标记。
  • 它以“修复了多少回执”来报告进度,这看起来像是在干活。

这一连串行为中,没有哪一步单独看是愚蠢的。每一步都是可以辩解的局部决策,但合在一起它们耗费了好几天,而最终输出与你原本已有的输出完全相同。病态在于:管理元数据被用作了正确性的替代指标,而这个替代指标既容易被检查,又完全不能说明任何问题。

失败模式的另一半更糟:代理告诉你它无法继续。于是你只好亲自去运行那个阶段,或者再开一个代理来做,而第一个代理就坐在那里守着它的哈希。

这个技能做什么

在每次行动前,代理将其归类为以下三种之一:

  1. **语义实现。**构建或连接生产者、消费者、适配器、运行时路径、schema、fixture 或最终输出。
  2. **聚焦验证。**通过行为、schema、计数、有序样本、守恒性、一致性、无截断以及实测时间和内存,测试发生变更的依赖锥。
  3. **行政簿记。**生成或修复哈希、锁、回执、仪表盘、认证标记、进度元数据或仅有“存在性”的记录。

执行第 1、2 类。跳过第 3 类,除非用户明确要求,或该工件本身就是产品的一部分。当第 3 类在不保护正确性的情况下阻塞了路径时,删除这个依赖。

这就是全部核心思想。SKILL.md 的其余部分让代理很难找借口绕过它,因为一个想做簿记的模型总会找到理由。

它不放松的部分

这是让这个技能可以安全安装的关键,也是大多数“只要再快一点”式提示词搞错的地方。簿记可以廉价地跳过,但证据不行。该技能明确保留:

  • 属于产品本身的完整性:用户会校验的校验和、格式所要求的签名、作为输出契约一部分的哈希。这些是功能,不是文书;
  • 输入与修订版本的身份标识——当它决定你正在操作哪个版本时。搞错这个意味着在错误的目标上做了正确的工作;
  • 断言结果的测试、基准测试、复现和端到端运行;
  • 覆盖与结果的区别。跑过某条路径并不等于检查了该路径产生了正确答案。

一条包含命令、输入、结果以及所校验的预期的执行记录才是真正的证据。它的缺失会阻塞它所支持的那个论断,但它不会追溯性地使二十步之前一个无关阶段失效。这个区别正是“严谨”与“迷信”的全部差别,也正是这个技能划下的那条线。

前向游标规则

流水线阶段只有在有真实理由时才可以重放或回滚:

  • 它的输入语义发生了变化;
  • 它的目标或固定的修订版本发生了变化;
  • 它的输出格式错误、被截断、不守恒、不一致,或与其消费者不兼容;
  • 一次实际运行的观测结果推翻了之前的静态结论;
  • 被修改的生产者所声明的依赖锥要求如此。

缺失或过时的元数据不在此清单上。当一个阶段仅仅被一个标记阻塞时,代理应手动运行它、验证输出、发布结果、从游标处继续,然后移除这个纯行政性的关卡,使同样的阻塞不再发生。只重放受影响的最小依赖锥,而不是整个历史。

并行工作:不变量,而非调度器

该技能也涉及并行,因为这两个问题常常同时出现。一个忙于簿记的代理通常也会把所有事情串行化。

早期反馈指出了第一版搞错的一条边界:技能绝不能充当编排器。调度、资源竞争和 worker 拓扑属于你的运行时,几行 Markdown 若想宣称这些权力,就会与任何真正的调度器冲突。因此这一部分被拆成了两半。

以下不变量作为一等规则保留,因为它们在任何调度器下都成立:

  • 恰好只有一个写入者负责发布、游标移动和结论。并行的 worker 只做准备和检查,永远不会成为第二事实来源。
  • 在消费 worker 的输出之前先验证它。报告只是陈述意图,不是结果。
  • 前向推进不等所有 worker。当推进到需要某个输出的依赖时再去消费它。
  • 绝不为了填补空闲槽位而捏造无意义的工作。

调度策略本身、worker 数量、波次大小、什么算重负载进程——这些完全不在这个技能里。你的运行时已经拥有这些权力,一个自带调度策略的技能会与它打架。如果你的环境里没有任何东西负责调度,examples/execution-profile.md 是一个可以复制和修改的起点配置。该技能绝不会自行加载它。

这些不变量比提速更重要。廉价的并行 worker 之所以有用,恰恰是因为它们不被信任;一旦它们的输出未经检查就被合并,价值就会消失。

安装

这个技能是一个带 YAML frontmatter 的单一 Markdown 文件,遵循 Agent Skills 约定。把它复制到你的代理查找技能的位置:

git clone https://github.com/Vuk97/forward-implementation-first
cd forward-implementation-first
./install.sh

install.sh 会把 SKILL.md 复制到它找到的每一个代理技能目录:

代理路径
Claude Code~/.claude/skills/forward-implementation-first/
Codex~/.codex/skills/forward-implementation-first/
共享约定~/.agents/skills/forward-implementation-first/

若要按项目安装,请将该目录复制到仓库中的 .claude/skills/ 或 .agents/skills/。之后需重启代理,运行中的会话不会重新加载技能。

技能只是一个建议,由模型决定是否加载。如果你的代理支持常驻规则或 hooks,也把这条决策规则放进去,因为这个特定的失败模式正是模型会“自信地”走进去的坑。

何时使用

如果你的环境符合以下任一情况,就安装它:

  • 带有有序阶段和持久化游标的流水线;
  • 后续阶段依赖的生成工件;
  • 由编排器而非工作本身写入的任何清单、锁文件或回执;
  • 运行时间长到你无法盯住每一步;
  • 多个代理或会话操作同一个仓库。

常见场景:分阶段的数据处理和 ETL 运行、大型代码迁移、构建和发布流水线、针对大量输入的文档生成、批量分析任务,以及任何代理需要连续数天推进的路线图。

单次任务、短交互会话,以及审计轨迹本身就是交付物的任何工作流,则可以跳过它。如果有人要读你的回执,那它们就不是簿记。

来源

它最初是一段粘贴在长时运行分阶段流水线每个会话开头的提示词。在那个流水线里,代理曾因元数据漂移反复将数十个已完成的阶段标记为失效,然后又拒绝手动运行阶段。每次都粘贴它,问题就解决了;忘记粘贴一次,就要损失好几天。

把它变成技能,让这个行为成为默认,而不是靠记忆。

许可证

MIT。详见 LICENSE。