rig-epic — 集成分支工作流
对于需要多个项目,但直接将每个项目提交到主干可能会暂时破坏运行时契约的复杂任务,可以在共享的集成分支上堆叠子 PR,最后将该分支压缩成一个 PR 合并到主干。每个子 PR 都按其实际步骤进行审查;而最终提交到主干的交付则是一次压缩后的变基提交。
配置
读取 .rig/config.json(括号内为默认值):
tracker.provider—linear|github|none(none)。父子项目的存储方式。none→ 项目仅存在于史诗状态文件(见下文)中;不调用跟踪器。tracker.team/tracker.project/tracker.ticketPrefix/tracker.githubIntegration。vcs.baseRef(origin/main),vcs.defaultBranch(main),vcs.protectedBranchMergeQueue(false)。sourceScope[0]— 在plan期间探索的范围。agents.architect/agents.reviewer(默认rig-<role>) — 用于新上下文的review面板。
委托给 /rig-task(每个子项目)、/rig-worktree(检出)、/rig-review + /rig-review fix(组合差异审查)、/rig-tidy(可选)。
史诗状态文件(替代外部内存)
每个活跃的史诗都在仓库本地的 JSON 文件中跟踪,路径为 .rig/epics/<integration-branch>.json:
{
"parent": "ABC-42 或 tracker=none 时的 slug",
"parentTitle": "…",
"integrationBranch": "abc-42-<slug>",
"whyEpic": "哪些子项目交错以及原因",
"children": [
{ "id": "ABC-43", "title": "…", "blockedBy": [], "branch": null, "status": "todo|merged" }
]
}
这是 next/run/review/finish/prune 读取的唯一真实来源。将 .rig/epics/ 添加到 .gitignore(这是临时协调状态)。父项目推断(当 <PARENT> 省略时):如果恰好存在一个 .rig/epics/*.json,则使用它;如果零个或多个,则询问。
意图横幅: 每次调用都必须在第一行打印 — 模式、PR 目标分支、不会做什么:
rig-epic: <子命令> — <操作>。PR 目标分支为 <branch>。不会 <thing>。
status(默认,仅报告)
读取史诗状态文件。报告:集成分支 + 领先 vcs.baseRef 的提交数;开放的子 PR(gh pr list --base <integration-branch>)及其状态;每个子项目的跟踪器状态(如果存在跟踪器);剩余已合并/已删除的工作树(建议 /rig-epic prune);以及一行建议(打开子 PR X、准备就绪:/rig-epic next 或 准备就绪:/rig-epic finish)。不修改任何内容;不创建任何内容。
plan <FEATURE>
将一个功能分解为一个父项目 + 3–8 个子项目,写入状态文件,然后链接到 start。
仅当工作确实具有史诗形态(子项目交错 — 至少一个子项目的运行时契约依赖于另一个子项目部分完成)时使用。如果项目是独立的,并且每个项目都可以单独提交到主干,则停止并告诉用户运行 /rig-sprint plan — 相同的分解,无需集成分支。
步骤
- 读取上下文。 如果项目有产品/规格文档,则阅读(如果不确定则询问);探索代码库(
sourceScope[0])以查看现有内容。如果配置了跟踪器,首先搜索接近重复的项目。 - 合理性检查它是否是一个史诗(根据上述交错测试)。如果不是 → 发送到
/rig-sprint plan。 - 创建父项目。
tracker: linear/github→ 创建父项目(来自配置的团队/项目);描述涵盖概述、为什么是史诗以及计划的子项目。tracker: none→ 父项目是仅记录在状态文件中的 slug + 标题。
- 创建每个子项目及其依赖边。
- 足够小,适合单个代理会话(1–3 个文件);具体、可测试的验收标准;首先完成基础工作。
- 为每个真实依赖记录
blockedBy— 这是next用来选择下一个未阻塞子项目的依据。没有它,选择将回退到声明顺序,从而导致交错的史诗出错。 - 跟踪器模式:设置跟踪器的本机父/阻塞依赖关系,并将它们镜像到状态文件中。
none:仅状态文件。
- 显示摘要表(ID · 标题 · 依赖项)。
- 链接到
start <PARENT>—plan即是规划并启动;不要停下来询问。 - 在
start后停止。 报告集成分支、子项目以及下一步(单个子项目用/rig-epic next,循环用/rig-epic run)。从不自动启动run— 执行是显式选择加入的。
start <PARENT>
预检:git fetch origin;确认父项目和至少一个子项目存在(在跟踪器中,或者对于 none 作为参数)。
- 集成分支名称:
<parent-slug>-<title-slug>(kebab 风格,例如abc-42-agent-as-definition)。 - 从
vcs.baseRef切出集成分支,无需本地检出:
非破坏性。如果分支已存在,则保留它(绝不覆盖 — 可能销毁正在进行的工作)。git fetch origin git push origin <vcs.baseRef>:refs/heads/<integration-branch> - 写入
.rig/epics/<integration-branch>.json(上面是 schema),包含父项目、为何是史诗以及每个子项目 +blockedBy。这使每个/rig-task <child>都针对集成分支而不是主干。 - 如果配置了跟踪器,为每个子项目添加一条“集成分支:目标
<integration-branch>,而不是主干”的注释,以便下一个代理不会重新读取此技能,并确保父项目处于进行中状态(自适应:仅当尚未开始时移动;如果实时集成已关闭则推迟)。子项目从其/rig-task步骤 1 获取自己的进行中状态。 - 将会话命名为
"EPIC: <父标题> (<父项目>)"通过scripts/set-session-name.sh(仅限 Claude Code;其他地方无操作),以便后台作业列表显示为史诗。子项目使用--skip-if-prefix "EPIC:"设置自己的FEAT:/CHORE:名称,因此此史诗标签保持在顶部。 - 报告分支、子项目以及下一步。
next(单个子项目)
- 解析活动的集成分支(期望一个;如果多个则询问)。如果会话尚未以
EPIC:命名(即next直接调用,而不是通过start),则将其命名为"EPIC: <父标题> (<父项目>)"(仅限 Claude Code)。 - 选择下一个未阻塞的子项目: 第一个未完成且其
blockedBy都已合并到集成分支的子项目。在横幅中说明选择 + 理由。 - 确保前一个子项目已落地。 使用
--auto-merge(步骤 4),每个子项目的 PR 在 CI 通过后会自动合并到集成分支,因此集成分支顶端会自动推进 — 只需git fetch origin并确认。(对于没有--auto-merge运行的子项目的回退:将其分支快进到其顶端 —git push origin origin/<previous-child-branch>:refs/heads/<integration-branch>,这会将那个 PR 自动关闭为已合并。重复运行是安全的。) - 运行
/rig-task <CHILD> --base <integration-branch> --auto-merge(当run的前置规范审查已经清除了规范时,添加--spec-cleared)—--base使子项目的工作树分支和其 PR 目标都指向集成分支;--auto-merge使子项目在自身审查通过后,为其 PR 启用gh pr merge --squash --auto,以便 CI 将其落地到集成分支(始终 squash — 不要 rebase-merge;许多仓库禁止这样做。如果集成分支没有必需的检查,子项目会直接合并)。一次性运行(开始→完成);它为合并门返回一个单一的结果字符串。 - 合并门 — 只有
clean是合并绿色:clean→ 子项目启用了自动合并,因此其 PR 在 CI 通过时落地。等待:轮询gh pr view <N> --json state(~60 秒,最多 ~30 分钟)直到MERGED,然后git fetch origin并确认顶端已推进。在状态文件中记录子项目merged及其分支,并确保子项目工单已完成(自适应 — 仅当尚未完成时移动;如果实时集成已关闭则推迟)。如果 CI 失败 / 从未合并 → 视为 not-clean。- 其他任何情况(
actionable/timeout,或跟踪器暂停状态)→ 子项目未启用自动合并;停止。展示结果、PR URL 以及任何审查者摘要。等待用户;不要重试暂停的审查。
next 只处理一个子项目。使用 run 进行循环。
run [--advisor]
前置规范审查 — 一次,在循环之前。 提前一起审查所有子项目的规范,而不是在运行过程中逐个发现阻塞因素。一个因规范问题暂停的子项目会拖慢整个史诗(并且在并行或持久执行下,暂停的子项目可能导致整个批次失败),因此在任何子项目开始编码之前解决规范问题:
- 将
agents.architect+agents.qa分派到每个子项目的规范中,对照集成分支进行审查;每个返回其阻塞因素。 - 整合成一个阻塞因素列表并一次性解决 — 在跟踪器中澄清,或与用户决定。这是史诗的单一规范决策点。
- 然后运行每个子项目,其自己的规范门已预清除:
/rig-task <CHILD> --base <integration-branch> --auto-merge --spec-cleared,这样就没有子项目会再次暂停在已经回答的问题上。
这是编码前的规范检查;合并后的差异 review(见下文)是合并后的代码检查 — 不同的门。
--advisor(无人值守)。 使用顾问检查(而不是人为干预)来决定前置门:委托的 agents.architect 审查读取架构师 + QA 规范,并要么继续,附带合成的每个子项目方向(逐字传递给每个子项目的编码器),要么停止,并附带一个阻塞报告,指定必须由人决定的内容。没有人为等待,因此史诗可以无人干预地运行到子 PR;真正的阻塞因素仍然会阻止它,而不是在错误的规范上展开。(配对的 Smithers 持久工作流使用一个廉价模型实现此功能 — “Fable advisor” — 因此启动的史诗永远不会在门口停留。)
然后循环 next,直到没有未阻塞的子项目为止:
当存在未阻塞的子项目时:
运行 /rig-epic next # 子项目以 --spec-cleared 运行(规范已预先加载)
如果它未合并就停止(结果 ≠ clean)→ 停止,交回控制权
否则 → 重新评估未阻塞的子项目
当队列为空时,报告“史诗准备就绪:/rig-epic finish。”
review [<PARENT>]
在最后一个子项目合并到集成分支之后,finish 之前运行。每个 PR 的审查(每个 /rig-task 内的 /rig-review)会孤立地看待每个子项目;此审查看到的是组合形态和只有在所有东西都到位后才可见的简化。新上下文子代理(输入 = 压缩后的差异 + 子 PR 标题)无法继承实现者记住的合理化理由。
在 prune 之前运行 — 审查子代理需要工作的检出;如果存在,重用子项目工作树(避免重新安装 + 重新符号链接环境)。
- 解析集成分支;
git fetch origin。 - 确保集成分支工作树 (
$WT)。快进一个已合并的子项目工作树到集成分支顶端,否则使用/rig-worktree创建一个(--base <integration-branch> --reuse)。 - 并行分派三个子代理(一条消息,三个
Agent调用),每个cd进入$WT,检出集成分支顶端:- 视角 1 — 简化 (
agents.architect): 差异git diff <vcs.baseRef>...HEAD;通过gh pr list --base <BR> --state merged获取子 PR 列表。任务:找到可以折叠的抽象、一个 PR 添加但另一个 PR 的最终形态使其多余的辅助工具、没有人设置的配置旋钮、组合差异使其失效的代码路径、单调用者类型。具体的删除/合并,文件:行,影响最高者优先。跳过正确性。 - 视角 2 — 跨 PR 正确性 (
agents.reviewer): 将项目的审查模式目录 (review.patternsFile) 应用于组合差异。单个 PR 的审查已经运行;捕获仅在合并形态下可见的交互(PR-A 的辅助工具 vs PR-D 的过时调用者;PR-B 移除了 PR-F 仍然读取的旋钮)。P0/P1/P2 级别,附带文件:行 + 类别。 - 视角 3 — 死代码和过时引用 (
agents.reviewer): 对于差异添加的每个符号,它在其他地方被调用吗?对于删除的每个符号,使用 grep 搜索树(工作流、清单、IaC、脚本、文档)以查找残留引用。附带文件:行报告。
- 视角 1 — 简化 (
- 整合 — 去重,生成一个按视角分组的 P0/P1/P2 列表,打印计数。
- 分类:
- 0 个项目 →
clean — 准备就绪:/rig-epic finish,停止。 - 发现问题 → 通过
AskUserQuestion询问:立即应用/跳过并仍然完成(降级为后续任务) /暂停。如果选择立即应用,在$WT中运行/rig-review fix --source local(生成agents.coder,重新审查直至干净),提交 +git push origin <integration-branch>,再次运行review以确认收敛。
- 0 个项目 →
- 结果字符串(供
finish使用):clean — …/applied — …/paused — …。
finish [<PARENT>] [--merge]
将整个集成分支压缩成一个 PR 提交到主干。默认:打开 PR 并停止 — 这是需要仔细检查的一个 PR。
review 是一个硬性门。 finish 总是首先运行 review;只有在 clean 或 applied 时才打开 squash PR。如果是 paused,停止并等待。
- **运行
review(门)**内联;根据其结果分支(clean/applied→ 继续;paused→ 停止并打印待处理的问题)。 - 如有必要刷新并变基。
git fetch origin;列出git log <vcs.baseRef>..origin/<integration-branch> --oneline。如果主干有移动,先将集成分支变基到它上面(在本地副本上执行git rebase <vcs.baseRef>,然后git push --force-with-lease origin <local>:<integration-branch>)。 - 打开最终 PR 到
vcs.defaultBranch,标题引用父项目,正文总结所有子项目。在使用具有关闭动词的跟踪器(Fixes <PARENT>/Closes #<n>)时,包含它以便父项目在合并后自动关闭。
...
[为翻译截断]