mcpField
B
build-dark-factory

build-dark-factory

github.com/coleam00Agent 工作流722228 次安装3 周前更新
代码仓库

关于 build-dark-factory

build-dark-factory 是一项在代码仓库中搭建无人值守软件交付流程的 Agent 技能,面向希望将现有 AI 编码工作流转为自动化工厂的团队。它要求以 PRD 为输入,逐步建设指导规则、验证、工作流和部署,并把触发器留到最后。

主要功能

  1. 01以 PRD 和现有流程为依据
  2. 02在仓库中构建工厂组件
  3. 03先建立指导层与验证机制
  4. 04区分工厂与验证框架
  5. 05所有组件验证后才启用触发器

适用场景

  1. 01将已有 AI 编码流程转为自动化交付
  2. 02为代码仓库设置无人值守构建与验证
  3. 03分阶段搭建部署和自动触发机制

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/coleam00/skills --skill build-dark-factory

安装后在 Claude Code 中输入/build-dark-factory确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
automation.md
deployment.md
guidance-layer.md
interview.md
setup.md
validation-harness.md
scripts/
_audit_runner.py
_test_audit_runner.py
_test_factory_doctor.py
_test_runner.py
factory_doctor.py
templates/
CLAUDE.md
FACTORY_RULES.md
FACTORY.md
MISSION.md
templates/harness/
appproc.py
ci.py
e2e.py
harness.config.json
README.md
templates/harness/holdout/
run.py
templates/harness/locks/
floor.json
templates/harness/mutations/
defects.json
run.py
templates/runner/
.gitattributes
.gitignore
templates/runner/.factory/
decisions.md
templates/runner/factory/
config.sh
cost.py
deploy.sh

详细介绍

构建暗色工厂

用户输入: $ARGUMENTS

请自行从这一行中判断 PRD 路径和仓库路径,不要输出未经核实的解析结果。 位置参数按空白字符拆分,因此输入一句话(“build a dark factory for my repo at C:\code\thing”)的人会把前两个单词当作两个路径——有三次独立测试运行显示 PRD: Build 和 Repo: a,对于之后悄悄自行纠正了解析结果的技能来说,这样的初次体验显然出了问题。

因此:读取这一行,找出看起来像 .md PRD 的内容和看起来像目录的内容,并在 Phase 0 前用一句话向用户确认两者。如果只给出一个路径,根据它的扩展名判断它是哪一种,并询问另一个路径。如果 PRD 路径不存在,说明情况并停止——这就是提前到达的 Phase 0a。

暗色工厂是一个仓库:工作从一端进入,交付的代码从另一端产出,中间没有人参与。工作以 issue 的形式到来。工作流负责规划、构建、验证并合并。部署则将其交付给真实用户。没有人审核差异。

最后这句话就是全部难点。其他一切都是管道工作。

将工厂构建到用户的仓库中。不要只交给他们一份设计文档。 以下每个阶段结束时,都必须有文件已提交,并且有可证明能正常工作的成果。

暗色工厂的五个组件

一页看懂整个系统。 五个组件、三个治理文件,以及独立性界限。打开 dark-factory-diagram.png 查看原图,先了解整体结构,再开始操作。


输出规范——写给用户的第一句话前,请先阅读

本文档很长,因为必须完整。但你要说的话不必如此。 一位使用者将体验描述为*“极其令人沮丧,难以理解,至少可以说让人不堪重负”*——而当时技能运行正常,只是在每一步都解释自己。应该写进文件的推理,出现在聊天窗口里就是噪音。

严格限制。以下不是风格偏好。

时机限制
一个问题与下一个问题之间什么都不要说。 直接提问。不要铺垫,也不要回顾上一个答案。
完成一个阶段时两行。 说明现在有什么,以及接下来要问什么。
解释概念时只有用户询问时才解释,而且先给简短版本。
报告你写入的文件时一行。 写明路径,以及由什么决定文件内容。
报告命令输出时不要粘贴输出。只说结论和数字。

绝不要这样做:

  • 在执行一个阶段之前宣布计划。先执行,再说明现在有什么。
  • 用一段话复述用户的回答。选择器已经展示过了。
  • 解释技能为何如此运作。这些推理写在 references/ 中,是给你看的,不是给他们看的。如果他们想知道,自然会问。
  • 列出一张表,展示你即将构建的一切。
  • 在阶段结束时总结你在阶段开始时说过的话。
  • 粘贴你刚写入的文件。他们可以自己打开。

唯一值得多花笔墨的是需要用户做出实际决定的问题。应通过提问工具提出,让选项承载信息,而不是在问题上方另写一段说明。

每次发消息前都可以问自己:如果删掉这句话,它依然成立吗? 如果磁盘上的文件已经记录了这件事,就删掉它。


它是什么,不是什么

暗工厂不是一种不同的 AI 编码方式,而是你已经在用的 AI 编码方式,只是移除了人工检查点。

你今天运行的任何流程,都会放进工厂里。GitHub Spec Kit、BMAD、PRP 框架、你自己的先规划后实现循环,或者只是一个驾轻就熟的习惯。步骤不变,技能不变。你已经信任的 MCP 服务、规则文件、子 Agent、命令也都不变。

唯一的变化是:没人批准计划,也没人会在发布前审阅差异。

所以这里的任务不是发明一种流程,而是记录用户已经采用的流程,再构建让人可以放心离开的部分。尽早询问他们当前的 AI 编码工作流是什么样的,并将其编码实现,而不是强行套用示例工厂的结构。

此技能不会编写 PRD。 这是有意为之。为产品制定顶层计划,是几乎每个人都已有值得保留的自定义方法的一环;泛泛的访谈反而会降低质量。如果用户还没有方法,请让他们使用同一仓库中的 plan-create-prd 技能,等他们准备好文件后再回来。

塑造以下每项决策的两个要点

  • 缓存读取的成本远远高于输出成本。 上下文大小对费用的影响远大于 Agent 写入的内容量,因此规划环节应使用高级模型,其他环节则使用更便宜的模型。
  • 拒绝的成本很低,构建的成本却不低。 如果 Phase 0 的结果尚不确定,就拒绝。错误的工厂要到第二个月才会被发现,而且无法靠更好的提示词来修补。

如果用户希望先做较小的投入,可以提出只完成指导层就停下。即使他们永远不启用 cron,这也很有用。

首先要做的事:区分三种 harness

人们常把它们混为一谈,结果遇到问题时无法调试。尽早清楚地说出它们的名称:

Harness它是什么由谁构建
Agent harnessClaude Code、Codex、Pi——将提示词转化为编辑内容的循环供应商。与你无关。
工厂 harness规划、实现、审查、设门禁、合并工作的方式templates/runner/。 组件 1-4,基本直接复制。
验证 harnessAgent 用来像用户一样检查自身工作的工具由你构建,而且这是大部分工作。 组件 5。

工厂 harness 决定运行什么;验证 harness 决定运行的内容是否值得保留。混淆两者,正是人们构建出令人印象深刻的 DAG,却仍按计划发布有问题软件的原因。

这种区分也决定了哪些部分会以模板形式提供:

工厂 harness 可以模板化。验证 harness 不可以。

调度器、运行器、门禁、守卫、合并机制和状态机在每个工厂中都相同,因此它们位于 templates/runner/ 中,保留了所有踩坑后的改进。对于这个应用而言,“正常工作”意味着什么,是没人能提前写好的唯一部分,所以组件 5 由你负责——这也是本次构建中真正的工作所在。


构建顺序,以及为什么不是 1-2-3-4-5

这五个组件按结构顺序编号,即讲解这台机器时的顺序。它们并非按此顺序构建。应按以下顺序构建:

构建组件原因
第 0 个(PRD)不是组件,而是输入。以下所有内容都会读取它;没有它,以下任何内容都无法如实编写。
第 1 个指导层(#4)Markdown,其他每个组件都会读取它。这里成本最低、杠杆效应最高。
第 1.5 个(行走骨架)仅适用于 Greenfield,且应在指导层之后,而不是之前——这个切片应在任务范围内构建,而且 Markdown 无需任何代码即可存在。它不是组件;它刻意保持精简,是能产生一种可断言行为的最小切片。针对尚不存在的软件,无法编写组件 5。参见阶段 0c;这里的危险在于构建 MVP,而不是切片。
第 2 个验证框架(#5)这是关键路径。要提前启动,因为你会在这件事上判断失误两次。
第 3 个工作流驱动的仓库(#1)现在工作流已有规则可遵循,也有检查需要通过。
第 4 个部署(#3)在让它无人值守之前,先让真实用户参与,完成闭环。
最后触发器(#2)定时任务就是开关。只有在 1-4 都经过验证后,才启用它。

**触发器有意放到最后构建。**启用调度器的那一刻,仓库便开始自主运行。在此之前,一切都可以手动运行并检查。先造好调度员的工厂,只会变成无人监督、从未有人检查过的代码生成器。

开始之前,先向用户说明这一点。这会让整个项目从“接好一个 Agent”转变为“证明自己有资格放手”。


阶段 0。输入、两种拒绝方式,以及 Greenfield 路径

0a. 必须有 PRD

此技能的输入是 PRD:要构建什么以及为什么,达到产品经理撰写的详细程度。问题、用户、范围,尤其是非目标。可以称之为规格说明、简报、产品文档、史诗;名称不重要,内容才重要。

PRD 中不会刻意包含技术栈、架构、数据模型或文件布局。这些属于工程决策,之后才会制定;在工厂中,通常会在首次实际运行时决定,或者现有代码库早已确定。此时要求提供这些内容,只会让 PRD 变成一份没人能改动的规格说明。

**如果 PRD 中确实包含这些内容——而且通常会包含——就把它们视为已定事项,而不是范围,并说明你会这样处理。**非工程师会把技术栈写进去,因为这是他们觉得自己有把握的部分;转行者写的简报,往往会先列出框架、托管方和一份表结构草案,却还没提到任何非目标。跟他们争论毫无益处,只会让会议气氛变差。

所以:把它视为已经做出的决定,不要写进 MISSION.md(它不属于范围,工厂也不能为它辩护),并用一句话指出这一点,以表明这是一个选择,而不是你默默假定的内容。唯一需要当面确认的是可达性——如果某个技术栈只能通过渲染后的页面来调用,就需要把逻辑拆分出来,放在 E2E 可以调用的接口后面。参见 0c。

提问之前,先完整阅读 $prd 中的 PRD。然后按以下方式梳理:

PRD 提供的内容工厂据此构建的内容
问题,以及解决它的价值MISSION.md 开头的背景说明
用户是谁E2E 流程中扮演的角色
MVP 范围、能力领域分诊允许接纳的内容
非目标MISSION.md 中永远不在范围内的事项,是整个构建中最具决定性的清单
成功指标验证测试最终要衡量的内容
未决问题、任何标记为 TBD 的内容待提出的决策,而非阻碍。工厂会选出站得住脚的方案并记录下来;合并需由人工把关。只有 FACTORY_RULES.md §7.2 中的少数情况才会升级处理——把“未决”理解为“我还没有决定”,绝不要理解为“你不可以提出方案”

还要明确告诉用户PRD 没有提供哪些内容,因为这些正是访谈要梳理出来的:

  • 以可观察步骤叙述的 E2E 顺利路径
  • 受保护列表
  • 必须用代码而不是提示词实现的两个关卡
  • 目标自主级别
  • 停止按钮
  • 工作如何到达,以及工厂在哪里运行

**如果没有 PRD,就拒绝。**说明原因:没有书面的范围,MISSION.md 就没有范围外清单;没有这份清单,任何看似合理的功能请求都可能被认为在范围内。工厂会把它们全部构建出来。这是自主代码仓库最常见的出错原因,而且之后无法靠改进提示词来修复。

指向此仓库中的 plan-create-prd 技能,然后停止。二十分钟后带着真正的 PRD 再回来,这是最快的途径,不是绕远路。

0b. 仓库必须可观测

先检查,再提问。查找:可运行的测试命令、启动应用的方法、现有 CI、gh 是否已通过身份验证、仓库是否公开,以及已有的任何 AI 编码配置(CLAUDE.md、AGENTS.md、.claude/、.cursor/、现有技能、命令、MCP 配置)。最后这一项就是要编码的流程,而且通常已经放在那里了。

通过观察判断这是两类仓库中的哪一类——你刚刚已经检查过了。不要提问。 以下拒绝条件是为其中一类编写的,用在另一类上会严重失准;文件列表里就能看出区别:

  • 棕地项目——包含非脚手架的源文件。拒绝条件按原样适用。
  • 绿地项目——有 PRD,也许还有 .gitignore、.claude/、README,但没有任何可运行的内容。**这两条拒绝条件在这种情况下显然都成立,却都没有任何参考价值。**前往 0c;不要拒绝。

用一行说明你的判断及理由,让用户可以纠正你:"docs/ 和 .claude/ 之外没有源文件,因此我将其视为绿地项目。" 猜错了很容易纠正,而提问只会浪费一个你已经有答案的问题。

遇到以下情况时,拒绝并说明原因:

  • 无法观察软件运行情况——没有任何东西可启动、可调用,也没有任何可导入的内容。组件 5 无从着手。

    **这里指的是无法观测的软件,而不是尚不存在的软件。**绿地仓库按定义会触发这一条和下一条;拒绝它就等于否定前提,而不是指出缺陷。参见 0c。

    **库不属于这种情况。**该测试框架附带三个驱动程序——http(服务端)、cli(命令)和 library(不运行进程;E2E 会导入它并调用它)——而 APP_STARTED driver=library 表示导入成功,这与服务端正常响应所表达的意思相同。这一条过去以“库”开头,针对纯 Python 库运行的测试差点就硬性拒绝了一个脚手架开箱即支持的仓库。在判断某个项目是否不可观测之前,请先阅读 templates/harness/appproc.py。

  • **仓库既没有 CI,也完全没有测试命令。**先从测试套件开始。没有任何检查支撑的黑暗工厂,就是一台用来合并看似合理代码的机器。

  • **用户想让 Agent 接触身份验证、支付,或任何后果严重到他们无法承受的内容。**这些应该列入受保护清单,而不是交给工厂处理。

现在拒绝,代价比到第二个月才拒绝更低。如果符合上述任一条件,就提供范围更小的方案:现在搭建指导层和测试框架,到自主运行之前停止。

0c. 绿地项目:行走骨架,而且要小

**这是常见情况,不是例外。**大多数人希望在项目启动时就建好黑暗工厂,而这也是最佳时机——趁还没有任何东西与之冲突,指导层最容易编写;而下面所说的模拟与呈现分离,在还没有代码时几乎不费成本,之后则代价高昂。

绿地项目不是拒绝的理由。但这确实意味着组件 5 目前无从着手,而无论如何安排各阶段顺序,都无法改变这一点。必须先有东西存在。

骨架是最精简的纵向切片,不是 MVP

绿地开发最容易在这里出错,而且每次都会朝同一个方向出错:Agent 提议构建产品核心,好让测试框架有东西可测;用户觉得这听起来有必要,于是同意;结果,现在有趣且风险最高的工作都由人手动完成了,工厂只剩下边角料。这完全颠倒了整个做法的初衷。

构建一个能端到端产出可观察、可断言行为的最小切片。
对于游戏:一个敌人、一次命中、一个伤害数值,并且在重启后仍能保留。对于服务:一个能写入一行数据并读回该行数据的端点。对于 CLI:一个带一个标志、能改变一行输出的命令。

测试标准不是“这有用吗”,而是**“E2E 能否断言某个用户会注意到的事情?”**如果可以,就停止构建产品,开始构建工厂。MVP 中的其他所有内容都是 issue,而构建这些内容的工厂才是你来这里要做的事。

开始前明确说明切片的规模,并说清楚你有意不做什么:"我正在构建一个号角关卡、一波敌人、一个伤害数值和一个存档文件。不做奖励曲线,不做元素交互,也不做波次编排——这些分别是 issue 一、二和三。"

可达性约束,现在就要确定

测试框架只有三种方式可以触达软件——http(服务)、cli(命令)、library(导入并调用)。阅读 templates/harness/appproc.py。渲染窗口、游戏循环、画布、原生 UI,都不属于这三种方式。

因此,在绿地开发中,这不再是架构偏好,而是硬性要求:**逻辑必须位于无头、可脚本化的界面之后,以便 E2E 驱动。**模拟与渲染分离。领域与视图分离。如果规则只存在于引擎节点和渲染循环中,就没有东西可供断言,工厂也无法达到第 3 级——不是因为技能有限,而是因为没有任何东西能检查工作成果。

在编写任何代码之前就说明这一点。现在这么做几乎不费力,之后则需要重写。

工厂的范围严格小于 MVP

有些 MVP 项目无法通过机器验证,也永远无法做到:"战斗感觉不错"、"升级过程在视觉和听觉上明显不同"、"初次游玩的玩家能理解它"。这些属于手感、呈现效果和易读性。

明确说出这些项目,并将它们写入 MISSION.md 和 FACTORY_RULES.md,标记为永久由人类判断;同时说明工厂负责的是模拟层,而不是产品本身。这仍然是一个广阔且有价值的范围——通常承载着大部分实际风险——但若假装这就是整个 MVP,最终只会得到一个测试全绿、发布的游戏却没人想玩的工厂。

然后,按以下顺序进行——分支选择要放在访谈之后

现在就在第 0 阶段说明上述两点(骨架是一个切片;逻辑必须可达),因为这两点都会影响用户在访谈中告诉你的内容。然后:

  1. **第 1 阶段:访谈。**在绿地开发中,这一步保持不变。
  2. **第 2 阶段:指导层。**它是 Markdown,无需代码,后续每个组件都会读取它——包括骨架;骨架应在任务范围内构建,而不是与任务并行构建。对于绿地开发的用户来说,这也是自然的停步点;先构建骨架会剥夺这个选择。
  3. 骨架:根据 R1.1 中的历程确定名称和规模。
  4. 第 3 阶段起按原文执行。

**下面的分支选项应在第 1 阶段之后介绍,而不是在此处。**推荐选项要求你明确切片内容和不做的部分;在 R1.1 告诉你历程之前,这两点都无法如实确定。第 0 阶段就询问会导致用户基于尚未掌握的信息做出决定。第 0 阶段只需提示用户稍后会做选择;把选择放到访谈之后。

面试结束、了解了你的规划后做出的分支选择

有三个已知选项,因此像其他选项一样通过提问工具发起调用,并推荐第一个:

  1. 现在搭建精简骨架,再在其上构建工厂 (推荐)——明确切片的范围,也明确省略哪些内容,这样“推荐”就不会被理解为“我会帮你构建 MVP”。
  2. 仅提供指导层和脚手架——复制 MISSION.md、FACTORY_RULES.md、CLAUDE.md,以及 runner/ 和 harness/,并记录契约,断言则留空。由用户构建骨架;你从组件 5 继续。这是真正的选项,不是安慰奖:无论最终是否启用 cron,MISSION.md/FACTORY_RULES.md 这一对在交互式工作中都很有用。
  3. 暂停——先定架构——当 PRD 将 0c 的可达性约束所依赖的内容推迟处理,而用户希望在代码编写前先确定它时。

第一阶段:面试

阅读 references/interview.md 并按其流程进行。这就是完整的技能,只是以问题的形式呈现:每个问题的实际目的、理想答案是什么样的,以及遇到哪些含糊回答时应追问。

这是三轮面试,不是一份问卷。 第一轮是下面的三个问题,必须先逐个提问。第二轮有六个问题,只有用户能回答。第三轮则用一条消息列出所有剩余设置,并预先填好默认值,再询问用户想改哪些。

提出默认值,不要盘问。 受保护路径、轮询间隔、并发数、停止按钮、PR 上限、模型路由和保留集位置都有可用的默认值,这些默认值已随 config.sh 和模板提供。开放式地询问这些内容,会让用户替这项技能做功课,还会埋没真正重要的问题。与其问“哪些文件必须禁止 Agent 修改?”,不如问“我准备保护这五个路径,以及你的 CI 配置——还需要保护其他内容吗?”。从未构建过这类系统的人也不可能答错后者。

PRD 已经回答了其中一部分问题。 不要重新询问 PRD 中已有答案的问题。将范围和非目标复述为提议——“所以,分流会接受这四个领域的内容,并拒绝这六个领域的内容,对吗?”——把时间花在尚未明确的部分上。用户明明已经写下答案,你却再次询问,这是面试在前两分钟就失去他们注意力的原因。

进入下一个问题前,先将每个回答复述为具体的产出物(“所以,合并门槛是:X”)。

每个问题都必须通过提问工具提出。 在 Claude Code 中使用 AskUserQuestion,其他环境则使用等效工具。每个问题都要通过工具,包括开放式问题。不得例外,也不得用普通文字替代。

过去的做法是将两者分开——已知选项用选项列表,开放式问题用普通文字——理由是,为“描述用户最有价值的操作”提供选项,会把答案变成一份由你猜测的菜单。工具本身已经解决了这个问题:它始终提供可输入自由文本的“其他”选项。 想用自己的话回答的用户仍然可以一键输入。原本会略读一段文字后说“你来选”的用户,现在可以从三个具体候选项中指出最接近的一个并加以修正;这正是你需要的答案,也是原本得不到的答案。

旧观点中仍然成立的是对选项的约束,而不是对工具的约束:对于开放式问题,选项应根据他们的 PRD 和仓库推导出来,并注明来源。基于他们自己的材料起草的选项,相当于把他们的答案复述给他们,他们会很乐意改写;凭空编造的选项则会让他们受你的猜测影响。

第二轮的每个问题都要询问用户身上已经发生过的事情——曾经漏出的缺陷、他们会放下一切去修复的问题、以及他们在变更后会做什么来让自己确信一切正常。不要让用户设计产出物。他们只需回忆自己软件中的实际经历;将这些经历转化为场景、缺陷集合和规则是你的工作,并且应默默完成。interview.md 写明了具体措辞以及每个回答会转化成什么。 每个问题都适用两条规则:

  1. 始终给出一项推荐。 恰好一项标记为 (Recommended),并放在首位, 在其单行描述中说明原因。绝不留白。如果推荐并不诚实——确实五五开——就在问题中 说明这一点,而不是凭空装作有把握。
  2. 在对方回答前,主动提出解释难懂的概念。 留出集、变异集、棘轮机制、 独立性界线、结构门槛,这些概念只有构建过这类系统的人才会觉得显而易见;不想承认自己 没听说过留出集的用户会猜。添加一个 "先解释这个" 选项。interview.md 为每个术语 都准备了一句话解释——用那些话,不要长篇说教。

第一轮——三个问题将决定项目方向,所以不要放过任何一个:

  1. "请带我走一遍:有人使用它时最有用的一件事,从第一次点击开始,到最终看到的内容为止。" 这一流程将成为每次变更时都会检查的主路径。如果他们说不清楚,就无从检查。
  2. "你现在如何借助 AI 构建功能?" 只问一个开放式问题,不要搞问卷——根据对方提供的信息,再查看 CLAUDE.md、AGENTS.md、.claude/ 和 .cursor/,补全其余部分。工作流应当让他们认得出是自己的流程,只不过去掉了审批环节。
  3. "你愿意让代码在无人事先审阅的情况下触达用户吗?" 然后再看下面的档位。推荐级别 3。 人们常会说 5;5 意味着工厂根据使命自行编写任务,这是另一项决策。
自主性档位
级别自动执行的内容你仍需做的事
0工作流已就绪手动运行
1带标签的问题单 → 自动创建 PR审阅并合并所有内容
2+ 验证器运行并发布判定结果合并所有内容
3+ 所有结构门槛均通过时,验证器会自动合并编写问题单、发布版本
4+ 它会自行分类问题单,定时测试也会自行提交 Bug编写重要问题单
5+ 它会根据使命自行编写问题单什么都不用做

级别 3 是默认值。按此级别构建。

这是代码首次能在无人审阅的情况下合并的级别,也是整个系统的意义所在:停在 2 的工厂只是一个带队列的代码生成器,而人仍是他们本想消除的瓶颈。这项构建中所有困难之处,都是为了达到级别 3;按更低级别构建,意味着做了难的部分却不用它。

级别 0 到 2 是逐步迈向目标的阶段,不是终点。按顺序交付,在每个级别都验证一次完整流程,然后继续推进到 3。orchestrator.sh 会强制执行档位限制;在留出集存在之前,factory_doctor 会彻底阻止启用级别 3。因此,“按级别 3 构建”不会变成证据不足就“开启级别 3”。

只有当用户有具体理由时,才停在 3 以下——例如无法取消的审阅要求、无法承受的影响范围,或尚未信任的测试框架。这是合理的选择,也应该由他们明确作出,而不是因为没人提起档位而默认如此。

级别 3 以上是另一个问题,不是更进一步:级别 4 把构建什么交由系统决定,级别 5 则把要构建什么也交由系统决定。希望自动合并,并不意味着也希望交出这两项决定权。

阶段 2:指导层(组件 4)

阅读 references/guidance-layer.md。根据模板编写三个文件:

  • MISSION.md——要构建什么,以及永远明确排除在范围之外的内容
  • FACTORY_RULES.md——Agent 在无人监督时的行为方式,以及受保护列表
  • CLAUDE.md / AGENTS.md——任何项目(无论是否使用工厂)都应遵守的约定 (模板位于 templates/CLAUDE.md;如果已存在此文件,请拆分,而不是替换)

MISSION.md 是对 PRD 的提炼,而不是一份新文档。 直接根据 PRD 起草,并向用户展示含义上的差异,而不只是文件差异。PRD 中的非目标几乎应原样成为范围外清单;访谈额外补充的内容则应标明,以便日后清楚区分哪些约束来自产品,哪些是为了实现无人值守而添加的。

如果已存在约定文件,请保留它,并从中抽出仅适用于工厂的规则,而不是直接覆盖并重写。这种拆分通常是本阶段对现有代码库最有价值的修改。

每条规则都要进行如下判断:

如果由人来完成工作,你仍会写下这条规则吗?→ 约定文件。 这条规则是否仅因无人监督而存在?→ FACTORY_RULES.md。 这条规则是否关乎产品是什么或不是什么?→ MISSION.md。

最重要的一点:Agent 不能修改评判自身的规则。 这三个文件都要加入受保护列表;凡是涉及这些文件的 PR,都应在评估其他内容之前自动拒绝。应在代码中强制执行,而不是依赖提示词。

现在运行 scripts/factory_doctor.py --repo <path>。它会明确报错,这正是预期结果——它是一份检查清单,而现在正是开始逐项处理的时候。

第 3 阶段。验证工具链(组件 5)

开始编写前,请完整阅读 references/validation-harness.md。这是最长的一份参考文档,因为工厂真正出问题的地方就在这里。开篇部分就是运行器要求遵守的契约——入口点、标记、追加规则以及 --quick 子集。即使只粗略浏览其余内容,也要读完这部分,因为追加规则弄错后,每个标记断言都会失败,原因看起来还像是代码的问题。

从脚手架开始,然后删除其中的断言。

cp -r templates/harness <repo>/harness

templates/harness/ 提供的是基础设施,而且仅限基础设施。它不只适用于 Python,也不只适用于 Web:每条命令都位于 harness.config.json 中,驱动程序可以是 http、cli 或 library。已在 Python HTTP 服务、Node CLI(只更改五个配置值,其他内容不变)和 Python 库上验证过。

它提供:逐级测试流程、带计数的标记、步骤命名器、--quick 子集,以及一个应用进程管理器,可绑定动态端口、等待健康检查,并在所有路径下完成清理。开箱即用。

这种划分不是权宜之计,而是结论。两个人从零开始、在没有脚手架的情况下,独立地为不同产品构建了这套工具链,并写出了同一个文件——两人甚至都自行加入了“未发现任何测试不算通过”的保护机制。基础设施由标记契约决定,而不是由应用决定。

e2e.py 中的每个断言都是示例,应该全部删除。 .factory/holdout/run.py 和 harness/mutations/defects.json 也一样。每个文件都带有一行标记,内容成为你自己的之后就要删除这行,而在你删除之前,factory_doctor 会在级别 2 及以上阻止流程——针对模板示例产品也能报告绿色的门禁,比完全没有门禁还糟糕。

访谈会产出全部三项:R1.1 用户旅程、R2.5a 构建者无法看懂的组合场景、R2.5b 必须捕获的缺陷。用户会注意到的部分无人能替你编写,它就是对 R1.1 的回答,也是实际工作的所在。脚手架能帮你搭好基础设施,但不能替你编写断言。

简而言之,但不能代替阅读全文:

  • 沿阶梯逐级推进: 静态检查 → 单元测试 → 集成测试 → E2E:模拟真实用户 → 视觉评估 → 保留场景 → 确定性门禁。
  • 在集成测试之后划定独立性边界。 边界以下的一切都处于 Agent 的优化循环之中,因此只要给它时间,它就会满足你测量的内容,而不是你真正想要的结果。增加边界以下的测试不是解决办法。
  • 至少有两个门禁必须由模型无法绕过的代码实现。 合并操作本身,以及明确断言应用确实已启动。其他地方的“门禁”都是提示词指令,只是一种礼貌的建议。
  • 空不等于通过。 断言实际运行了多少项检查,而不只是检查有多少项失败。跳过的检查不会返回任何结果,而没有结果不等于失败。
  • 验证器永远不会了解代码是如何编写的。 它只了解提出了什么要求,以及代码现在的实际行为。

交付物:一个工作流可调用、会输出明确标记的 validate 入口点,以及一个通过 grep 搜索这些标记的 Bash 合并门禁。

阶段 4:工作流驱动的仓库(组件 1)

阅读 references/automation.md,了解每个 Agent 的无头模式约定以及运行器包含的内容。

复制运行器;不要自己编写。 templates/runner/factory/ 是一套可运行的执行层,包含调度器、运行器、结构门禁、受保护路径守卫、合并、部署、状态机和七个节点提示词。其 README.md 列出了安装顺序。

cp -r templates/runner/factory <repo>/factory
mkdir -p <repo>/.factory/{locks,holdout,runs}

接下来进行三项修改,其中第三项才是本阶段真正要做的工作:

  1. factory/config.sh —— Agent、模型,以及指向阶段 3 测试框架的 FACTORY_VALIDATE_CMD。所有项目专属值都在这里;如果你要通过编辑其他脚本来更改路径,那就是 config.sh 写错了。
  2. factory/guard.py —— 受保护列表。先填好它,不要只接受访谈得出的结果。
  3. factory/prompts/*.md —— 将这些提示词改写为用户自己的流程。 阶段 1 的 R1.2 回答会在这里落实。如果他们用一种技能进行规划,再用另一种技能来实现,那就是两个节点。如果现在某个步骤会加载规则文件或 MCP 服务,那就在这里的对应步骤加载。

工厂的有趣之处在于它能无人值守地运行,而不是它的工作方式有所不同。用户若能在这些提示词中看到自己的工作流,就会信任并维护它;若还得学习一套新流水线,就不会。个性化体现在提示词中,而不在管道中——这正是为什么管道以副本形式提供,而提示词则以标明待决策事项的框架形式提供。

如果用户已经在运行某个工作流引擎(Archon、YAML DAG、GitHub Actions、Agent SDK 程序),运行器仍可作为参考,说明各节点必须执行什么操作——新上下文边界、工具允许列表、holdout 拒绝、提交步骤和门禁。移植这些特性;不要移植 bash。

阶段 5:部署(组件 3)

阅读 references/deployment.md。内容很简短,其中包含一个陷阱,它悄无声息地毁掉的工厂比其他任何问题都多:GitHub 不会因使用默认 GITHUB_TOKEN 创建的提交而触发工作流。 Agent 完成提交,部署却不会启动,没有任何报错,也没有任何提示。

如果闭环没有触达真实用户,用户构建的就只是一个 PR 生成器。

阶段 6。触发器(组件 2)

现在才做。完整阅读 references/setup.md 和自动化参考文档中的调度器部分。

references/setup.md 是不起眼却没人会写下来的那一半内容:前置条件、cron、systemd 和 Task Scheduler、.gitattributes 的行尾设置、core.longpaths、PYTHONIOENCODING、git check-ignore 预检、凭据过期,以及如何有意测试停止按钮。上面的每一项都曾让真实的工厂出过问题。你可以有五个完美的组件,但如果检出时行尾被改写,机器就可能从未完整跑完一轮。

运行器已经强制执行这个刻度:orchestrator.sh 会读取 FACTORY_AUTONOMY,并拒绝执行低于其级别的操作,因此提高刻度是一个刻意的行为,而不是文件里的一条备注。

请大声说出来,因为几乎每个人一开始的理解都是错的:没有任何东西会主动推送。 提交问题不会触发运行。没有 webhook,而且本来也不该有——调度器会按计时器唤醒、读取状态,并且最多调度一项工作。09:01 提交的问题要等到下一个时刻。推送触发器一旦失效,就会悄无声息地失败,看起来和工厂无事可做完全一样;轮询一旦失效,你能看出来它没有运行。

在第一轮完成后再安装,不要现在安装。 install-trigger.sh 在刻度低于 1 时会拒绝安装;而且刻度要等到阶段 7 手动验证一轮完成后才会离开 0——因此,按编号顺序无法执行阶段 6。现在构建触发器配置;到阶段 7 的第 3 步、刻度发生变化时,再运行安装程序。代码没问题,错的是这个顺序。

使用安装程序启用它,不要手动操作;请注意,它会在刻度为 0 时拒绝安装——级别为 0 的调度器会永远唤醒,却正确地什么也不做,这正是人们误以为工厂正在运行、其实它从未完成过一轮的原因:

bash factory/install-trigger.sh --status     # what is armed right now
bash factory/install-trigger.sh --install    # cron, systemd timer, or Task Scheduler
bash factory/install-trigger.sh --remove

然后再次运行 factory_doctor。现在它会检查调度器是否确实已启用,因为没有任何任务被调度的完整工厂,在审计结果上和正在运行的工厂完全一样。

调度器必须是整个系统里最简单、最确定的部分。 不要让 LLM 决定运行什么——那会为不存在的工作虚构调度任务。使用 Bash、固定优先级顺序,以及存放在简单可靠之处的共享状态(GitHub 标签就足够;不需要数据库,也不需要消息总线)。

优先级固定,且以下顺序至关重要:

  1. 修复需要修复的 PR
  2. 验证等待审核的 PR
  3. 实现优先级最高的已接受问题
  4. 对尚未分类的问题进行分流

先完成正在进行的工作,再开始新工作。 顺序反过来,工厂就会永远处理问题分流,而自己的 PR 却无人理会。

阶段 7:验证成果,然后升至 3 级

目标是 3 级,直到指针到达那里,任务才算完成。 以下步骤是为达成目标提供证据,而不是让你爬到一半就停下的阶梯。

  1. 手动跑通最简完整流程:从一个真实问题开始,一路做到你亲自合并 PR。没有完整跑完一轮的工厂,不要继续推进。
  2. 运行 python scripts/factory_doctor.py --repo <path> --audit,直到检查通过。如果没有留出测试集,它就会拒绝认定为 3 级;这项检查决定了此前的一切是否都是真实有效的。 2b. 运行 python scripts/_test_runner.py --repo <path> 和 python scripts/_audit_runner.py --repo <path>。 doctor 会检查仓库是否设置正确;这两项检查底层机制是否仍能正常工作。它们无需额外付费,耗时约两分钟;未通过检查的工厂会悄无声息地出问题——工作被搁置,却无人获知;或工作流反复运行,注定失败。每当你手动编辑 factory/ 下的内容,以及重新启动闲置工厂前,都要重新运行这两项检查:运行器会被复制到仓库中,不会建立链接,因此上游的修复不会自动同步到你的仓库。
  3. 将指针调至 1 级,然后调至 2 级;每一级都观察一个完整周期——接着调至 3 级。停在 2 级意味着每个 PR 都要由人来合并,而这正是整个构建要解决的瓶颈。如果用户选择停在 3 级以下,就在 FACTORY.md 中记下继续升级需要满足的条件,这样这项决定就有改变的途径,而不是再也没人碰过的指针。
  4. 根据模板编写 FACTORY.md——说明构建了什么、目前运行在哪一级,以及升至下一级前需要满足什么条件。链接它所依据的 PRD,因为产品变更时,任务也必须随之变更;否则工厂会一直忠实地构建旧范围,直到有人发现为止。

运行须知——不是要照着念的演讲稿

不要逐字复述本节。 这部分读起来像开场简报,而且过去确实被当作简报来讲,导致用户还没做任何事,就先听了六段密集的说明。这些是你正确构建所需了解的事实,应在它们变得可执行的那一刻分别提及——启用触发器时提到令牌的事项,编写第一个会提交更改的工作流时提到 git check-ignore 的事项,每次只说一行。如果用户问有哪些注意事项,就从这里回答,先说最简要的。

  • PRD 现在是持续更新的文档,不再是启动项目时的一次性产物。 在常规开发中,PRD 会过时,由人悄悄补上缺漏。而在这里,没有人会补救:工厂会一直按照给定的范围构建,直到有人编辑范围。要改变产品,就必须有人类有意提交 MISSION.md 的修改。
  • 在第一轮无人值守运行前的第一天,就开始记录令牌用量。 这不是警告,而是一项你将来会需要、之后却无法补录的指标。从外部看来,一次“修复问题”的运行背后可能有远超想象的 Agent 会话;要知道你自己的工厂实际消耗多少,唯一的方法就是从第一轮开始记录。
  • 在规划环节使用一个高级模型,其他环节都用更便宜的模型。 在两个关键环节之一使用高级模型,带来的质量提升已接近两个环节都使用高级模型。真正让你付出代价的,是两个环节都不用高级模型。
  • 将每个可编辑节点限制在各自的差异范围内。 如果节点可以不受文件范围限制地编辑,它就会把一个六个文件的 PR 扩大成十一个文件,还可能在过程中引入错误。
  • 在第一个会提交更改的工作流运行前,对每个配置文件运行 git check-ignore -v。 在创建 PR 的步骤中执行 git add -A,会发布所有未被忽略的内容;公开发布就是对所有人公开。
  • Agent 是可以互换的部分,底层机制则不是。 凭据过期、成本骤增、没有默认会话超时,以及沙盒出站流量限制,是所有 Agent 都会遇到的问题,没有哪种 Agent 能替你解决这些问题。

资源

  • dark-factory-diagram.png:一页展示整个系统——五个组件、三个治理文件、阶梯和独立性分界线。供阅读此仓库的人查看,不供 Agent 使用。 构建期间不要讲解它。

  • references/interview.md:分三轮进行访谈——三个决定项目的问题、七个关于用户已熟悉的软件的问题,以及一轮确认默认值。每个问题都通过提问工具提出,并附带一项建议;问题中不得提及用户没有理由了解的概念;每个术语都附有一句可一口气读完的通俗英文解释。在 Phase 1 阅读。

  • references/guidance-layer.md:三文件拆分、放置测试、受保护文件,以及如何编写真正发挥作用的范围外清单。在 Phase 2 阅读。

  • references/validation-harness.md:阶梯、独立性分界线、留出集设计、结构门禁与提示词门禁,以及失败模式。在编写任何检查之前,于 Phase 3 阅读。

  • references/automation.md:八种编码 Agent 的无头模式契约、编排器选项及权衡,以及调度器规则。在 Phase 4 和 Phase 6 阅读。

  • references/deployment.md:部署策略、GITHUB_TOKEN 陷阱,以及 GitHub 调度的注意事项。在 Phase 5 阅读。

  • references/setup.md:先决条件、平台成本、调度和启用方式。在 Phase 0b 浏览,尽早决定是否拒绝;在 Phase 6 完整阅读。

  • templates/:MISSION.md、FACTORY_RULES.md、FACTORY.md。复制并填写;绝不能原样交付模板中的占位文本。现在已经没有单独的 orchestrator.sh 或 validate-gate.sh 草稿——它们只是 templates/runner/factory/ 中真实版本的劣质重复,而交付一套流水线的第二个定义,正是 automation.md 警告的错误。没人运行的那套才会逐渐偏离。

  • templates/runner/:可工作的执行层,约 3,000 行,在 Phase 4 复制到仓库中。阅读其中的 README.md,了解安装顺序和关键内容列表。注释记录了真实事故——只凭设计重新构建工厂,就会在无人值守的生产环境中再次遇到每一项事故。

  • templates/harness/:验证框架的底层支撑,在 Phase 3 复制。开箱即用;其中的每项断言都是示例,必须删除。工厂验证框架可模板化,其底层支撑也可模板化——不可模板化的是对这个产品而言“正常工作”的定义,而这正是组件 5 的全部内容。

  • scripts/factory_doctor.py:对工厂仓库进行确定性审计——检查受保护文件、留出集泄漏、门禁是否为代码、空结果是否未被视为通过、被忽略的密钥,以及自主性级别。在 Phase 2 和 Phase 7 运行。绝不要将其源码读入上下文;只读它的输出。

  • scripts/_test_factory_doctor.py:doctor 自身的测试。它会构建一个健康的工厂,每次破坏一项内容,并要求 doctor 检测出来。修改 doctor 后运行。如果一个门禁从未失败过,就说明没人测试过它;这个原则也适用于此技能的门禁。

  • scripts/_test_runner.py:runner 的行为测试套件,也是回答“这个工厂真的可靠吗?”的依据。它会用真实的 factory/ 构建一个真实的 git 仓库,通过 stub Agent 和验证器,让完整流程既免费又可确定地运行,然后驱动实际的 shell 脚本。每项测试都以它防止的缺陷命名。

    python scripts/_test_runner.py                    # the shipped template
    python scripts/_test_runner.py --repo <path>      # a factory somebody BUILT
    python scripts/_test_runner.py --mutate           # do the tests catch anything?
    

    要记住的是 --repo。 runner 会被复制到仓库中,从不通过链接关联,因此对此模板的修复无法影响任何已构建的内容;手动编辑的工厂则会在无人监控的情况下逐渐偏离。再次将工厂托付给无人值守运行之前,先对它运行此测试。 --mutate 是确保测试套件诚实的关键。 它会将每个历史缺陷还原到一个临时副本中,并要求测试套件变红。如果一个测试可以恢复缺陷,而所有测试仍保持绿色,那它就只是装饰,我们会如实标明。这正是该技能关于对产品进行变异测试的观点,将其应用到了自身——而且它已经发现这里有一个测试因错误原因通过了。

  • scripts/_audit_runner.py:用于检查行为测试无法表达的结构不变量——子进程读取了一个 config.sh 从未导出的参数、提示词占位符未被渲染器替换、没有任何分发逻辑处理的状态、未加保护的命令在下一行的升级操作执行前就已崩溃。这里同样支持 --repo。factory_doctor 审计的是你的仓库,这个脚本审计的是 MACHINERY:它发现的是工厂本身的缺陷,而不是你设置中的缺漏;即使配置正确的仓库运行着有缺陷的机器,doctor 的所有检查也都会通过。

为什么要有这两个工具。 同样的四种故障反复出现在这个运行器中,每次都是手动发现,然后作为一次性问题修复。原因正是该技能花五个阶段反复强调的代码问题:没有测试框架。运行器有约 4,200 行,却没有任何东西真正执行它,因此每次修复都只是在文档里写下一句话,而不是让测试变红。如果你要从这项技能中为自己的仓库带走一个理念,就带走这一点——并且要注意,它既适用于你构建的工具,也适用于这些工具构建的产品。

评论

支持 Markdown