关于 br
br 是一项将原始需求逐步转为 BR、开发 frames 并通过受控循环执行的 skill,面向需要可追溯交付流程的项目。它以人工审阅为关口,使用 lint、运行护栏和状态监控,并将产物保存在项目文件中。
主要功能
- 01访谈并整理原始需求
- 02编译带条款追溯的 BR
- 03切分并校验开发 frames
- 04通过多重护栏运行循环
- 05生成流水线状态报告
适用场景
- 01将非结构化需求整理为可审阅规格
- 02把 BR 条款拆分为有依赖关系的 frames
- 03在人工批准后运行受控开发循环
- 04追踪失败 frame 与对应需求条款
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ rheinmir/ setup --skill br安装后在 Claude Code 中输入/br确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/defaults.yamldesign-template.mdframe-template.mdqueue.example.yamlrevise-prompt.mdspec-template.md详细介绍
Skill:br — Ralph 生产线(BR 技术编写 → frames → 带 harness 的循环)
BR = 业务需求(Business Requirements) — 已敲定的需求规格,位于
br/BR.md。Skill 以其生成的核心工件命名,而非以动词命名。每个 frame 和每条 clause 都能追溯到该文件,因此“产品缺陷 ⇔ BR 缺陷”(GH#15,2026-07-03) 是整条生产线的前提,而非口号。单名称 Hub:用户描述范围(interview / compile / slice / run / status),无需记住多个命令。基础:council 028(thin-slice、人类参与环路)+ council 031/032(包含 6 项强制条件的 loop v1 — Taleb 均值排名第 1.0)。
内容
用途与上下文
- **用途:**将用户的原始需求文档转化为有纪律的产品,经过 BR 技术编写 → frames → 带 harness 的循环生产线;每个 frame 和 clause 都能追溯到
br/BR.md。 - 触发条件(何时使用):
- 用户有需求文档(原始/非结构化),并希望将其转化为有纪律的产品。
- 用户提到:interview / 需求访谈 / 编写 BR / slice frame / 运行 frame / 生产线状态 / ralph。
- **非目标:**不写入
llmwiki/raw/;不重写已构建的确定性工具(frame-lint.py、loop-runner.py、build-line-status.py等);不代替用户自行提交/合并;不在/br run之外手动修改 UI;不自动触发钩子。
心智模型
llmwiki/raw/ → interview(填写完整的 S1–S10 规格 + 补充问题)→ compile(包含 clause_id + “正在承担的假设” + BR.clauses.json 的 BR.md)→ slice(包含 depends_on 的 frames,由 frame-lint 把关)→ run(loop-runner 的 6 项刹车、每个 frame 单独提交、追踪日志)→ qc / find / status(从错误反向追溯到 frame → clause)。用户只需描述范围;Hub 选择模式。
输入与输出约定
| 字段 | 必填? | 含义 | |
|---|---|---|---|
| 输入 | llmwiki/raw/ 中的原始文档 | 是(interview 模式) | 只读;为空时 → 请用户放入文档 |
| 输入 | 已填写的 br/interview/NNN-answers.md | 是(compile 模式) | 用户按 field-id 提供的真实回答 |
| 输入 | 用户描述的范围 | 是 | interview · compile · slice · run · find · qc · status · sync · contract · rail |
| 输入 | 标志 --proactive · --lens-fill · --ack-tier · --worktree · --dry-run | 否 | 可选分支(见分支) |
| 输出 | br/spec-filled.md、br/interview/NNN-{questions.html,answers.md} | interview 模式 | 字段带有 status + provenance |
| 输出 | br/BR.md、br/BR.clauses.json、br/DESIGN.md(如有 UI) | compile 模式 | check-contract 通过 |
| 输出 | br/frames/*.md、br/frames/index.md、br/prompts.md | slice 模式 | frame-lint 通过 |
| 输出 | frame(<id>) 提交、br/frames/<id>.run.json、.checkpoints.jsonl | run 模式 | 单行摘要 + medic |
| 输出 | br/line-status.{json,html} + llmwiki/html/line-status.html | status 模式 | 3 行摘要 |
规则与能力
- RULE-01(MUST):人是最终关卡 — 绝不自动提交/合并 frame 输出;采用 dry-run + 人工审核(council 028)。
- RULE-02(MUST):刹车不可侵犯 — 绝不提高 max_iter 或关闭 guard 来“让它完成”。多一道刹车的成本低于少一道(council 031/032)。
- RULE-03(MUST):Prompt 中的嘱咐不是安全层 — scope-jail/test-hash 是确定性代码(loop-runner guard 5/6),而非 prompt 中的嘱咐(5/5 个 council 席位)。
- RULE-04(MUST):Lens-fill 始终为
verified: false— 不与真实回答混在一起;始终显示在“正在承担的假设”表中。 - RULE-05(MUST):初期采用有人参与环路的 Slicer — 尚未实现全自动(Slicer 错误属于相关性错误,影响范围 = 整份 BR)。
- RULE-06(MUST):文件优先,按需运行 — 所有工件都是可移交的文件;由 Skill 手动调用,绝不自动触发钩子(ADR-004)。
- RULE-07(MUST):为用户生成的 HTML 必须解释术语 + 打印完整路径(R16)。
- 能力:读取原始文档 + 代码库;在
br/下写入工件;在本地运行确定性工具(lint、loop、monitor);调用工具范围受限的模型适配器;仅在确认后于外部跟踪器创建 issue。
失败边界
llmwiki/raw/为空 → clarify:询问用户是否放入了文档。br-fill.py check-contract显示红色 → 编译失败,修复 BR,直到通过。frame-lint.py check显示红色,或工作树不干净 →/br runblocked(拒绝运行)。- Frame 的
tier: compensable/irreversible尚未提供--ack-tier→ blocked(TIER-GATE)。 - 触发 KILL 条件(例如 diff-jail 触发 ≥2 次 / test-hash 触发 1 次)→ 整个 run cancelled,不挽救,不解除刹车。
- Frame 显示红色 → 下游分支标记为
status: blocked(partial),无关分支仍继续运行。 - UI 检查没有真实图片文件 +
MANIFEST.json→ 视为失败(等同于从未做过)。
HOW
Main workflow
| Step | Type | Inputs | Action | Outputs/exit | Failure/next |
|---|---|---|---|---|---|
| W01 | 判断 | 用户的话 | 根据用户描述的范围选择模式(单名称 hub) | mode | 模糊 → 询问 |
| W02 | 判断 | llmwiki/raw/ + spec-template | Mode 1 interview:将 raw 拆解到 S1–S10,进行 gap-diff,生成 questions.html + answers.md | 2 个文件 NNN | raw 为空 → clarify;--proactive → B01 |
| W03 | 判断 | — | STOP — 用户打开 HTML + 填写 answers.md | 已填写的 answers | --lens-fill → B02 |
| W04 | 判断 | 已填好的 spec + answers | Mode 2 compile:BR.md + BR.clauses.json(如果有 UI,还包括 DESIGN.md) | BR | — |
| W05 | 确定性 | BR | Gate br-fill.py check-contract | 通过 | 显示红色 → 修复 BR,重复 W05 |
| W06 | 判断 | BR.md | Mode 3 slice:提出切片,STOP,等待用户逐个批准,按模板记录 frame | frames + index | — |
| W07 | 确定性 | frames | 运行 frame-lint.py check + br-prompts.py sync 检查 | lint 通过 | 显示红色 → 修复 frame,重复 W07 |
| W08 | 执行 | frame | Mode 4 run:br-run.py run(tier-gate、lint、干净的工作树、loop-runner、commit、run_log_ref、trace 日志) | frame commit + run log | 阻止下游分支;KILL → 丢弃 run |
| W09 | 确定性 | frames + run log + BR | Mode 5 status:build-line-status.py build + 3 行摘要 | line-status.html | 错误落入 assumed → 下一轮返回 W02 |
各步骤详情(W01–W09 和所有辅助模式的事实来源):
确定性工具(已构建 + 自测 — 请勿重写)
| Tool | 用途 | selftest |
|---|---|---|
skills/br/assets/spec-template.md | 标准 specs 套件 S1–S10(所有项目的参考框架) | — |
skills/br/assets/frame-template.md | 所有 frame 的确定性模板(frontmatter + 4 个易读的正文部分) | — |
skills/br/assets/design-template.md | 可复用的设计模板(Google design-doc 框架 + 从 /high-end-visual-design 加载的 design system)→ 复制为 br/DESIGN.md | — |
fdk/tools/frame-lint.py | 检查 frame 的 7 条规则(schema · scope · test-first · freshness · DAG · exclusive-scope 含 lease · content) | frame-lint.py selftest |
harness/scripts/loop-runner.py | 6 道刹车的 loop(max_iter·budget·no_progress·escalate·diff-jail·test-hash) | loop-runner.py selftest |
fdk/tools/build-line-status.py | 确定性监控工具(frame·run-log·BR → json+html,--check) | build-line-status.py selftest |
运行时产物存放在项目根目录的 br/ 中(不在 skill 内):br/spec-filled.md、
br/interview/NNN-{questions.html,answers.md}、br/BR.md、br/BR.clauses.json、br/frames/*.md、
br/frames/index.md、br/frames/<id>.run.json、br/line-status.{json,html}。
模式 1 — /br interview
- 读取
llmwiki/raw/中的所有文件(只读——规则禁止写入 raw/)。如果为空 → 请用户放入文档。 - 对照标准 specs 模板
skills/br/assets/spec-template.md:从 raw 提取信息并映射到各个字段 S1–S10 → 写入br/spec-filled.md。每个字段都要记录status(filled|missing|conflict|assumed)+provenance(raw:<file>)。 - 差异分析:对于
missing/conflict字段 → 生成一组问题。**每个字段对应一个明确的 spec(rigor /orca-workflow):**问题要说明字段的作用 + “怎样回答才算充分”(字段的验收标准),不能问得含糊。写入 2 个文件(使用相同的序号 NNN):br/interview/NNN-questions.html— 按 section 查看,包含术语解释 + 每个字段的充分标准,显示完整路径(R16),支持深色模式。只询问缺失部分。br/interview/NNN-answers.md— 按字段 ID 提供填写区块(例如## S4.2…留空),供用户输入答案。 3b.--proactive(T-260714-01,简称/br auto) — 用户希望由机器填写缺失部分,而不是把问题全部交给用户:运行python3 fdk/tools/br-fill.py fill --root .(必须执行,不使用模型)。工具查询 registry defaults(skills/br/assets/defaults.yaml— 26 个 loop 条件的表格 + github/spec-kit 约定;若字段重复,项目 overridebr/defaults.yaml优先),并输出 2 组内容:- 机器填写建议 → 粘贴到
NNN-answers.md,每项都保留原样的filled_by: <source>:<refs>+verified: false(lens-fill 规则适用于所有机器填写层级)。 - 真实问题(carve-out 字段——认证/权限、信任边界、资金——以及没有默认值的字段):按 Impact × Uncertainty 选择 ≤5 个问题,放入 questions.html(carve-out 已优先排序,优先占用提问名额);超出上限的部分则使用 lens-fill(步骤 5)。绝不允许为 carve-out 字段赋予机器生成的值——即使 registry 中有条目,即使使用 lens 也不行。
- 停止 — 告知用户打开 HTML 查看并填写 answers.md。
- 如果用户启用
--lens-fill(或表示“让专家填写不确定的项目”):通过python3 harness/scripts/council.py roster --case product --json获取 lens,为用户标记为“不确定”的missing字段填写内容 → 每个字段都标记filled_by: lens:<tên>+verified: false。不要与用户的真实回答混在一起。
模式 2 — /br compile
- 读取
br/spec-filled.md+ 已填写的br/interview/*-answers.md。 - 生成
br/BR.md:每个条款都包含clause_id(继承字段 ID,例如S4.2)+ provenance(raw|user|lens:<tên>)。文件开头放置 “正在承担的假设” 表格,列出所有lens/assumed条款(fail-fast:一眼看出正在押注什么)。- 带 UI 的产品(S7.5):确定一个指向
br/DESIGN.md的 NFR 条款(例如N01 giao-diện),不要把 design 规则复制到 BR 中。同时将skills/br/assets/design-template.md复制到br/DESIGN.md,并为产品填写 §1/§2/§4/§6/§7(§3/§5 保持继承内容不变)。BR = 必须有主题/设计;DESIGN.md = 设计看起来是什么样。
- 带 UI 的产品(S7.5):确定一个指向
- 生成
br/BR.clauses.json:{clause_id: {provenance, assumed: bool, fields: ["S4.2", …]}}—fields声明该条款落实了哪些 S1–S10 spec 字段(这是合同 checksum 的键);monitor(/br status)读取此文件,为 assumed 条款标为橙色。“正在承担的假设”表格按填入来源(default/spec-kit/lens)分组,让审核者看清正在从何处接受哪些风险。 - 合同 checksum 门禁(G1 修复 — council c9dc13d):
python3 fdk/tools/br-fill.py check-contract --root .— 所有必填 S1–S10 字段都必须有对应条款;显示红色即表示编译失败,必须修复 BR,直到检查通过。不能出现“编译完成但合同有漏洞”的情况。
模式 3 — /br slice
- 阅读
br/BR.md。提出切片列表:每个切片 = {clause_ids、预期 scope_code(≤3 个文件)、scope_test、acceptance_test、depends_on}。暂停,让用户逐个审核/修改/合并/拆分切片(人在回路中——防止 slicer 相关性错误的关卡)。首批 ≤ 3–5 个 frame。depends_on必须考虑,但不要求必须有值(GH#75,提炼自 Atomic Task Graph):依赖链是图,不是列表。若 B 在 A 尚未通过时无法通过(B 调用 A 构建的 API/store/schema),则在 frame B 中声明depends_on: [frame-A]。如果没有依赖 →depends_on: []。正确声明后,模式 4 会自动获得三项好处:自动确定正确的执行顺序、frame 失败时自动阻断下游分支,以及修改某个 frame 时只需重新运行其对应分支。随意声明(为了「看起来合理」而连线)会损失并行性并造成不必要的等待——只在存在真实依赖时连线。
- 按照模板
skills/br/assets/frame-template.md编写br/frames/frame-NNN-<slug>.md(schema v0 + 5 个必需正文部分:业务 · 输入/输出 · Spec(FR/SC) · 验收标准 · 范围之外——内容应便于后续读者理解,frame-lint R7 会严格把关:frame_id 必须包含业务 slug,muc_tieu 不能是通用描述,每个 frame 必须有明确的 FR-id/SC-id,各部分不能为空)+parent_br_hash = sha256(br/BR.md)。 - 根据各 frame 的 frontmatter 生成 registry
br/frames/index.md(表格列:frame_id · clause_ids · scope_code · status · run_log_ref)。 - 检查:
python3 fdk/tools/frame-lint.py check br/frames --root .— 全部通过后才算切片完成(包括 R6 exclusive-scope:2 个未完成的 frame 不得占用同一个文件)。- **R6 是租约,不是产权证:**已完成的 frame(run-log
verdict: SUCCESS)会释放文件占用权。因此,新 frame 可以接入曾由旧 frame 占用的启动点(main.ts、state.ts、server.ts……)。否则,即使新代码通过,用户也看不到(walleye 2026-09-10:4 个 frame 均已通过,但玩家什么也看不到)。两个未完成的 frame 仍不得同时占用同一个文件——除非depends_on已将它们排成前后依赖(其中一个 frame 是另一个的祖先):这样它们就不会同时修改文件,也可以让多个功能依次接入同一个main.ts。_manifest.json会将文件交给最后一个租用者(后代)。 - 每项功能都必须有一个接入启动点的切片;UI frame 必须通过实际界面测试(e2e/route-shots)验收,而不能只用独立模块的单元测试验收。
- **R6 是租约,不是产权证:**已完成的 frame(run-log
python3 fdk/tools/br-prompts.py sync— 将新 frame 的提示词条目添加到br/prompts.md,以便用户立即手动编辑。
模式 4 — /br run <frame>
确定性调用方式(已接入 — 默认 IN-PLACE,仅一个工作树):
python3 fdk/tools/br-run.py run br/frames/<frame>.md --root .
# xem prompt sẽ gửi mà không chạy: thêm --print-prompt
# chạy cả hàng đợi resumable: python3 fdk/tools/br-queue.py run --queue br/queue.yaml
# sửa 1 frame → chạy lại ĐÚNG nhánh của nó, không cả dây chuyền:
# python3 fdk/tools/br-queue.py affected <frame_id> --queue br/queue.yaml --reset
# python3 fdk/tools/br-queue.py run --queue br/queue.yaml
# cần cô lập thư mục thật sự (hiếm): thêm --worktree
队列按图运行,而非按手动输入顺序(GH#75 — 提炼自 Atomic Task Graph,arXiv 2607.01942):
- 拓扑顺序:
br-queue读取每个 frame 的depends_on并自动排序(没有依赖时保持声明顺序 — 旧队列的运行方式不变)。 - 红色 frame 会阻断其下游整个分支(
status: blocked,记录blocked_by):该分支的输入已损坏,继续运行只会浪费模型调用次数,因为它必定失败。不相关的分支仍会正常运行 — 一个 frame 出错不再阻断整个流水线。 - 局部修复(
affected):修复一个 frame → 仅该 frame 及其下游分支重置为pending,其他所有绿色 frame 保持不变。这正是节省成本的关键:以前,链中间一个 frame 出错,就会迫使你重跑超出必要范围的内容。 - 不实现子图复用缓存(论文有,我们有意省略):
status: done已会跳过绿色 frame;在几十个 frame 的规模下再加哈希缓存,只会产生陈旧缓存 bug。论文自身的限制在此同样适用 — 图较小且acceptance_test确定时,收益依然存在;图非常大,或测试/工具返回结果不稳定时,这种运行调度就会失效。br-run.py会自动执行:(0) TIER-GATE — frontmatter 中声明了tier: compensable|irreversible的 frame(不可逆副作用:调用外部 API/发送邮件/写入 DB)会被阻断,直到运行者使用--ack-tier重新运行(SHEPHERD 在物化前进行门控);(1) frame-lint;(2) 检查工作树是否干净;(3) 在当前工作树中立即运行 loop-runner,且 revise 已指向fdk/tools/br-revise.py(渲染skills/br/assets/revise-prompt.md→ 使用受限工具的claude -p);(4) frame 通过 → 提交到当前分支,提交信息附带 frame_id(用于回滚/追责);(5) 打印一行摘要;(6) 将run_log_ref写入 frame;(7) 在 TRACE LOG.checkpoints.jsonl中记录检查点(checkpoint-trace/SHEPHERD — 记录直接指向已有提交,不重复提交)→ 查看整个流水线:python3 fdk/tools/checkpoint.py list;按名称将整个流水线回滚到任意 frame:checkpoint.py rollback <frame_id>(保留历史,并警告检查点之后发生的不可逆 tier 副作用)。 **为什么默认使用 in-place(用户反馈 05/07):**N 个 frame = N 个工作树 = N 个没人会去翻找的文件夹;普通用户的流程是打开应用查看,修改必须立即显示在当前运行应用的工作树中。范围外修改的控制由 HARNESS 负责(每轮 diff-jail 回退 + FINAL SCOPE SWEEP + test-hash + scope_clean + R6 exclusive-scope),而非目录隔离。不满意结果 →git revert <commit frame>。
等效的手动步骤(如需手动微调):
- 使用
frame-lint check确认该 frame 通过。检查工作树干净(git status --porcelain为空)— 不干净则拒绝。 - 从该 frame 的
baseline_ref创建独立的 git worktree(文件系统 jail — 第一个 frame 不会触碰 harness/hook/CI)。 - 运行 loop — 逐 frame 提交到 WORKTREE BRANCH(不是 main);仍由用户手动合并:
Revise 适配器 = 使用受限工具的python3 harness/scripts/loop-runner.py run \ --verify "<acceptance_test>" --revise "<adapter claude -p>" \ --state "<scope_code>" --scope "<scope_code>" --protect "<scope_test>" \ --baseline "<baseline_ref>" --commit-on-success \ --commit-message "frame(<frame_id>): <muc_tieu> [<clause_ids>]" \ --max-iter <g> --budget-seconds <g> --no-progress-k <g> --escalate-after <g> \ --log br/frames/<id>.run.json --cwd <worktree>claude -p(--allowedTools Edit,Write,Read,Grep,Glob— 不允许自由使用 Bash,也不允许网络访问),提示词根据muc_tieu+scope_code+ 最近一次 verify 失败的输出生成。 追踪 frame→代码(前提条件 — 确认哪个 frame 生成了哪些代码,且不超出范围):- Run-log 记录
changed_files= frame 实际修改的文件(≠ 预期范围);当所有文件 ⊆scope_code时,scope_clean=true;attempted_out_of_scope= frame 试图写入范围外、但已被回退的文件。 - FINAL SCOPE SWEEP:每次 loop 停止时(包括 PROTECT_VIOLATION),loop-runner 都会干净地回退所有
scope_code范围外的文件 → worktree 始终保持范围干净,changed_files始终 ⊆scope_code。这是完全控制,而非仅依赖提示词提醒。 - 只有 verdict=SUCCESS 且 scope_clean 时,
--commit-on-success才会提交;提交信息附带frame_id→git blame可准确追溯到对应 frame。--baseline= 用于计算 diff 的原始提交(通常是 worktree 开始时的 HEAD)。
- Run-log 记录
提示词与队列(运行多个 frame,可恢复)
- 📒 提示词总账(优先级最高的来源,用户可手动修改,无需模型):
br/prompts.md——一个文件,每个 frame 一个## <frame_id>条目。打开文件,找到 frame 后可随意修改/添加内容(保留{{...}}占位符,由机器在运行时填入)。python3 fdk/tools/br-prompts.py sync会自动为新 frame 添加条目,绝不会覆盖手动修改过的条目(每次/br slice后运行);使用list/get <frame_id>查询。运行时优先级:提示词总账 > 队列内联内容 > prompt_file > 默认模板。 - 原始模板(总账的种子):
skills/br/assets/revise-prompt.md。Adapterfdk/tools/br-revise.py会渲染胜出的来源 → 调用claude -p(工具范围受限)。查看将发送的提示词:br-revise.py run --frame <f> --verify "<cmd>" --print。 - QUEUE 文件(
br/queue.yaml,示例skills/br/assets/queue.example.yaml):按顺序运行的 frame 列表;每项使用prompt_file:(指向模板文件)或prompt:(直接填写文本,仍支持占位符)。Driverfdk/tools/br-queue.py run --queue br/queue.yaml会逐项运行,并在每项运行后回写status→ 重新运行队列时会跳过done,从中断处继续(恢复)。使用--dry-run查看每项使用的提示词;使用list查看状态。 - Adapter
claude -p是verified:false(BNAL)的边界——模板、队列和渲染均为确定性操作,并带有 selftest(br-revise.py selftest、br-queue.py selftest)。
- 预先写明 KILL 条件(via negativa):例如 diff-jail 触发 ≥2 次/test-hash 触发 1 次 → 丢弃整个 run,不挽救,不松开刹车。
- 循环停止 → 输出一行摘要(判定 · 循环次数 · diffstat · 最后一次 verify 命令)+ 运行
python3 fdk/tools/medic.py --ci。STOP — 由读者在 worktree 中查看 diff,自行决定合并/继续运行/丢弃。 - 将
run_log_ref+outcome填入 frame 和 registry。记录经验(包括没有发生的事——哪些刹车从未触发)。
Mode 4b — /br find <file或关键词> — 指向出错位置,找出负责的 frame/提示词
常见用户流程:打开应用 → 看到错误 → 指向出错区域:
python3 fdk/tools/br-find.py "src/auth/login.py" # theo file
python3 fdk/tools/br-find.py "đăng nhập" # theo từ khoá / clause
输出:负责的 frame(按实际变更的文件 > scope_code > 关键词匹配)· BR 条款 · 提示词位置(内联于 queue.yaml/prompt_file/默认模板)· 修改提示词后准确重跑该 frame 的命令。此功能依赖 R6 exclusive-scope(frame-lint)强制每个文件在任何时刻只属于一个 frame——如果文件通过 lease 更换了归属,负责的 frame 就是最后一个租用它的 frame(_manifest.json);历史归属则通过 git blame 按 frame(<id>) 提交追溯。
Mode 4c — /br qc [frame] — 对 mockup/frame 进行高级 QC 审计(LLM 四项)
mockup/frame 通过后,运行高级人工审查(成本较高=LLM,手动调用——低成本的确定性检查已在每次 /br run 后自动运行):
- **代码:**调用
/qc-code(Skill tool →qc-code)检查 frame 的 diff——涵盖安全性/性能/命名/逻辑四项,并生成复现问题的qc-*测试。 - **UI/UX:**调用
/qc-uiux(Skill tool →qc-uiux)审计 mockup——涵盖 a11y/层级/一致性/反模式四项;可测量的部分(对比度/点击目标/重叠/错位/缺少标签)通过 visual-qa headless engine 运行:node skills/visual-qa/assets/route-shots.mjs <base-url-mockup> --audit - 判定为需要修改 → 定稿 frame 前先修改。仅供参考——LLM 判定只是意见;只有 engine 测量结果 +
qc-*测试才是强制门槛(已在/br run和verify-before-commit的步骤 3b 中自动运行)。未指定 frame → 审计现有 mockup 路由。
Mode 5 — /br status
python3 fdk/tools/build-line-status.py build --root .→br/line-status.json+llmwiki/html/line-status.html。- 输出 3 行摘要(总体状态 · 最值得关注的 frame · HTML 路径)。页面支持从错误追溯至 frame → 条款;假设条款以橙色标示 → 如果错误落在假设条款上,请在下一轮执行
/br interview。
模式 6 — /br sync(frame ↔ GitHub 子议题)
提炼自 automazeio/ccpm:每个 frame 对应一个 GitHub 子议题,让团队查看进度并交接。不要重新实现溯源(clause_id/manifest 已比 ccpm 更深入);只在 gh 上添加一层轻量同步。
python3 fdk/tools/br-sync.py sync br/frames --root . --repo <owner/repo> --dry-run——始终先执行 dry-run(不调用 gh,不写入映射)。- 确认无误后移除
--dry-run→ 为尚未映射的 frame 创建子议题,并写入br/frames/issue-mapping.json。支持幂等操作。--epic可创建 epic 议题。status/selftest可用。 - 创建 issue 会产生仓库外部操作 → 移除
--dry-run前必须先确认。
模式 7 — /br contract(用于最终实现的 UI Contract,md+html)
将 CODE 轴(frame)与 DISPLAY 轴(screen/route)分开。所有项目采用以下标准:
- Frame 声明
ui_role: none|screen|panel|widget|form|action+ui_screen(frame-template)+ 章节「## UI 如何运作」。 br/ui-layout.yaml:包含nav_style+screens[](id·title·实际 route·frames[])。集中修改屏幕时无需触碰 frame。python3 fdk/tools/br-contract.py build br/frames --layout br/ui-layout.yaml --root .→br/UI-CONTRACT.md+.html。包含 frame·功能·ui_role·屏幕·route·clause·acceptance 表格 + frame/屏幕/route 计数 + 偏差警告。selftest可用。
分支
| ID | 类型 | 条件 | 行为 | 跳过 / 失败 | 汇合点 |
|---|---|---|---|---|---|
| B01 | 用户可选 | interview 中使用 --proactive(简写为 /br auto) | br-fill.py fill 提供机器填充建议(verified: false)+ 最多 5 个真实问题,按 Impact × Uncertainty 排序;例外项不接受机器填充值 | 超出上限 → lens-fill | W03 |
| B02 | 用户可选 | 使用 --lens-fill 或「让专家填写尚不确定的字段」 | council.py roster --case product --json,填写用户标记为不确定的缺失字段,添加标记 filled_by: lens:<名称> + verified: false | 不与真实回答混合 | W04 |
| B03 | 条件必需 | 产品带有 UI(S7.5) | NFR clause 指向 br/DESIGN.md;将 design-template.md 复制到 br/DESIGN.md,填写 §1/§2/§4/§6/§7 | 没有 UI → 跳过 | W05 |
| B04 | 条件必需 | frame 的 ui_role 不为 none | 编码前运行 /design-twice;acceptance_test 为 visual-qa route-shots.mjs --assert | 缺少 ## 设计(design-twice) 章节 → frame 尚未完成 | W08 |
| B05 | 条件必需 | frame 声明 tier: compensable 或 irreversible | 阻止执行,直到使用 --ack-tier 重新运行 | 未确认 → 不运行 | W08 |
| B06 | 能力可选 | 需要真正隔离目录(少见) | 添加 --worktree,或使用等效手动步骤(从 baseline_ref 创建独立 worktree) | — | W08 |
| B07 | 用户可选 | 运行多个 frame / 修改一个 frame | 按拓扑顺序执行 br-queue.py run --queue br/queue.yaml;affected <frame_id> --reset 可重新运行正确分支 | frame 标红会阻止下游分支 | W09 |
| B08 | 用户可选 | /br find <文件或关键词> | 模式 4b:br-find.py 输出负责的 frame + clause + prompt 位置 + 重运行命令 | — | W08(修改 prompt 后重新运行) |
| B09 | 用户可选 | /br qc [frame] | 模式 4c:/qc-code + /qc-uiux(建议性检查);判定为需要修改 → 定稿 frame 前先修改 | — | W08 |
| B10 | 用户可选 | /br sync | 模式 6:先运行 br-sync.py sync --dry-run,确认后再移除 --dry-run | 未确认 → 停在 dry-run | 结束 |
| B11 | 用户可选 | /br contract | 模式 7:br-contract.py build → br/UI-CONTRACT.md + .html | — | 结束 |
| B12 | 用户可选 | /br rail off 或 skip | 通过 frame-lint … --soft-off 关闭软门控(R7 content · visual-qa UI · assumption-gate);硬性制动保持不变 | skip 仅生效一次,之后自动重新启用 | W08 |
验证与停止
必须执行:frame-lint.py check(7 条规则)、br-fill.py check-contract、loop-runner 的 6 个制动条件 + FINAL SCOPE SWEEP、每轮 loop 后运行 medic.py --ci、每个工具的自测(frame-lint.py selftest、loop-runner.py selftest、build-line-status.py selftest、br-revise.py selftest、br-queue.py selftest)。必须进行 review(人是最后一道关卡):审核 answers、在 slice 中审核每一片、阅读 frame diff,然后自行决定合并/继续运行/丢弃。Mode 在已记录的 STOP 点停止;loop 按制动条件停止,不得提升制动条件。
示例
- **正向:**用户将 3 个需求文件放入
llmwiki/raw/,并说“起草 BR” → interview 生成br/interview/001-questions.html,询问缺失的 7 个 field → 用户填写 → compile 生成br/BR.md+ check-contract 通过 → slice 提出 4 片,用户审核通过 →frame-lint.py check br/frames --root .通过 →br-run.py run br/frames/frame-001-dang-nhap.md --root .→ SUCCESS,提交frame(frame-001-dang-nhap): …,用一行总结 + medic。 - **边界/失败:**当
git status --porcelain不为空时运行/br run→ 拒绝运行。Frame 声明发送邮件的tier: irreversible→ TIER-GATE 阻止运行,直到指定--ack-tier。Frame-003 未通过 → frame-004(depends_on: [frame-003])变为status: blocked,无关的 frame-005 仍然运行。
参考 — 统一的 Stream UI + 明确的 Spec(提炼 hallmark + orca-workflow)
多 frame 流程存在两个缺口,通过两个提炼机制来弥补:
A. 跨 FRAME 统一 UI/UX(提炼自 hallmark)。 每个 frame 通过 loop-runner 独立运行 → 容易导致每个 frame 风格各异、mockup 拼凑。hallmark 机制:br/DESIGN.md = 锁定的 TOKEN 系统,必须先阅读,并覆盖所有选择;反向规则 — frame 必须彼此相同(共享系统),不得追求多样化;locked-token — 所有颜色/字体/间距都必须指向具名 token(var(--…)),禁止 inline。应用到 /br:
/br compile将design-template.md复制到br/DESIGN.md,其中的 §4 + §4.1 token 表(锁定 token)是唯一真实来源。## UI hoạt động ra sao中的 Frame UI 只能使用 DESIGN.md 中的 token;新增值 = 将 token 添加到 DESIGN.md 并引用,不得在 frame 中自行创造。/qc-uiux(一致性)+ engine visual-qa 会捕获 token 漂移 → “stream” 由确定性 gate 驱动,而非靠口头提醒。结果:frame-01 和 frame-09 看起来像同一个产品。
B. 每个 frame + interview 屏幕都需要明确的 SPEC(参考 /orca-workflow)。 Propose 生成稳定的 FR/SC id + acceptance;/br 将这种严谨性带入每个环节:
- **Frame:**frame-template 包含
## Spec (FR/SC)section(frame-lint R7 严格把关)— 每个 frame 声明 FR-id(系统必须……)+ SC-id(面向人的衡量标准),acceptance_test 是 SC 的证据,每条验收标准都能追溯到一个 FR。Frame 缺少明确的 FR/SC = 尚未完成,就像 interview 缺少 field 一样。 - **Interview:**每个被询问的 field S1–S10 都必须是一条明确的 spec — 问题要说明 field 的用途 + “怎样的回答才算足够”的标准(不得含糊提问)。仍为
missing/assumed的 field = spec 尚不完整,显示在“正在承担的假设”表格中,避免遗漏。
参考 — UI frame 的设计轮次(skill /design-twice)— 编码前运行
**所有 ui_role≠none 的 frame 都必须执行:**在编写任何 UI 代码之前,运行 /design-twice
以获得 2–3 个根本不同的方案,进行比较,选择 1 个,然后在 frame 本身添加 ## Thiết kế (design-twice)
部分(3 个方案 + 选定方案 + 理由 + 从落选方案中借鉴的点)。
- 原因:第一个想法是最容易想到的,不是最好的。没有方案可供比较时, agent 只会不断修补唯一的方案 — 每轮修补都会产生一个新问题(Lume 主题:修补 5 轮)。
- 需要回到设计轮次的信号:同一位置正在进行第 2 次修补,或用户表示 “难看/糟糕/不喜欢”,却没有指出具体问题 ⇒ 形态错了,继续修补只会浪费时间。
- 缺少
## Thiết kế (design-twice)部分的 UI frame = 尚未完成(R7 content 会视为缺少内容)。 - 设计完成后才能进入
## UI hoạt động ra sao→ 编码 → 下方的/visual-qagate。
参考 — UI frame 的视觉自检循环(技能 /visual-qa)
**原则(不是单独的重新检查规则):**修改 UI = 编辑该 frame 的 spec + 代码,然后再次运行
/br run。若想实现“重新运行 frame 时自动重新验证 UI”,那么 UI frame 的 acceptance_test 必须就是 visual-qa — 测试必须命中 UI,而不是旁边的单元测试。这是高杠杆做法:无需提醒 Agent“记得重新检查”,因为 frame 自身的验证循环已经包含了 UI 检查。
- 设置
ui_role≠none的 frame:acceptance_test: "node skills/visual-qa/assets/route-shots.mjs --base <url> --route <route> --assert --user <u> --pass <p> --out <dir>"→ 若路由不是 200 / 内容为空,则退出码为 1 → 直到 UI 正确渲染,frame 才会变绿。每次修改后重新运行/br run= 自动重新验证。 - 变绿后,Agent
Read图像(技能/visual-qa)→FINDINGS.md(路由·级别·修复方法)→ 每条发现都对应 frame 的一次 spec+代码修改 → 再次运行/br run。可捕获主题/品牌/空状态问题,这些是单元测试发现不了的;在 MCP 扩展 localhost 出错时使用。 - 禁止在
/br run之外手动修改 UI(欠账 p28 05/07):手动修改 = 失去门禁 + 不会重新验证。所有 UI 修改都必须通过 frame。
参考 — Rail — 流水线的 harness 开关(/br rail on|off|skip)
“On the rails” = 正处于监管范围内。默认开启 — 使用 /br 时,整个会话自动开启。
python3 fdk/tools/br-rail.py status --root .→ 状态 + 始终提醒可以开启/关闭。on(全面监管)·off(关闭软门禁,直到再次开启)·skip(恰好跳过一次软门禁,然后自动重新开启 + 警告)。- 安全性(不变量):
off/skip只会关闭软门禁 — R7 content · visual-qa UI · assumption-gate。硬制动机制(diff-jail · test-hash · scope-clean)+ R1–R6 结构 + 安全 hook 永远不会通过此方式关闭。 - **接线:**在
/br run开始时,读取br-rail.py consume→ 若为off/skip,则调用frame-lint … --soft-off(跳过 R7+assumption),loop-runner 的硬制动机制仍保持不变;每次运行时输出 Rail 状态 + 提醒行。
参考 — 证据胜过说法(UI 检查规则 — 反馈 2026-07-13)
UI / 视觉检查只有在存在真实图片文件 + 列出 route→图片→字节数的 MANIFEST.json 时才有效(技能 /visual-qa)。没有文件 = 从未做过 = 失败,无论模型怎么说。修改 UI 后必须重新截图 + 重新查看,然后才能变绿。禁止靠推理“判定通过”。(这也是 /fdk 的规则。)