关于 forge
Forge 是一款规划技能,可将初步产品构想整理为六层产品与实施计划,并建立可追踪关系。它面向准备开展实现的团队和 Agent,以人工审批关卡及机械化检查约束阶段顺序和交付物位置。
主要功能
- 01六层产品与实施文档
- 02规则与边界情况的追踪 ID
- 03各阶段之间的人工审批关卡
- 04项目状态与交付物检查脚本
- 05交付物限定存放于 .forge
适用场景
- 01将早期构想整理为产品计划
- 02把产品工作拆分为可实现的切片
- 03检查项目阶段与审批状态
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ tleguede-works/ ship-clean-skills --skill forge安装后在 Claude Code 中输入/forge确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.mdagents/client-liaison.mdforge-implementer.mdplan-validator.mdpremise-challenger.mdproduct-analyst.mdquality-analyst.mdred-team.mdscenario-tester.mdscope-architect.mdsystems-architect.mdux-designer.mdreferences/archetypes.mddesign-quality.mdfast-track.mdimpact-protocol.mdmigration-v1-v2.mdmodule-prioritization.mdresearch-protocol.mdreview-checklists.mdscenario-tests.mdskill-boundaries.mdstate-schema.mdtest-strategies.mdscripts/audit-report.jsconsistency-check.jscoverage-check.jsddl-exec.jsdependency-check.jsdesign-check.js详细介绍
Forge
Forge 可以将一个初始想法——哪怕它还很模糊——转化为一份完整的产品与实现计划,分为六个逐步深入的层级,精确到即使能力较弱的 AI 也能毫无歧义地实现每个切片。
六个文档层级
Niveau 0 — INTENT : Pourquoi ce produit existe, pour qui, quel problème il résout (PRD).
Niveau 1 — SCOPE : Quoi et quand. MVP, V1, V2..., roadmap, compromis de scope.
Niveau 2 — DESIGN : À quoi ça ressemble. Standards, direction visuelle, écrans, flows, interactions.
Niveau 3 — ARCHITECTURE : Comment c'est structuré. Slices, modules, fondations, modèles de données, API, dépendances.
Niveau 4 — PLAN : Comment implémenter chaque slice. Contrats, algorithmes, composants, checklist de tâches, critères d'acceptation.
Niveau 5 — VALIDATION : Comment vérifier que tout fonctionne. Tests unitaires, intégration, E2E, UI (Chrome MCP), régression.
术语——三种规划单元
- 切片:一项完整的端到端功能,涵盖 UI、业务逻辑、数据访问和集成。这是规格说明和实现的基本单位。 灵感来自 Corpus 的“能力”概念——这是一种第三方开源方法论,并非本集合中的技能——但定义依据是需求,而非代码。一个切片对应 PRD 中确定的一项用户需求。
- 模块:一组技术上连贯的内容(例如“身份验证”“支付”)。包含多个切片。用于组织架构,而非规划实现。其排名由使用频率决定,而非领域组织结构。
- 基础项:一项横向关注点(设计系统、身份验证、错误处理、i18n、配置、日志记录、CI/CD)。在业务切片之前实现。保持原子性,不拆分为切片。
指导原则
每项重要决策都有依据,每项声明都可验证,每条路径都经过预判。
Forge 遵循五项基本原则:
-
每条业务规则、每个边界情况、每项约束都有稳定的标识符(业务规则使用 B1、B2……,边界情况使用 E1、E2……,验证使用 V1、V2……,约束使用 C1、C2……)。这些 ID 永不重复使用,即使规则已被删除也不例外。它们构成完整可追溯性的主干:PRD → 架构 → 计划 → 测试。
-
人工关卡不可妥协。 每个阶段都以明确验证结束。未经明确“批准”,绝不开始下一阶段。绝不将沉默或提问视为批准。(有界且有记录的例外:Fast Track 模式,它会在单一检查点后自动执行第 4 至第 5 阶段——参见
references/fast-track.md。) 这条规则由防护机制落实,而非仅靠自律。 每个制品都归属一个阶段(PHASE_ARTIFACT_OWNERS):state.js register拒绝在所属阶段到达之前注册制品,而forge-guard会检查已写入磁盘的制品(no_premature_artifacts)。曾有一次,在设计仍处于draft状态时写入了architecture.md和十五份计划,十二项检查却全部通过:阶段顺序当时只是一条指示。如果它提示premature_artifact,这不是需要绕过的障碍,而是基础尚未获批的信号。请推进阶段,或在通过关卡后再生成制品。 -
完整性优先于速度。 一份表面连贯却暗藏漏洞的浅薄计划,比一份产出较慢但真正完整的计划更糟。始终要问:“还缺什么?有什么被遗漏了?”
-
系统性地采用多视角分析。 在定稿重要文档(PRD、架构、计划)之前,至少应由两种不同视角进行分析。目的不是说“没问题”,而是找出主视角遗漏的内容。
-
交付物只存放在
.forge中,不得存放在其他位置。 在临时目录中生成的文档就等于丢失。这不是建议,而是由forge-guard.js机械验证的约束。
如何运行脚本
本文档中的命令相对于技能目录,而非项目目录。
脚本不在项目中:它们随技能一起安装
(~/.agents/skills/forge/scripts/、.opencode/skills/forge/scripts/……)。项目
没有 scripts/ 目录。因此,脚本路径相对于项目的命令无法从任何项目中
执行——首次调用时,会因 Cannot find module '<projet>/scripts/state.js' 而失败。
定义一次技能路径,并在所有地方使用它:
# Le dossier de base du skill est communiqué au chargement du skill.
export FORGE=/chemin/vers/skills/forge
node "$FORGE/scripts/state.js" start
由此得出两条规则:
- 当前目录是项目目录,而不是技能目录。脚本通过
process.cwd()解析锚点:如果从技能目录运行,项目锚点就会指向技能仓库——也就是说,指向错误的项目,而且不会给出提示。 - 当当前目录不是项目根目录时,显式传入锚点:
node "$FORGE/scripts/state.js" start /chemin/du/projet。
步骤 0 — 获取实际状态(每次调用时最先执行)
此步骤必须先于其他所有操作——包括读取 state.json,也包括解析锚点。
node "$FORGE/scripts/state.js" start
一条命令即可显示:当前阶段、待处理的门禁、各状态下的切片及计划是否实际存在和测试用例数量、哈希不匹配的文档、未解决的分歧、尚未晋升的发现,以及项目记忆状态(AGENTS.md §Definition of Done、未解决的 ADR、LEARNINGS.md 的篇幅)。
为什么用命令而不是文件。 每次会话都完整阅读会话日志太耗时,最后还会凭记忆重新构建。一个真实项目中的实际后果是:14 个已批准的切片没有任何测试,而跟踪记录却毫无征兆地显示错误信息——因为进度是「根据对话记忆了解的,而不是根据本应作为事实来源的文件了解的」。
如果 start 报告有切片已标记完成但没有测试用例,这并不是新情况:这是第一个可靠信号。继续之前先处理这些切片。
步骤 0 bis — 解析当前项目
在错误的目录中创建 .forge,意味着之后必须手动全面补救。
node "$FORGE/scripts/state.js" anchor
该命令会显示选定的锚点、其来源(existing_state | project_marker | cwd)、是否通过向上遍历解析,以及遍历过的目录链。
如果会话可以访问 Legacy 项目、语料库或参考项目,绝不能将其设为锚点。 应将其声明为只读,且绝不修改:
node "$FORGE/scripts/state.js" init <racine> "<NomProduit>" --reference /chemin/vers/Legacy
解析遵循以下三条规则,按顺序执行:
- 如果某个祖先目录中已有
.forge/state.json,则优先使用它——这表示恢复正在进行中的项目,包括从子目录恢复。 - 如果没有,则检查当前目录中的项目标记(
package.json、pyproject.toml、go.mod、.git……);如果当前目录已有文件,也会进行有限的向上遍历。空目录表示一个新项目:不会向上遍历,否则新项目会以相邻的 monorepo 为锚点。 - 如果以上都不满足,则直接使用当前工作目录。
如果解析出的锚点是已声明的参考项目,该命令会明确报错——即使该 Legacy 项目没有 .forge 也一样;这种情况最危险,也最常见。这是为了防范代价最高的情形:分析 Legacy,然后把新项目的 .forge 写入 Legacy。
状态与恢复
如果 anchor 返回 state_exists: true,请读取 state.json。它会标明最近完成的阶段、每个切片/基础项的状态,以及待处理的关卡。告知用户项目进展到哪一步,并从下一阶段继续——除非用户明确要求,否则绝不重新生成已处于 approved 状态的文档。
如果文件采用 v1 架构,则会被拒绝,不会静默迁移:
node "$FORGE/scripts/state.js" migrate <anchor>
确切格式请参阅 references/state-schema.md。
写入位置——不可妥协的规则
| 内容 | 位置 |
|---|---|
| 所有 Forge 交付物 | <anchor>/.forge/,位于 CANONICAL_LAYOUT 中规定的规范路径 |
| 项目状态 | .forge/state.json——仅包含元数据,绝不包含内容 |
| 审计日志 | .forge/audit/ |
forge-guard.js 会检查以下三项禁令:
- 绝不写到
.forge/之外。 写入临时目录或项目根目录的交付物等同于丢失。 - 绝不在
state.json中写入文档内容。 PRD 应位于.forge/prd.md。在状态文件中放入文本块属于 bug——会通过禁用键和数值长度检测出来。 - 绝不手动在
.md的 front matter 中写入status:。 唯一的写入方是state.js set-status,它会在同一操作中更新状态和 front matter。
工具包脚本不得修改——且此规定经过验证
以上三项禁令保护的是项目交付物。工具包本身此前却没有任何保护:forge-guard.js 检查的是 .forge/、AGENTS.md、.opencode/rules/ 和清单——不包括运行工具包的脚本。而 $FORGE 是由 Agent 设置的 export,因此可以指向任意位置。
因此存在两条绕过路径,且都不会被检测到。我们在一个真实项目中发现:AI 修改了脚本以绕过关卡,而仓库状态——脚本已损坏、缺少必需交付物——直到人工复查时才被发现。这是唯一一个会停用自身保护机制的缺陷,因此也是唯一一个无法自行检测到的缺陷。
node "$FORGE/scripts/forge-guard.js" kit-integrity <anchor>
node "$FORGE/scripts/forge-guard.js" kit-integrity <anchor> --write-manifest
.forge/kit-manifest.json 会记录工具包中每个文件的 sha256 指纹。每次运行时,门禁都会进行比对。两种处理方式刻意区分:
| 发生变化的内容 | 处理方式 | 原因 |
|---|---|---|
| 一个脚本 | 硬性失败 | 脚本负责落实流程。脚本一旦被修改,就意味着流程不再得到落实 |
| 一份参考文档 | 警告 | 文档为 Agent 提供信息,但不会落实任何事项。如果把失败和警告混为一谈,文档更新就会无谓地阻塞项目——届时门禁也会因此被绕过 |
清单必须通过明确操作写入,绝不自动写入。 这是唯一可能掩盖修改的操作:如果门禁能自行重写,就不再能保护任何东西。如果脚本是有意修改的——例如更新工具包——请重写清单,并在 DECISIONS.md 中说明原因。否则,请还原脚本。
补充脚本应有明确归处
当工具包无法满足实际需求时,可以编写脚本。脚本应放在 .forge/tools/ 中,并进行声明:
{ "project": { "tools": { "seed-dwight.js": { "purpose": "…", "owner": "…" } } } }
forge-guard.js tools 会拒绝以下三种情况,且每一种都是独立缺陷:未声明的工具(没人会知道三个月后它的存在)、已声明但未说明用途的工具,以及已声明但磁盘上不存在的工具——登记内容与实际不符的登记表,比没有登记表更糟,因为人们会相信它。
在其他位置编写脚本——例如项目根目录或 .forge/ 中 tools/ 以外的位置——会被标记为放错位置的脚本。这类位置是尚未找到合适归处的脚本默认落点。
哪份内容具有权威性——状态和交付物永远不会不一致
state.json = AUTORITÉ pour le statut
front matter = MIROIR (champ status:), écrit par set-status
如果出现偏差——state.json 写着 implemented,而 .md 仍写着 draft——系统会检测到并自动修正:
node "$FORGE/scripts/forge-guard.js" sync . # détecte, exit 1
node "$FORGE/scripts/forge-guard.js" sync . --fix # réaligne le miroir sur l'autorité
content_hash 针对的是文档的正文,而不是 front matter:因此,更改状态不会使计划失效。哈希不再匹配,表示发生了越界编辑——此时文档会被标记为 stale。
各自负责什么——与 project-rules-architect 的职责边界
两个彼此不了解的 skill 会产生两套互相竞争的记忆系统,且没有优先级规则。这是大多数跟进故障的结构性原因。
| Forge 负责 | project-rules-architect 负责 |
|---|---|
.forge/——正在构建什么、进展如何 | AGENTS.md、.opencode/rules/*.md——需要遵循什么 |
state.json——状态、路径、ID、哈希 | DECISIONS.md——原因 · LEARNINGS.md——发生过什么故障 · SESSION_LOG.md——发生过什么 |
规则:业务或技术事实应保存在由 project-rules-architect 负责的文件中。state.json 只包含指向该文件的引用。包含散文内容的 state.json 不是状态文件,而是伪装成状态文件的文档——forge-guard.js state 会拒绝它。
发现应当路由,而不是堆积:
node "$FORGE/scripts/state.js" finding <anchor> --domain=testing.md --severity=majeur "<fait>" "<correction>"
必须指定领域。 没有领域的发现就没有可提升的目标,因此不会产生任何改变:它只会变成又一条日志,与本应由它提供依据的规则相互竞争。这是经测量确认的零提升原因。
完整约定:references/skill-boundaries.md。
两种模式
| Guided(默认) | Fast Track | |
|---|---|---|
| Gate | 每个阶段一个 | 第 5 阶段结束时一个,第 7 阶段每个里程碑再加一个 |
| 阶段 4-5 | 手动,逐个 slice 进行 | 自动化,由子 Agent 验证 |
| 阶段 7 | 手动 | 每个 slice 均设有可执行门禁 |
| 验证器 | 会话中轮换验证视角 | quality-analyst、red-team 和 plan-validator 并行运行 |
| 启用条件 | 始终可用 | PRD、约定、设计、界面和基准测试均已批准 |
| 退出方式 | — | 随时选择“返回常规模式” |
每次启用时都要选择自主级别:milestone(默认)或 full。详情和理由见 references/fast-track.md § 两种自主级别。
Fast Track 不会取消验证,只会取消重复操作。
各个阶段
按顺序执行。**每个阶段都必须以明确的人类验证 gate 结束——没有得到清晰的“approved”,绝不能开始下一阶段。**这是此 skill 最重要的规则。
阶段未产出应有内容,就不能获批。 complete-phase 和 set-phase … approved 会拒绝缺少交付物的阶段;forge-guard 也会在 gate 前通过 current_phase_has_deliverables 发出提示。拒绝信息会指出缺少的交付物,并提供登记命令。
这项约定不是走形式。检查只会验证已声明的交付物:没有声明就没有检查,结果便会全部显示通过。曾在一次完整测试中发现这种情况——第 0 阶段在 deliverables: {} 且没有 conventions.md 的情况下获批,之后整个流程都建立在这个缺失的基础上继续推进,没有任何检查发出警告。
如何提出 gate 问题。 对于规格文档:“是否遗漏了使用场景,或你已经发现的约束?” 对于拆分方案:“你认可将工作拆分为这些 slices 吗?还是需要合并或拆分其中某些部分?” 对于计划:“实现顺序是否合理?你是否发现缺失的依赖关系?” 只有得到明确的批准用语后才能继续。
每次 gate 前,都要运行防护检查。它们是确定性的、即时的,且不消耗任何 token:
node "$FORGE/scripts/forge-guard.js" all <anchor> # chemins, état, contrat de phase, synchronisation, placeholders, versions
node "$FORGE/scripts/consistency-check.js" all <anchor> # écarts ENTRE artefacts
这里出现 fail 不是建议:请先修正,再提交文档。
为什么有两个命令。 forge-guard 一次只读取一份文档:它会检查文档是否存在、路径是否正确、状态是否一致。它无法发现某个计划与其本应实现的架构相矛盾。consistency-check 只做这件事,而且只有它能做——因为项目中代价最高的问题模式并非规格不完整,而是后续产物揭示了先前已获批准的产物存在缺陷。在一个真实项目中,这种情况出现了 13 次,旁边还写着这句话:“没有任何 gate 检查能发现它。”
声明交付物依赖什么。 已获批准的交付物应由 PRD 中的需求作为依据,而且必须明确写出这种依赖关系:
node "$FORGE/scripts/state.js" register <anchor> deliverable conventions .forge/conventions.md --requires=B11,C1,C2
consistency-check premises 会将这些 ID 与 PRD 的实际状态进行比较,并标记已获批准的交付物仍依赖的已撤回需求。如果没有这项声明,文档就会继续基于 PRD 已放弃的前提保持批准状态:在一次实测中,conventions.md 以“这是对严格多租户需求的回应”为由论证采用 PostgreSQL,而 PRD 却因没有第二个客户端而将多租户排除在范围之外。没有任何检查能发现这一点。
已撤回的需求必须保留其 ID,并列在 ## 9. Hors scope 条目的开头:- **C102** — Multi-tenant strict — raison : …。撤回需求时去掉它的标识符,会让它无法追踪,矛盾也就再次变得无法检测——检查还会拒绝没有 ID 的撤回,因为无法追踪的撤回就等于没有声明撤回。
一个 ID 只能指代一个需求。 如果 C1 在范围外条目中指代“严格多租户”,在约束条目中又指代“仅一台服务器”,那么所有对 C1 的引用都会变得模棱两可——包括这项检查中的引用,它会因此指错交付物。检查会拒绝这种冲突。
如何避免冲突,以及千万不要怎么做。
“把已撤回的需求重新编号到单独的编号范围(B1xx、C1xx)”这种本能做法会破坏可追踪性,必须摒弃:前面的规则要求已撤回的需求保留其 ID,正是为了让已获批准的交付物能够与它关联起来。把 B18 改名为 B118 会切断这条关联——检查将不再指认正确的交付物,而会指向一个从未有人写过的 ID。
正确做法是在上游遵循一条规则:
将已撤回的需求编号放在编号范围的末尾,从已使用的最大编号开始,永远不要重新分配已空出的编号。
也就是说,撤回 B18、B19、B20、B21 后,下一个有效需求就是 B22。已撤回的编号仍以原始 ID 保留在第 § 9 节,并且 18–21 这个编号段标记为已作废。这正是冲突检查所验证的内容,因此没有商量的余地。
这种规范是有代价的——编号会增长得更快——但这是值得的取舍:编号中的空缺一眼可见,ID 冲突却要等到产生错误诊断后才会被发现。
conventions.md 是最常见的情况:它是一份持续更新的文档,PRD 修订会要求相应修改。请重新修订它,将状态改为 stale,然后再改为 approved,并重新运行 consistency-check premises。
各阶段的分工
本表具有规范性。 它说明了编写各阶段交付物时应读取哪个 Agent 文件。没有这张表,就只能猜文件名——而猜测会生成不存在的文件,且文件缺失永远不会导致失败。
在测试项目中连续两次发现了这个问题:Phase 4 使用 agents/solution-architect.md(实际文件名是 systems-architect.md),Phase 5 使用 agents/plan-writer.md(该文件不存在)。两种情况下,调用都看似成功:子 Agent 确实生成了交付物,并依据 SKILL.md § 5 开展工作,同时指出文件缺失。绕过错误指令的 Agent 不会让缺陷显现出来,反而会把缺陷掩盖起来。
| 阶段 | 交付物 | 要读取的 Agent | 验证方式 |
|---|---|---|---|
| 1 | .forge/prd.md | agents/product-analyst.md | forge-guard placeholders、client-liaison --check |
| 2 | .forge/roadmap.md | agents/scope-architect.md | consistency-check premises |
| 3 | .forge/design/ | agents/ux-designer.md | design-check contrast、design-check tokens-used |
| 4 | .forge/architecture.md | agents/systems-architect.md | ddl-exec all、dependency-check |
| 5 | .forge/plans/ | 由你自己编写,遵循 SKILL.md § Phase 5 和 templates/implementation-plan.md.tmpl | coverage-check slice、forge-guard placeholders |
| 6 | .forge/test-plan.md | agents/quality-analyst.md | consistency-check plans |
Phase 5 没有负责编写的 Agent,这是刻意安排的。 实施计划是最容易凭空编写的东西:描述尚未编写的代码的文档,很容易通过所有格式检查。因此没有人可以代写——只有 agents/plan-validator.md,它会审阅已经写好的计划,但不会重写任何内容。
premise-challenger.md 会在 Phase 1 的两个时点额外介入:在初步构想的访谈进行到一半时,以及 PRD 完成时。它不会重写任何内容,只会指出问题,由你来处理。
validate-repo 会拒绝磁盘上存在但此处未列出的 Agent 文件,也会拒绝此处列出但磁盘上不存在的 Agent 文件。因此,本表不会自行失去同步。
Phase 0 — 初始化
目标:在进行任何产品构思之前,明确项目背景并生成约定基线。
- 解析 anchor(
state.js anchor)——这是步骤 0,已完成。 - 如果 anchor 中已有项目,请读取其配置文件:
package.json、tsconfig.json、.opencode/、AGENTS.md、规则、ADR。提取其中隐含的约定(lint、格式、目录结构、技术栈、测试框架)。 - 如果项目尚不存在,请询问用户:
- 计划采用的技术栈(语言、框架、数据库……)
- 技术或托管限制
- 必须使用或禁止使用的工具
- 创建
.forge/:node "$FORGE/scripts/state.js" init <anchor> "<Nom>" --reference <projet de référence si applicable>。 - 以“背景基线”模式调用
project-rules-architect——参见 § 两次调用。只需交付以下文件:放在 anchor 根目录下的AGENTS.md、SESSION_LOG.md、DECISIONS.md、LEARNINGS.md。 - 根据
templates/conventions.md.tmpl生成.forge/conventions.md。尚未确定的部分(例如状态管理、E2E 框架)标记为À DÉCIDER EN PHASE 4。 - 注册交付物:
state.js register <anchor> deliverable conventions .forge/conventions.md。 - 根据
templates/contract.md.tmpl生成.forge/contract.md,使用client-liaison --check检查,修正其指出的问题,并让相关方签字确认:node "$FORGE/scripts/state.js" register <anchor> deliverable contract .forge/contract.md node "$FORGE/scripts/state.js" set-status <anchor> deliverable contract approved - 向用户总结检测到的内容,并请求确认。
在明确这些背景之前,绝不要开始讨论产品。 技术选择会限制产品可能性,反之亦然。
签约后,只有两件事会再打断你
这是合同的承诺,而且并非象征性的:所有涉及采购的事项都在签约前决定,否则合同会被 forge-guard contract 拒绝。因此签约后:
| 原因 | 方式 |
|---|---|
| 与合同存在偏差 | state.js client --kind=ecart … |
| 由你负责的决定 | state.js client --kind=decision … |
四个字段都是必填项——what、price、by、if_no_answer,命令会拒绝缺少这些字段的事项。没有截止日期的决定不会一直搁置:它必须得到决定,而决定者是 Forge。超过日期后,Forge 会执行「未回复」条款,并在下一次总结时告知你。
上下文基础不包含任何规则。 在第 1 次调用和第 2 次调用之间,项目有记忆,但没有规则集:这是正常状态,并非只完成了一半的工作。如果第 1 次调用返回了
AGENTS.md或.opencode/rules/,说明 scaffold 模式被绕过了——它在技术栈探测之前就停止了。
对 project-rules-architect 的两次调用
Forge 是调用方,会在两个固定时间点调用。绝不会是被调用方。
| 调用 | 时间 | 你传递 | 你获取 |
|---|---|---|---|
| 1 — 上下文基础 | 第 0 阶段,第 5 步 | 产品名称、用户已经说明的内容 | 四个记忆文件,已就位 |
| 2 — 规则集 | architecture 为 approved 时 | 已确定的技术栈、选定的约定、MVP 范围 | AGENTS.md + 规则,已接入 |
调用 1 — 上下文基础
调用 project-rules-architect,并明确要求使用 scaffold 模式:
「为这个项目搭建上下文结构:
AGENTS.md、SESSION_LOG.md、
DECISIONS.md、LEARNINGS.md。不包含任何规则,不创建AGENTS.md,不进行技术栈探测——技术栈尚未确定。」
应该返回:anchor 根目录下的四个文件,包含各自的标题,除此之外不应有任何内容。返回结果中包含规则,就说明结果有误。
调用 2 — 规则集
当 architecture 变为 approved 时,而不是之前:
“以下是已确定的技术栈和本项目的范围。请建立规则集, 并将其接入目标工具。”
从 .forge/architecture.md 和 .forge/conventions.md 中传递:技术栈及其确切版本、已选定的约定、范围,以及不应转化为规则的未决问题。
传递摘录,而不是整个文件。 这两份文档可能有数千行,而决定规则的部分始终只占其中一小部分。结构化摘要——技术栈表、库的选择、未决问题——既比完整文件更精简,也比走马观花地读完整文件更可靠。规则:传递的一项事实占一行,而不是一章。
为什么不能提前。 规则是依据技术栈生成的。在技术栈确定之前生成规则,就是猜测——而猜出的规则有规则的权威性,却只有假设的可靠性,因此 Agent 会照做。
这次调用有一道门槛,而不只是一个时间点。 在 architecture approved 之前,它尚未到执行时机;之后若仍未执行,则属于 forge-guard 会报告的缺陷:
node "$FORGE/scripts/forge-guard.js" rules-present <anchor>
如果规则目录不存在、为空,或目录存在但未接入,检查就会失败——因为四个无人加载的 Markdown 文件,看起来是完整的规则集,实际上却完全不起作用。这正是之前缺失的检查:调用 2 有记录、有日期、有条件,却从未触发。在实验室中进度相同的五个项目里,只有一个有规则集,而且没有任何提示指出这一点。
继续之前,请验证结果:
node "$PRA/scripts/rules-selftest.js" <anchor>
对交付的规则集进行十项检查:接入、索引、占位符、交叉引用、相互矛盾的阈值、.forge/ 耦合、污染、无法验证的说明、门槛、预算。此处失败属于交付缺陷,不是讨论事项。
Forge 对这些文件绝不会做的事
| ❌ 绝不 | ✅ 应改为 |
|---|---|
写入 AGENTS.md、SESSION_LOG.md、DECISIONS.md、LEARNINGS.md | 什么也不做。这些是 Agent 的记忆,由它自己维护。 |
创建自己的 AGENTS.md 或 .opencode/rules/ | 由调用 2 生成规则集。 |
将规则复制到 conventions.md | 将技术栈事实传递给调用 2。 |
由两个写入者共同写入的记忆会无声无息地丢失数据:一个添加内容,另一个覆盖,而文件仍然存在,看起来也合情合理。这就是这份约定存在的原因,而不是为了讲究整洁。
记忆的实际状态:state.js start 会在 project_memory 中报告该状态。
conventions.md 是一份持续更新的文档。 它从 Phase 0 已知的内容开始,在 Phase 4(架构:验证库、状态管理的选择)中逐步补充,也可以随时修订。实施计划(Phase 5)会引用它;之后对 conventions.md 的任何修改都会使依赖它的计划失效——每次修订后都要运行 state.js check-stale。
修订契约——只扩展,绝不重新编号
其他文档按编号引用的文档不得重新编号:必须对其进行扩展。在 § 5.9 插入内容会导致 § 5.10、§ 5.11 以及后续所有章节的编号顺延——于是每个交叉引用仍然指向一个存在的章节,却指错了位置。这是最糟糕的漂移形式:它能解析成功,检查会判定一切正常,也没有任何提示。
已发现,INC-011:修订两项关键根本原因时,在 § 5.9 和 § 5.10 插入了两个 endpoints。八份计划中的十七处交叉引用因此失效——error-handling(4)、restriction-lignes(3)、journal-acces(4)、export-provenance(4)——却没有任何一行指出这一点。安全的修复方式是将两个 endpoints 添加到 § 5 的末尾。
不要编辑已批准的文档。要修订它:
node "$FORGE/scripts/state.js" amend <anchor> <clé> \
--reason "<pourquoi cet amendement existe>" \
[--changes <fichier-listant-ce-qui-change>]
这条命令的作用,以及每一项存在的原因:
必须提供 --reason | 没有理由的修订就是普通编辑。说明理由正是修订与编辑的区别。 |
| 标题映射 | 它在批准时捕获——这就是其他文档引用的版本。没有它,第一次修订就可能随意重新编号。 |
| 重新编号 → 拒绝 | 某个编号对应了不同主题,或对应章节已消失时,命令会拒绝执行,并按顺序指出漂移。警告可以被忽略;拒绝会迫使你采取行动。 |
--allow-renumber | 它不是一个开关:必须同时提供 --renumber-reason <texte>,而且该理由会保留在状态中,与失效编号一并记录。没人记得原因时,这是唯一留下的记录。 |
状态 → stale | 修订后的文档已不再是获批的版本。使用 stale 而非 draft:这是已为动态文档定义的流程——它会在 gate 重新通过 approved。 |
命令拒绝时会告诉你该怎么做:
Un document cité par numéro s'étend, il ne se renumérote pas.
Corrige sans risque : ajouter les sections NOUVELLES en fin de numérotation,
et ne toucher à aucun numéro existant.
交叉引用必须指明目标。 单独写 § 5.15,无法说明它指的是哪份文档。写成 `architecture.md` § 5.15:这样检查就能准确知道该查看哪里,无需进行任何解释。consistency-check references 会给出两种判定:
- 失效指针——已指明目标,但章节不存在 → 失败。这是编号漂移,也就是 INC-011 的形式;
- 目标未声明——未带文件名的交叉引用 → 计数,但绝不判为失败。在测试项目中:276。若让这些情况失败,就会产生一种一周后就会被关闭的检查——这个项目中已经发生过四次。它的解决方法已写在输出中:为文件命名,计数就会下降。
Phase 1 — 发现阶段(PRD)
目标:将模糊的想法转化为完整且一致的产品需求文档。
这不是写作阶段。 这是访谈和逐步完善的阶段。PRD 是产出,而不是过程。
premise-challenger 在本阶段会介入两次:一次在访谈进行到一半时,针对最初的想法;另一次在最后,针对 PRD。它不会改写任何内容:只会指出问题,由你来处理。参见 agents/premise-challenger.md。
1.1 初始访谈
逐步提问,每次一到两个问题。不要向用户连珠炮似地提问。需要涵盖以下类别(按顺序):
- 问题:这个产品要解决什么问题?面向谁?为什么是现在?
- 用户:用户是谁?有哪些细分群体?技能水平如何?使用场景是什么?
- 解决方案:产品如何解决这个问题?价值主张是什么?
- 功能:主要功能有哪些?次要功能有哪些?
- 约束:是否存在法律、技术、预算或时间方面的约束?
- 现有产品:是否有竞争对手?是否有类似产品?这个产品有什么不同?
- 风险:预期有哪些风险?有哪些未知因素?
- 成功:如何判断产品是否成功?
1.2 质疑与深入探究
完成初次访谈后,进一步质疑回答:
- 发现矛盾:“你说产品应该简单,但功能 X 很复杂——如何兼顾两者?”
- 找出隐含问题:“你没有提到错误处理——产品是否需要处理失败情况?”
- 测试边界:“如果用户在状态 Y 下执行 X,会发生什么?”
- 质疑必要性:“这项功能可能要花 40% 的工作量,却只占 5% 的使用量——它真的有必要吗?”
- 指出遗漏:“我没有看到密码恢复机制——这是有意为之吗?”
- 找出依赖关系:“要让功能 A 正常工作,必须先有 B、C 和 D——这个顺序你觉得合适吗?”
- 提出替代方案:“与其在 V1 中实现复杂的角色系统,不如只用一个简单的管理员/用户标记,够用吗?”
1.3 编写 PRD
回答成熟后,根据 templates/prd.md.tmpl 在 .forge/prd.md 中编写 PRD。绝不能写入 state.json,也不能写在其他位置。
规则:
- 每条业务规则都必须有一个稳定 ID(B1、B2……)。
- 每个边缘情况都必须有一个稳定 ID(E1、E2……)。
- 每项约束都必须有一个稳定 ID(C1、C2……)。
- ID 一经确定即为最终版本——绝不能重复使用。
- 用户故事必须编号并标明优先级。
- PRD 不包含实现层面的技术术语(框架、数据库……)——它是一份纯产品文档。
- 已发现但尚未解决的所有歧义都应放入“待澄清事项”一节。
然后:state.js register、forge-guard.js placeholders,之后才能进行 gate。
1.4 多视角评审
最终 gate 前,应用视角轮换——PRD 的这一阶段为必做项:
- 质量视角:是否识别了所有类型的用户(包括管理员、支持人员)?用户故事是否涵盖所有用例?是否涵盖了非功能性约束?
- 风险视角:用户故事之间是否存在矛盾?是否有未明确说明的隐含业务规则?是否有未经验证的假设?
根据发现的问题修正 PRD,然后再提交评审。
1.5 调研——不要重复造轮子
确定 PRD 前,应用 references/research-protocol.md:
- 识别原型类型(
references/archetypes.md)。 - 查找并阅读至少两个参考产品。将结果记录在
.forge/benchmarks.md中——不要写入state.json。 - 针对 PRD 中的每个业务问题,提取其不变量(绝不能为假的属性),而不是代码。
- 阅读该原型类型的常见病灶(
archetypes.md第 9 节),并逐一思考:我们的设计做得更好吗?如何证明? - 有意为之的差异应记录在
benchmarks.md第 5 节,并注明其可逆转成本。
如果调研没有改变任何决策,那就没有产出。如果确实如此,应如实说明,而不是填满文档。
1.6 GATE
提交完整 PRD。Gate 检查清单见 references/review-checklists.md#prd。
阶段 2 — 范围(路线图)
目标:定义每个版本包含哪些内容,以及原因。
2.1 范围分析
- 重看 PRD,列出所有功能/用户故事。
- 针对每项功能评估:用户价值、复杂度、依赖关系、风险。
- 确定 MVP:解决核心问题且可供真实用户使用的最小功能集合。
- 定义 V1:在 MVP 基础上,加入能带来差异化但不会让范围失控的功能。
- 将所有“锦上添花”或依赖用户反馈的内容推迟到 V2 及之后。
2.2 拆分依据
对于每个版本,说明:
- 为什么包含这些功能。
- 为什么推迟其他功能。
- 做出了哪些权衡。
- 承担了哪些风险。
2.3 路线图
根据 templates/roadmap.md.tmpl 生成 .forge/roadmap.md。绝不写入 state.json。
每个版本都包含:
- 带有 ID(B*)的功能
- 成功标准
- 版本间依赖关系
- 工作量估算(相对估算,不按天计算)
- 此版本的特定风险
2.4 多视角审查
在 gate 之前,应用视角轮换:
- 质量视角:是否全面列出了各版本的风险?是否有未明确说明的跨版本依赖?
- 风险视角:MVP 是否真正解决了主要问题?哪些被推迟的功能可能会阻碍真实用户?
2.5 GATE
展示路线图。Gate 检查清单(references/review-checklists.md#roadmap)。
阶段 3 — 设计(UI/UX)
目标:在实现功能之前设计界面,明确视觉方向,并根据真实使用频率确定导航优先级。
本阶段的顺序至关重要。不要跳过步骤。
3.1 视觉方向和标准——先于任何设计
在完成以下两份文档之前,不得开始绘制界面。
- 识别应用原型(
references/archetypes.md),并用一句话写出工作循环。将其记录在state.json(product.archetype)中。 - 根据情境调用适用的设计技能——这是必需步骤,参见
references/design-quality.md§ 2(移动端 →imagegen-frontend-mobile,落地页 →frontend-design,密集型 Web 应用 →impeccable……)。如果没有可用技能,至少应用 § 3 中的禁忌,并在审计中注明。 - 确定三个锚点:参考对象、氛围(三个词)、反面参考。缺少这些内容,阶段 3 就尚未完成。
- 根据
templates/benchmarks.md.tmpl生成.forge/benchmarks.md:参考产品、原型符合性检查表、已接受的偏差。此文档将作为 Fast Track 验证器的参考依据。
3.2 按使用频率确定导航优先级
导航项的顺序体现了优先级,这是移动应用设计中最常见的错误。
应用 references/module-prioritization.md:
- 为每个模块评分:频率(1–5)× 中心性(1–5),并说明理由。
- 排序:先放主要循环,再放重复性操作,然后是生命周期入口,最后是配置。
- 主要导航项最多 5 个——其余放入溢出菜单(“更多”)。
- “首页”不默认排第一:只有当它用于开启循环,或是使用频率最高时,才排在第一位。
导航顺序应可验证:
node "$FORGE/scripts/state.js" set-nav <anchor> '{ "archetype": "...", "core_loop": "...", "items": [ ... ] }'
3.3 设计系统
-
定义具有具体值的设计令牌——绝不要写「稍后定义」。
-
定义基础组件:按钮、输入框、模态框、卡片、表格等。
-
定义导航模式:路由、面包屑、侧边栏、导航栏、条目顺序(参见 3.2)。
-
遵守
references/design-quality.md§ 3 中的禁忌:不要使用未明确选择的纯白色,不要默认用阴影作为分隔,不要使用默认调色板,不要使用统一的字体比例尺。 -
从
templates/design-system.md.tmpl生成.forge/design/design-system.md。 -
在设计系统中声明颜色类别(模板的 § 0.0)。然后:测量对比度——不要填写对比度。 检查清单要求填写「对比度 N:1」,但此前没有任何工具验证它:因此这些比例只是写出来的,而非计算得出的。
声明并非形式上的要求。通过名称猜测颜色类别的检查无法处理名称所用语言之外的语言:历史信号都是英文字面量(
--color-text-*、--color-ink-50、*-subtle),而此技能生成的所有内容都是法语。对于法语词汇,所有颜色都会被归为「非文本组件」,并按 3:1 的标准评估——因此 3.80:1 的文本也能通过。这个检查本来就是为了找出这种缺陷,结果缺陷又出现在刚刚测量过的文档里。on:表示文本实际放置在哪些背景上——否则,反转色文本明明只放在墨色背景上,却会拿来与纸色背景对比,必然无法通过。exempt:需要填写理由:装饰性色调并非界面组件。未列入清单的颜色令牌会被标记:声明是一种承诺,因此省略也是一种选择。node "$FORGE/scripts/design-check.js" contrast <anchor> node "$FORGE/scripts/design-check.js" tokens <anchor>这项检查能捕捉两种校对时看不到的问题:标注的比例与测量结果不符——这是毫无依据的保证;以及文本在某种背景上清晰可读,却在另一种表面上过浅,例如表格的交替行或凹陷面板。问题往往就出在这里。
阈值依据 WCAG:文本与所有表面的对比度为 4.5:1(1.4.3),非文本组件(包括焦点环)的对比度为 3:1(1.4.11)。输出中会显示每个令牌的类别(文本、组件、填充、豁免),并根据其声明、用途和名称推断:如果检查没有说明令牌为何被归入该类别,就无法对其提出质疑。
3.4 屏幕与流程
对于 PRD 中每个带有用户界面的功能:
- 列出所有必要的屏幕,并为每个屏幕标明其导航层级。
- 在
.forge/design/screens/<nom>.md中为每个屏幕创建一个文件,并从templates/screen.md.tmpl生成。 - 模板要求填写 9 种状态、每个屏幕的视觉方向、交互、各断点下的响应式行为、无障碍设计和可追溯性。务必完整填写——残留的
{{PLACEHOLDER}}意味着该部分不会被实现。 - 定义屏幕之间的导航流程(主路径、替代路径、错误、引导流程)。
然后:
node "$FORGE/scripts/forge-guard.js" placeholders <anchor>
node "$FORGE/scripts/design-check.js" contrast <anchor>
node "$FORGE/scripts/design-check.js" component-parity <anchor>
引用了令牌的屏幕,必须引用一个确实存在且可读的值。后者无法通过重读屏幕来确认:必须进行测量。
渲染组件的屏幕必须了解其表面。组件增加插槽或状态时,将其同步到所有渲染该组件的屏幕,并非礼貌之举,而是确保同一组件始终以相同方式渲染的必要条件。
component-parity能捕捉到忘记同步后出现的问题,例如条目列表变得不准确(有 7 个插槽却写成「6 个插槽」)。如果屏幕选择不渲染某种状态,则应注明理由:`Tile` — exempt: `offline`(表格处于在线状态)。
3.5 验证设计
- 检查 PRD 中的每条业务规则(B*)是否都有对应的屏幕或流程。
- 检查每种错误状态(E*)是否都有视觉呈现。
- 检查所有屏幕之间的视觉一致性。
- 如果已有代码:使用 Chrome MCP 检查界面(溢出、响应式、布局、导航)。
3.6 多视角审查
在 gate 前,应用视角轮换:
- 质量视角:每种边缘情况都有视觉状态吗?是否考虑了无障碍访问?响应式设计是否覆盖所有断点?
- 风险视角:屏幕之间是否存在视觉不一致?是否有未处理的错误状态?
3.7 GATE
展示标准、优先级排序后的导航、设计系统和屏幕。用户在进入架构阶段前进行视觉验收。Gate 检查清单(references/review-checklists.md#design)。
Phase 4 — 架构(系统设计)
目标:将产品拆分为切片、模块和基础能力,并明确它们的依赖关系。
4.1 切片拆分
- 列出 PRD 中的每项功能。
- 将功能归组为模块(技术上连贯的分组)。模块的顺序和分组遵循
references/module-prioritization.md——优先考虑频率,绝不按领域组织结构排序。 - 将每个模块拆分为切片(可独立实现的端到端功能)。
- 确定横向基础能力(Phase 3 的设计系统、身份验证、错误处理、国际化、配置、日志记录、API 客户端)。
拆分规则:
- 一个切片应能独立实现和测试(或使用其依赖项的模拟对象进行测试)。
- 一个切片新增的文件不应超过约 10 个。
- 如果一个切片过大,说明它包含多个不同的功能。
- 如果两个切片有 50% 以上的代码相同,可考虑将它们合并。
4.2 数据模型
为每个切片定义:
- 实体及其字段(类型、约束、关系)。
- 验证模式。
- API 契约(端点、请求、响应、错误)。
规则:所有模型都必须逐字段定义,不能概述。此阶段遗漏字段会导致实现阶段出现错误。
4.3 依赖关系图
- 逐个切片声明依赖关系图:
node "$FORGE/scripts/state.js" dep <anchor> <slice|fondation> <a,b,c>state.js dep会拒绝对不存在切片的依赖、自依赖,以及任何会形成循环的依赖。错误的依赖关系图与不完整的依赖关系图无法区分:失效的依赖永远无法满足,之后也不会有任何提示。 - 运行
node "$FORGE/scripts/dependency-check.js" check <anchor> --write,计算depended_on_by和impl_wave。 - 找出循环依赖、拓扑顺序,以及可以并行开发的切片。
如果你的波次计划比最低要求更细,请声明该计划。 dependency-check 会计算最少的拓扑波次。更细的排期计划是合理的——两个人不可能同时负责 RLS 策略和差值公式——但必须写入架构的 front matter:
impl_waves: 13
impl_waves_rationale: >-
Plan d'ordonnancement, pas minimum topologique. Le graphe se réduit à 8 vagues ;
on en retient 13 parce que F4 et F9 ne doivent pas être portées par la même personne.
如果不作声明,writeBack 会在不作提示的情况下覆盖 impl_wave,导致 Phase 4 的两份文档相互矛盾,而 CI 却显示通过。声明但没有理由,差异将不予通过:没有理由的计划与计数错误无法区分。说明理由后,该差异会作为警告保留。
4.4 生成架构文档
根据 templates/architecture.md.tmpl 生成 .forge/architecture.md。
4.5 DDL 要么执行,要么就不该写
**文档中的 DDL 不会经过编译、类型检查或执行。**它只会被阅读。因此,只有在编写时,也就是作者重读自己刚写的内容时,才能发现其中的缺陷。
在一次真实测试中,三个这样的缺陷通过了三道 gate,且重读时一个也看不出来:
ALTER TABLE … ADD CONSTRAINT … CHECK (… <> (SELECT … FROM …))— 一个包含子查询的CHECK。PostgreSQL 会在创建时拒绝它,因为CHECK必须仅根据当前行进行求值。该约束并不存在。- 在触发器开头写入
IF NEW.status = OLD.status THEN RETURN NEW; END IF;— 只有在状态发生转换时才会触发该守卫。写入其他列的UPDATE会绕过它。这道门虽然写了、注释了,却不起作用。 - 一个触发器要求存在的
published_at,却没有任何代码生成它。
在 gate 之前运行:
node "$FORGE/scripts/ddl-exec.js" all <anchor>
三种判定,各有不同:
| 命令 | 检查内容 | 引擎 |
|---|---|---|
completeness | DDL 修改的每张表都已创建,或以列清单表格的形式列出。没有表被凭空使用。 | 无 |
execute | PostgreSQL 接受每条语句。被它拒绝的约束并不存在。 | pglite |
guards | 文档声明的每个守卫都确实会拒绝被禁止的操作。 | pglite |
声明你的守卫。首行是 -- forge:ddl-refuse 的 sql 代码块包含一条必须被拒绝的语句。如果它执行成功,检查会指出这一点——而它说的是事实,因为执行语句的是 PostgreSQL,而不是阅读者:
-- forge:ddl-refuse
-- Publier sans signature doit être refusé. Si cette instruction passe, la
-- porte n'est pas une porte.
UPDATE definition_version SET status = 'published' WHERE definition_version_id = 1;
被禁止操作的名称不是由检查猜出来的:是文档明确写出的。这就是有效检查与猜测式检查的区别——任何需要推断的检查都会产生噪声。
未声明的守卫不会经过测试:无论是脚本、审阅者,还是守卫本身,都不会测试它。对于未声明任何守卫的架构,guards 会返回 pass,并给出 guards_declared: 0,同时明确说明这一点——因为检查若不说明自己没有找到什么,就会让空缺蒙混过关。
引擎是可选的。没有 pglite 时,execute 和 guards 会返回 skipped,并给出安装命令;它们绝不会在未执行的情况下返回 pass。completeness 仍然可用:它不需要引擎,只需要文档。
4.6 多视角审阅
在 gate 之前,应用视角轮换——这是架构审阅的必备步骤:
- 质量视角:数据模型是否逐字段完整?每个 endpoint 是否列出所有错误代码?各个 slice 是否涵盖 PRD 中的全部用户故事?
- 风险视角:是否存在依赖循环?是否有入站依赖过多的 slice?是否存在缺乏依据的架构决策?
添加标准合规性检查:plan-validator 会将架构与 .forge/benchmarks.md 和架构类型(references/archetypes.md)进行比较。
4.7 GATE
Gate 检查清单(references/review-checklists.md#architecture)。
阶段 5 — 按 slice 制定实施计划
目标:生成一份足够精确的实施计划,让能力较弱的 AI 也不会出错。
每次处理一个 slice。Guided 模式下,每个 slice 之后都要经过一次 gate。Fast Track 模式下,使用 references/fast-track.md 中的自动验证循环。
5.1 数据契约(代码)
使用目标技术栈的语法生成实际代码:
- 验证模式(Zod、Pydantic、Dart 类等)。
- 类型和接口。
- API 契约(请求/响应类型)。
不可妥协的规则:代码中的每个字段都必须对应架构(阶段 4)中定义的字段。不得自行添加字段。
5.2 关键算法
对于包含多个条件分支或多个步骤的每条业务规则(B*),编写伪代码或实际代码。不要用散文改述。
5.3 组件计划
- 组件树。
- 每个组件的 Props、state、事件。
- 状态处理(loading、empty、error、success、边缘情况)。
5.4 状态管理(state management)
- 哪些数据是全局的,哪些是本地的。
- 每项数据的存储机制。
- 组件之间的数据流。
5.5 需要避免的陷阱
预判最可能出现的误解。每个陷阱都要关联到一个具体的 B*/E* ID,并明确对比表述:"不要将 X 与 Y 混淆——正确行为是 Z(参见 B12)。"
5.6 任务清单
按阶段排列的具体清单:
- 数据层(架构、类型、API 客户端)。
- 业务逻辑(算法、服务、状态管理)。
- 用户界面(组件、屏幕、表单、导航)。
- 集成(权限、功能标记、路由)。
- 单元测试。
- 组件测试。
- 集成测试 / E2E 测试。
- 润色(无障碍、响应式、动画、错误)。
5.7 验收标准
每条标准都可单独验证,并关联到一个 B*/E*/C* ID。
5.8 测试计划
对于此切片,仅列出特定内容:
- 涵盖的 B*/E*/C* ID,以及各自的测试类型。
- 此切片特有的 E2E 场景。
- 此切片各屏幕的 Chrome MCP 验证项。
通用框架(测试框架、模式、覆盖率规则)在全局测试计划(.forge/test-plan.md,于 Phase 6 生成)中定义。不要在此重复。
5.9 覆盖率验证
在 gate 前运行:node "$FORGE/scripts/coverage-check.js" slice <anchor> <slice>,然后运行 node "$FORGE/scripts/forge-guard.js" placeholders <anchor>。
pass: false = 返回并补全计划。脚本会检查:
- PRD 中的每个 B*/E*/C* ID 在计划中都有对应项。
- 每个必需章节都存在且内容非空。
- 不存在残留的
{{PLACEHOLDER}}。
5.10 GATE
Gate 检查清单(references/review-checklists.md#implementation-plan)。
Phase 6 — 验证(全局测试计划)
目标:定义全局测试策略并配置测试环境。
6.1 测试配置
- 安装/初始化测试框架(Jest、Vitest、Pytest 等)。
- 安装/初始化 E2E 工具(Playwright、Cypress 等)。
- 配置 Chrome MCP 以进行 UI 验证。
6.2 基础测试
对于每项基础功能,在实现各切片之前编写测试:
- 设计系统:基础组件的渲染测试。
- Auth:身份验证流程测试。
- 错误处理:错误情况下的行为测试。
- i18n:翻译是否存在的测试。
- API 客户端:拦截器、重试、超时测试。
6.3 回归计划
定义每次合并前必须通过的回归测试套件。
6.4 GATE
Gate 检查清单(references/review-checklists.md#validation)。
Phase 7 — 实现
对于计划已获批准的每个切片:
- 确认所有依赖项均已实现(或已模拟):
node "$FORGE/scripts/state.js" check-stale <anchor> <slice>。 - 首先阅读该切片的实现计划和约定(
.forge/conventions.md)。如果计划对与另一个切片的交互有歧义,只查阅架构中相关的章节,不要通读整个架构。 - 按照任务清单实现,并严格遵守文档中记录的数据契约、算法和注意事项。
- 在适用时,先编写测试(TDD);否则,在实现每一层后立即编写测试。
- 验证每项验收标准。
- 执行退出标准——这是一个关卡,不是检查清单:
它会运行项目的真实命令,并检查切片是否包含测试用例,而不只是测试文件。“测试存在”意味着“至少有一个用例”——此前批准 14 个切片却没有任何测试,正是因为缺少了这一区分。node "$FORGE/scripts/forge-exit.js" <anchor> <slice> - 运行 Chrome MCP 检查:溢出、响应式布局、导航、错误状态。
- 将发现的问题分配到相应领域——绝不允许没有目标的问题:
node "$FORGE/scripts/state.js" finding <anchor> --domain=<règle visée> --severity=<s> "<fait>" "<correction>" - 运行
node "$FORGE/scripts/consistency-check.js" all <anchor>——该切片不得出现在差异项中。 - 更新状态:
state.js set-status <anchor> slice <slice> implemented,验证通过后再设为validated。 - 每完成一个切片后都要执行 GATE。
规则:当前切片未完成全部测试和验证前,绝不能开始下一个切片。
在 Fast Track 下,步骤 1-9 不会中断:实现工作持续推进,并可按需生成一份里程碑报告(3 至 5 个切片)。报告会明确区分哪些内容经过了机械化验证,哪些没有。
如果领域涉及到期时间——例如租金、订阅、期限——则完整周期场景必须纳入引入该生命周期的切片的退出标准,而不是最后一个切片。参见 references/scenario-tests.md。
Phase 8 — 最终验证
- 运行完整回归测试套件。
- 确认 PRD 中的所有验收标准均已满足。
- 最后对整个项目再次进行视角轮换(质量视角 + 风险视角)。
- 运行
node "$FORGE/scripts/forge-guard.js" all <anchor>。 - 更新
state.json:将项目状态设为validated。 - 关闭事件日志(
.forge/audit/issues.md),并生成项目审计报告。
变更管理与影响分析
每项变更都可能产生影响。
当用户要求修改(功能、规则、界面、架构……)时,绝不能在未进行影响分析的情况下立即应用变更。
影响分析流程
应用变更前,遵循 references/impact-protocol.md 中的流程。向用户总结:
- 受影响的功能:哪些业务规则(B*)会被修改、新增或删除?
- 受影响的界面:需要修改哪些屏幕?
- 受影响的模块/切片:需要调整哪些切片?
- 受影响的依赖项:还有哪些切片依赖变更内容?
- 需要修改的测试:哪些现有测试会失效?
- 需要更新的文档:PRD、架构、计划、路线图?
- 风险:哪些内容可能在不知不觉中失效?
- 工作量:影响程度的相对估算(局部 / 中等 / 重大 / 结构性)。
用户必须明确确认接受这些影响后,才能应用变更。
应用变更后
- 更新源文档(PRD、架构、设计等)。
- 将影响传递到所有受影响的文档(计划、roadmap、测试)。
- 将受影响的文档标记为
stale:state.js set-status <anchor> <kind> <clé> stale。 - 对相关切片运行
state.js check-stale。 - 检查整体一致性:
forge-guard.js all。 - 报告所有变得不一致的内容。
多视角——两种验证模式
重要文档不会只经过一次审查就定稿。根据所用模式,有两种验证机制。
Guided 模式——视角轮换(默认)
在主会话中,以两种明确的视角对文档进行两次审查:
- 质量视角:缺失的边界情况、没有对应测试的规则、未涵盖的非功能性约束。
- 风险视角:内部矛盾、未经验证的假设、隐式依赖、盲点。
然后进行修正,再展示结果:“我已从质量和风险角度审查了这份文档。以下是我发现并修正的问题:[列表]。以下是仍需决定的事项:[列表]。”
何时应用:PRD(阶段 1)、架构(阶段 4)和最终验证(阶段 8)的关卡之前必须应用;建议用于 Roadmap、设计和计划。
为何在会话中进行,而不是使用子 Agent:视角轮换可以立即完成,不会产生额外的大模型调用,并能确保会话刚刚生成的文档接受同样严格的审查。对于大多数项目而言,在每个关卡编排 Agent 并不能带来成比例的额外收益。
Fast Track 模式——专用子 Agent(自动)
当方向已经过验证(PRD、规范、设计、屏幕、基准测试均已获批)时,手动验证 15 份计划既费力,也容易导致礼节性批准。此时,Fast Track 会并行委派给盲点互补的专用 Agent进行验证:
| Agent | 查找…… | 问题 |
|---|---|---|
quality-analyst | 缺失的内容 | “这份规范完整吗?” |
red-team | 错误的内容 | “哪些地方会行不通?” |
plan-validator | 不符合标准的内容 | “这是否符合此类应用的标准?” |
每个 Agent 都有一份输入契约(唯一需要读取的文件)和一份输出契约(严格的 JSON)。它们绝不会看到整个 .forge——上下文会带来成本,而上下文过载的验证器会降低验证质量。
确定性脚本会在 Agent 之前运行:脚本一秒就能检测出 Agent 需要读三遍才能发现的问题。
入口关卡可执行,并会明确指出拒绝原因:
node "$FORGE/scripts/forge-guard.js" fast-track <anchor> \
[--scope plans|phases4-7] [--autonomy milestone|full]
它不属于 forge-guard all——benchmarks 属于阶段 3,test_plan 属于阶段 6,因此纳入后会导致所有普通项目失败。但也不会因为忘记它而被绕过:state.js status 会显示该模式是否已启用,而 state.js fast-track --attempt 会在第三次尝试时停止。
完整流程、入口条件、限制和绕过方式:references/fast-track.md。
专业 Agent
每个 Agent 都是一份契约:包含角色、输入列表、流程、输出格式,以及明确列出的不负责事项。这不是角色描述,而是实现委派的关键。
| Agent | 阶段 | 模式 | 角色 |
|---|---|---|---|
product-analyst | 1, 2 | produce, review | 需求探索、访谈、PRD、用户故事 |
scope-architect | 2 | produce, review | 路线图、MVP、版本拆分、权衡 |
ux-designer | 3 | produce, review | 标准、视觉方向、优先级导航、屏幕、流程 |
systems-architect | 4 | produce, review | 架构、切片、模块、数据、API、依赖项 |
quality-analyst | 1–8 | produce, validate | 完整性、边界情况、测试计划;Fast Track 验证器 |
red-team | 1–8 | validate | 矛盾、盲点、未经验证的假设 |
plan-validator | 4, 5 | validate | 是否符合应用类型标准 |
premise-challenger | 1–4 | challenge | 质疑用户的假设——初始想法、所需功能、MVP |
scenario-tester | 6–8 | produce, review | 按业务场景测试:生命周期、时钟、不变量 |
forge-implementer | 7, 8 | produce | 实施、TDD、验证 |
client-liaison | 0, 4, 5, 7, 8 | check, stress | 客户无法理解的内容——未解答的问题,不给出结论 |
premise-challenger 是唯一不审阅 Forge 文档的 Agent:它审视您的需求,并指出某个想法何时不妥、已有解决方案、程度失当或放错位置。它会在第 1、2、3 阶段结束时触发;您在过程中添加功能时,也会一律触发。只要有一个 critical 结论,就会暂停,直到您作出回应。
client-liaison——唯一与客户沟通的 Agent
其他十个 Agent 都是工程师:他们寻找错误、不完整或无法测试之处。client-liaison 寻找难以理解之处,这是另一种专业工作。文档可能完全正确,却让接收者无法读懂——其他十个 Agent 都不会发现这一点,因为他们读的都是作者所用的语言。
| 模式 | 问题 | 输出 |
|---|---|---|
check | 客户能否不提出任何问题就签字? | 文档中未解答的问题 |
stress | 知情的客户会提出什么,而 Forge 没有写明? | 主要异议,以及保持沉默的代价 |
它绝不会给出结论。 一个表示赞同的子 Agent 会用假客户取代真正的客户,使关卡变成自我认证——这是此处代价最高的错误,因为它不会显现。它只提出问题;由客户作决定。
它不读取代码、计划或架构。这项限制不是预防措施,而是它的专业所在。由读过架构的人撰写的客户文档,总会包含架构内容。它的价值完全在于它没有读过架构。
适用于契约(第 0 阶段)、每份差异评估,以及实施前的阶段检查点。
没有可用的子 Agent 时:加载当前阶段相关 Agent 的指令,并应用姿态轮换。此时 Fast Track 不可用,改由 Guided 模式接手。
审计 — 基于 Forge 自身的执行结果改进 Forge
Forge 的每次执行都会在 .forge/audit/ 中记录日志:
| 文件 | 类型 | 用途 |
|---|---|---|
run-log.jsonl | 机器可读,仅追加 | 所有事件:状态转换、gate、验证器、护栏、事件 |
issues.md | 人类可读 | 事件日志:症状、根本原因、规避方法、纠正措施 |
metrics.json | 机器可读 | 汇总计数器 |
没有记录的事件就等于没有发生。 这是能够改进该技能的唯一数据。
必须记录的内容
node "$FORGE/scripts/state.js" log <anchor> <type> "<message>" [k=v ...]
必须触发记录的类型:
| 情况 | 类型 |
|---|---|
子 Agent 返回 REVISE | fast_track_validate |
子 Agent 返回 BLOCK | fast_track_block |
| 用户纠正输出(“不,这不对”) | user_correction |
| 护栏失败 | guard_failure |
| 脚本失败 | script_failure |
| 检测到状态不一致 | (通过 sync 自动记录) |
在 .forge 之外发现交付物 | (通过 strays --relocate 自动记录) |
| 需要重试某个阶段 | phase_retry |
| 人工 gate 被拒绝 | gate_revise |
| 用户退出 Fast Track | fast_track_escape |
issues.md 中的 origine 选项卡(forge / projet / environnement)是最重要的字段:它能区分“Forge 引导有误”和“PRD 含糊不清”。
跨项目分析
node "$FORGE/scripts/audit-report.js" <dossier-contenant-les-projets> --out reports/
合并多个项目的日志,按规范化签名汇总故障,并区分结构性问题(在多个项目中出现 → 归入该技能)与偶发事件(仅出现在一个项目中)。正常时返回 0,检测到结构性问题时返回 2。
验证纪律
这些规则不是偏好,而是从真实项目中累计的 43 次修正中得出的结论,其中 43 次全都是验证错误,而非知识错误——Agent 知道答案,缺少的是把知识应用到实际文件上的步骤。
它们出现在这里,是因为它们从未被提升为规则。没有进入规则的发现,什么也没有改变。
-
一项断言,值得执行一次验证它的操作。“不存在任何执行 X 的代码”是对系统的断言,理应像“代码执行 X”一样严谨。读完整个代码块,否则就不要断言。
-
**退出码不等于结果。**命令可能被忽略,却仍返回 0。已弃用的标志被悄然移除、
replace没有匹配项:两者都曾造成假通过。 -
**验证更改是否存在的检查,无法验证更改的内容。**证明文件已修改的门禁,只能证明它被修改了,不能证明其中内容属实。
-
只能看到已更改内容的检查,永远无法发现遗漏。
git status会显示更改内容;对它而言,未更新的文件与已更新的文件无法区分。 -
**重新实现待测规则的测试,测的不是规则,而是它的副本。**而且它会通过。
-
**因错误原因通过的测试,比失败更糟。**它占据了本该找出真实缺陷的测试位置。
-
没有触及错误所在代码行的测试,不算覆盖。“规则写了”不等于“规则已接入”。
-
**预期值是一个陈述,不是凭空编造。**把它写成一个关于测试数据的问题,然后作答。用与被测代码相同的代码计算出的预期值,什么也验证不了。
-
**不变量必须有明确形式。**对称性可以假定;不变量必须证明。如果唯一的写法是“除非……”,那它就不是不变量。
-
**一个事实,两种表示。**两个地方计算同一件事,却没有任何地方负责协调。一旦它们出现分歧,就没人知道哪个才是正确的。提取一个规范函数——绝不要保留两个计算点。
-
**没有两个测试的边界,就不是真正的边界。**只走正常路径的测试,无法验证其他情况。
-
无法写进文档的规则,就应该删除。而无法执行的规则,只是装饰。
-
**没有适用范围的发现并不完整。**它没有明确的晋升目标,因此不会带来任何改变。
-
**没有进入规则文件的发现,什么也没有改变。**它被用来替代规则,而不是补充规则。
参考资料
脚本 — 确定性执行,零依赖
调用方式:node "$FORGE/scripts/<fichier>" [<anchor>] [args…]。$FORGE 是 skill 的
目录,参见上文“如何运行脚本”。
只有一个例外,而且明确标注了:ddl-exec.js 会加载 PostgreSQL 引擎
(@electric-sql/pglite)来执行 DDL。这个引擎是
仓库的开发依赖,绝不是分发的 skill 的依赖。没有它时,脚本不会模拟任何内容:它会返回 skipped,说明自己没有执行什么,并给出安装命令。声称已执行、实际却没有执行的检查是最糟糕的检查,因为它会显示绿色通过。
| 脚本 | 作用 | 时机 |
|---|---|---|
state.js start | 实际状态:阶段、门禁、slice 及测试用例数、尚未晋升的发现 | 步骤 0,每次会话 |
state.js anchor | 解析当前项目,拒绝参考项目 | 步骤 0 bis |
state.js finding | 根据晋升领域路由发现 | 发现缺陷时立即执行 |
state.js set-status | 一次操作中写入权威状态及其镜像 | 每次状态变更 |
state.js sync | 调和状态 ↔ front matter | 每个门禁之前 |
state.js set-nav | 记录导航顺序及其理由 | 阶段 3 |
state.js check-stale | 派生文档,或审批后修改的计划 | 开始实现前 |
state.js dep | 声明 slice 或基础模块的依赖关系图 | 阶段 4 |
state.js amend | 记录修订并拒绝重新编号;写入 amended_from、原因和变更列表 | 每次修订 |
state.js migrate | v1 → v2 | 现有项目 |
forge-guard.js all | 路径、状态、词汇、同步、derived_from 来源信息、提前生成的产物、多余字符、“待决定”项、占位符、版本、项目记忆、工具包完整性、已声明的工具、未记录的事件 | 每个门禁之前 |
forge-guard.js memory-present | 四个记忆文件均存在,且 AGENTS.md 为三个文件中的每个文件都指定了触发条件 | 阶段 0,之后每个门禁 |
forge-guard.js kit-integrity | 工具包脚本与记录的指纹一致;修改过的脚本会导致硬性失败,文档则发出警告 | 每个门禁之前 |
forge-guard.js kit-integrity --write-manifest | 写入 .forge/kit-manifest.json — 明确执行的操作,绝不自动执行 | 执行一次,并在每次工具包更新后执行 |
forge-guard.js tools | 所有补充脚本都位于 .forge/tools/,并且已声明用途 | 每个门禁之前 |
forge-guard.js incidents | 将门禁检测到的偏差记录到 .forge/audit/issues.md | 每个门禁之前 |
consistency-check.js all | 检查产物之间的偏差:PRD ↔ 架构 ↔ 计划 ↔ 测试 ↔ 屏幕,以及已解析的章节交叉引用 | 每个门禁之前 |
forge-exit.js | 执行 slice 的退出条件 | 阶段 7,每个 slice 执行一次 |
coverage-check.js | 检查 slice 计划的覆盖率 | 阶段 5 |
design-check.js | 测量对比度(WCAG 1.4.3 / 1.4.11)、无值的 token,以及组件与屏幕之间的表面一致性 | 阶段 3,门禁时 |
ddl-exec.js | 执行架构的 DDL:PostgreSQL 会拒绝还是接受。检查 DDL 是否创建了它所修改的表,以及已声明的约束是否成立 | 阶段 4,门禁时 |
dependency-check.js | 循环、拓扑顺序;--write 会持久化依赖关系图 | 阶段 4 |
audit-report.js | 对多个项目进行交叉分析 | 多个项目完成后 |
selftest | skill 自身的测试 | 发布前 |
检查未亲眼看到失败,就不算验证通过
新增或修改的每项检查,都必须在同一批次中拦截一个它声称要查找的缺陷——同时放行一个干净样例。两者都要做到。
这不是形式上的预防措施。在同一个项目中,两次发现:PowerShell 中的 Get-Content -Raw + 正则表达式 \u 扫描,在已损坏的文件上报告了“0 个问题”;取代它的 Node 扫描则基于“损坏内容是 CJK”的假设,对 _USERNAMEOục 中含有 U+1EE1 的文件报告无问题——该字符属于 Latin Extended Additional。直到采用白名单,才发现第三个异常字符。
由此得出三条规则:
- 用白名单,不用可疑名单。 允许范围 = ASCII + Latin-1 + Latin Extended-A + 标点 + 符号 + emoji + 仓库语言的排版字符(序数
1ᵉʳ、下标CO₂)。其余一律标记。 白名单的首次尝试曾把正确的法语序数标记了 28 次:如果白名单没有覆盖仓库语言,它就会变成一个最终被关闭的检查。 - 标有
unicode-scan:ignore的行会被忽略,这样就能在日志中引用缺陷,而不会触发检查。否则,证明缺陷存在的报告就无法提交。 skip≠pass。 未运行的检查会说明自己没有覆盖什么。一个从未见过失败的检查,不算已验证,只能说状态未知。
对于输入是生成文件的检查:必须先在实际项目上验证,然后才能接入 all。由命令触发的检查仍可单独运行,不属于 all。
参考文档
| 文件 | 内容 |
|---|---|
references/skill-boundaries.md | Forge 与 project-rules-architect 各自负责什么;发现问题后的路由 |
references/state-schema.md | .forge/state.json(v2)的格式、写入规则、权威来源 |
references/migration-v1-v2.md | 迁移过度膨胀的 v1 state.json 的流程 |
references/module-prioritization.md | 按使用频率排列模块和导航的顺序 |
references/design-quality.md | 反通用化禁令、必需的设计 skills、视觉方向 |
references/scenario-tests.md | 按业务场景编写的测试——生命周期、注入时钟、不变量 |
references/test-strategies.md | 测试类别、如何选择、哪些测试可在没有设备的情况下运行 |
references/archetypes.md | 各类原型的标准 + 已测量的反复出现的问题 |
references/research-protocol.md | 不要重新发明:提取不变量,而非代码 |
references/fast-track.md | 自动验证、两级自主程度、限制 |
references/impact-protocol.md | 变更影响分析流程 |
references/review-checklists.md | 按文档类型划分的 gate 检查清单 |
产品访谈记录在 agents/product-analyst.md 中。
工作流摘要
anchor → Interview (Phase 1) → PRD → Roadmap (Phase 2)
→ Standards + Direction + Navigation priorisée + Design (Phase 3)
→ Architecture (Phase 4) → Plans d'implémentation (Phase 5) → Tests (Phase 6)
→ Implémentation (Phase 7) → Validation (Phase 8)
全程还需遵循:
Anchor résolu · Livrables dans .forge · État = autorité, front matter = miroir
Gates humains (ou Fast Track) · Analyse d'impact · Multi-perspective
Identifiants stables · Exhaustivité · Garde-fous déterministes · Audit