关于 build-dark-factory
build-dark-factory 是一项在代码仓库中搭建无人值守软件交付流程的 Agent 技能,面向希望将现有 AI 编码工作流转为自动化工厂的团队。它要求以 PRD 为输入,逐步建设指导规则、验证、工作流和部署,并把触发器留到最后。
主要功能
- 01以 PRD 和现有流程为依据
- 02在仓库中构建工厂组件
- 03先建立指导层与验证机制
- 04区分工厂与验证框架
- 05所有组件验证后才启用触发器
适用场景
- 01将已有 AI 编码流程转为自动化交付
- 02为代码仓库设置无人值守构建与验证
- 03分阶段搭建部署和自动触发机制
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ coleam00/ skills --skill build-dark-factory安装后在 Claude Code 中输入/build-dark-factory确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/automation.mddeployment.mdguidance-layer.mdinterview.mdsetup.mdvalidation-harness.mdscripts/_audit_runner.py_test_audit_runner.py_test_factory_doctor.py_test_runner.pyfactory_doctor.pytemplates/CLAUDE.mdFACTORY_RULES.mdFACTORY.mdMISSION.mdtemplates/harness/appproc.pyci.pye2e.pyharness.config.jsonREADME.mdtemplates/harness/holdout/run.pytemplates/harness/locks/floor.jsontemplates/harness/mutations/defects.jsonrun.pytemplates/runner/.gitattributes.gitignoretemplates/runner/.factory/decisions.mdtemplates/runner/factory/config.shcost.pydeploy.sh详细介绍
构建暗色工厂
用户输入: $ARGUMENTS
请自行从这一行中判断 PRD 路径和仓库路径,不要输出未经核实的解析结果。 位置参数按空白字符拆分,因此输入一句话(“build a dark factory for my repo at C:\code\thing”)的人会把前两个单词当作两个路径——有三次独立测试运行显示
PRD: Build和Repo: a,对于之后悄悄自行纠正了解析结果的技能来说,这样的初次体验显然出了问题。因此:读取这一行,找出看起来像
.mdPRD 的内容和看起来像目录的内容,并在 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 harness | Claude Code、Codex、Pi——将提示词转化为编辑内容的循环 | 供应商。与你无关。 |
| 工厂 harness | 规划、实现、审查、设门禁、合并工作的方式 | templates/runner/。 组件 1-4,基本直接复制。 |
| 验证 harness | Agent 用来像用户一样检查自身工作的工具 | 由你构建,而且这是大部分工作。 组件 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 阶段:访谈。**在绿地开发中,这一步保持不变。
- **第 2 阶段:指导层。**它是 Markdown,无需代码,后续每个组件都会读取它——包括骨架;骨架应在任务范围内构建,而不是与任务并行构建。对于绿地开发的用户来说,这也是自然的停步点;先构建骨架会剥夺这个选择。
- 骨架:根据 R1.1 中的历程确定名称和规模。
- 第 3 阶段起按原文执行。
**下面的分支选项应在第 1 阶段之后介绍,而不是在此处。**推荐选项要求你明确切片内容和不做的部分;在 R1.1 告诉你历程之前,这两点都无法如实确定。第 0 阶段就询问会导致用户基于尚未掌握的信息做出决定。第 0 阶段只需提示用户稍后会做选择;把选择放到访谈之后。
面试结束、了解了你的规划后做出的分支选择
有三个已知选项,因此像其他选项一样通过提问工具发起调用,并推荐第一个:
- 现在搭建精简骨架,再在其上构建工厂 (推荐)——明确切片的范围,也明确省略哪些内容,这样“推荐”就不会被理解为“我会帮你构建 MVP”。
- 仅提供指导层和脚手架——复制
MISSION.md、FACTORY_RULES.md、CLAUDE.md,以及runner/和harness/,并记录契约,断言则留空。由用户构建骨架;你从组件 5 继续。这是真正的选项,不是安慰奖:无论最终是否启用 cron,MISSION.md/FACTORY_RULES.md这一对在交互式工作中都很有用。 - 暂停——先定架构——当 PRD 将 0c 的可达性约束所依赖的内容推迟处理,而用户希望在代码编写前先确定它时。
第一阶段:面试
阅读 references/interview.md 并按其流程进行。这就是完整的技能,只是以问题的形式呈现:每个问题的实际目的、理想答案是什么样的,以及遇到哪些含糊回答时应追问。
这是三轮面试,不是一份问卷。 第一轮是下面的三个问题,必须先逐个提问。第二轮有六个问题,只有用户能回答。第三轮则用一条消息列出所有剩余设置,并预先填好默认值,再询问用户想改哪些。
提出默认值,不要盘问。 受保护路径、轮询间隔、并发数、停止按钮、PR 上限、模型路由和保留集位置都有可用的默认值,这些默认值已随 config.sh 和模板提供。开放式地询问这些内容,会让用户替这项技能做功课,还会埋没真正重要的问题。与其问“哪些文件必须禁止 Agent 修改?”,不如问“我准备保护这五个路径,以及你的 CI 配置——还需要保护其他内容吗?”。从未构建过这类系统的人也不可能答错后者。
PRD 已经回答了其中一部分问题。 不要重新询问 PRD 中已有答案的问题。将范围和非目标复述为提议——“所以,分流会接受这四个领域的内容,并拒绝这六个领域的内容,对吗?”——把时间花在尚未明确的部分上。用户明明已经写下答案,你却再次询问,这是面试在前两分钟就失去他们注意力的原因。
进入下一个问题前,先将每个回答复述为具体的产出物(“所以,合并门槛是:X”)。
每个问题都必须通过提问工具提出。 在 Claude Code 中使用 AskUserQuestion,其他环境则使用等效工具。每个问题都要通过工具,包括开放式问题。不得例外,也不得用普通文字替代。
过去的做法是将两者分开——已知选项用选项列表,开放式问题用普通文字——理由是,为“描述用户最有价值的操作”提供选项,会把答案变成一份由你猜测的菜单。工具本身已经解决了这个问题:它始终提供可输入自由文本的“其他”选项。 想用自己的话回答的用户仍然可以一键输入。原本会略读一段文字后说“你来选”的用户,现在可以从三个具体候选项中指出最接近的一个并加以修正;这正是你需要的答案,也是原本得不到的答案。
旧观点中仍然成立的是对选项的约束,而不是对工具的约束:对于开放式问题,选项应根据他们的 PRD 和仓库推导出来,并注明来源。基于他们自己的材料起草的选项,相当于把他们的答案复述给他们,他们会很乐意改写;凭空编造的选项则会让他们受你的猜测影响。
第二轮的每个问题都要询问用户身上已经发生过的事情——曾经漏出的缺陷、他们会放下一切去修复的问题、以及他们在变更后会做什么来让自己确信一切正常。不要让用户设计产出物。他们只需回忆自己软件中的实际经历;将这些经历转化为场景、缺陷集合和规则是你的工作,并且应默默完成。interview.md 写明了具体措辞以及每个回答会转化成什么。
每个问题都适用两条规则:
- 始终给出一项推荐。 恰好一项标记为
(Recommended),并放在首位, 在其单行描述中说明原因。绝不留白。如果推荐并不诚实——确实五五开——就在问题中 说明这一点,而不是凭空装作有把握。 - 在对方回答前,主动提出解释难懂的概念。 留出集、变异集、棘轮机制、
独立性界线、结构门槛,这些概念只有构建过这类系统的人才会觉得显而易见;不想承认自己
没听说过留出集的用户会猜。添加一个 "先解释这个" 选项。
interview.md为每个术语 都准备了一句话解释——用那些话,不要长篇说教。
第一轮——三个问题将决定项目方向,所以不要放过任何一个:
- "请带我走一遍:有人使用它时最有用的一件事,从第一次点击开始,到最终看到的内容为止。" 这一流程将成为每次变更时都会检查的主路径。如果他们说不清楚,就无从检查。
- "你现在如何借助 AI 构建功能?" 只问一个开放式问题,不要搞问卷——根据对方提供的信息,再查看
CLAUDE.md、AGENTS.md、.claude/和.cursor/,补全其余部分。工作流应当让他们认得出是自己的流程,只不过去掉了审批环节。 - "你愿意让代码在无人事先审阅的情况下触达用户吗?" 然后再看下面的档位。推荐级别 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}
接下来进行三项修改,其中第三项才是本阶段真正要做的工作:
factory/config.sh—— Agent、模型,以及指向阶段 3 测试框架的FACTORY_VALIDATE_CMD。所有项目专属值都在这里;如果你要通过编辑其他脚本来更改路径,那就是config.sh写错了。factory/guard.py—— 受保护列表。先填好它,不要只接受访谈得出的结果。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 标签就足够;不需要数据库,也不需要消息总线)。
优先级固定,且以下顺序至关重要:
- 修复需要修复的 PR
- 验证等待审核的 PR
- 实现优先级最高的已接受问题
- 对尚未分类的问题进行分流
先完成正在进行的工作,再开始新工作。 顺序反过来,工厂就会永远处理问题分流,而自己的 PR 却无人理会。
阶段 7:验证成果,然后升至 3 级
目标是 3 级,直到指针到达那里,任务才算完成。 以下步骤是为达成目标提供证据,而不是让你爬到一半就停下的阶梯。
- 手动跑通最简完整流程:从一个真实问题开始,一路做到你亲自合并 PR。没有完整跑完一轮的工厂,不要继续推进。
- 运行
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/下的内容,以及重新启动闲置工厂前,都要重新运行这两项检查:运行器会被复制到仓库中,不会建立链接,因此上游的修复不会自动同步到你的仓库。 - 将指针调至 1 级,然后调至 2 级;每一级都观察一个完整周期——接着调至 3 级。停在 2 级意味着每个 PR 都要由人来合并,而这正是整个构建要解决的瓶颈。如果用户选择停在 3 级以下,就在
FACTORY.md中记下继续升级需要满足的条件,这样这项决定就有改变的途径,而不是再也没人碰过的指针。 - 根据模板编写
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 行,却没有任何东西真正执行它,因此每次修复都只是在文档里写下一句话,而不是让测试变红。如果你要从这项技能中为自己的仓库带走一个理念,就带走这一点——并且要注意,它既适用于你构建的工具,也适用于这些工具构建的产品。