PR守护者Skill pr-shepherd

PR守护者技能用于自动监控GitHub Pull Requests的生命周期,包括处理CI失败、评论回复和线程解决,直到所有检查通过并准备好合并。关键词:GitHub、Pull Request、CI/CD监控、自动化修复、代码审查、DevOps、软件开发、自动化流程、GitHub Actions、测试、lint、类型检查、评论处理、线程解决、知识提取、BEADS任务。

DevOps 0 次安装 0 次浏览 更新于 3/24/2026

PR守护者

在PR创建后需要监控直到合并时使用 - 自动处理CI失败、评论和线程解决,直到所有检查通过和所有线程解决。

重要提示:此技能设计用于在工作树中工作的代理,而非协调器。代理处理自己的PR监控,以便协调器可以自由处理其他工作。

何时激活

当以下任一条件为真时激活此技能:

  • 代理刚用gh pr create创建了一个PR
  • 用户要求“守护”、“监控”或“跟进”一个PR
  • 用户调用/project:pr-shepherd <pr-number>
  • 用户要求“监视此PR”或“处理此PR直到合并”
  • 协调器以守护PR的指令生成您
  • 自动:使用bin/create-pr-with-shepherd.sh(输出守护指令)时

通过包装脚本自动激活

bin/create-pr-with-shepherd.sh创建PR时,它输出守护指令:

==========================================
  PR守护者活动:PR #123
==========================================

pr-shepherd技能将:
  - 监控CI/CD状态
  - 自动修复lint、类型和测试问题
  - 处理评论
  - 解决反馈后的线程
  - 报告PR何时准备好合并

手动稍后调用守护者:
  /project:pr-shepherd 123

当您看到此输出时,立即调用pr-shepherd技能,使用显示的PR编号。

开始时宣布

“我正在使用pr-shepherd技能来监控此PR直到合并。我将监视CI/CD、处理评论,并在问题出现时修复。”

对于协调器:生成带有PR守护的代理

当生成代理在工作树中工作时,在任务提示中包括PR守护:

在/path/to/worktree的分支feature/xyz上工作。

任务:[描述实现任务]

创建PR后:
1. 使用pr-shepherd技能监控直到合并
2. 自主处理CI失败和评论
3. 仅将复杂问题(需要用户输入)上报给协调器
4. 当PR准备好合并或受阻时报告

在后台运行,以便我可以继续其他工作。

关键原则:代理拥有其PR生命周期。协调器生成后忘记,通过AgentOutputTool在需要时检查。

状态机

代理在以下状态之一操作:

监控 → 修复 → 监控 → 等待用户 → 修复 → 监控 → 完成
状态 发生什么 何时退出
监控 在后台每60秒轮询CI和评论 CI失败、新评论、全部完成或需要帮助
修复 使用TDD修复问题,运行本地验证 本地验证通过或需要用户指导
处理评论 调用handling-pr-comments技能 评论处理或需要用户输入
等待用户 提供选项,等待用户决策 用户响应
完成 所有CI绿色 + 所有线程解决 成功退出

阶段1:初始化

# 获取PR信息
PR_NUMBER=$(gh pr view --json number -q .number 2>/dev/null)
OWNER=$(gh repo view --json owner -q .owner.login)
REPO=$(gh repo view --json name -q .name)

# 如果当前分支无PR,检查是否提供了编号
if [ -z "$PR_NUMBER" ]; then
  echo "当前分支未找到PR。提供PR编号。"
  exit 1
fi

echo "守护PR #$PR_NUMBER"

阶段2:监控循环(后台)

每60秒运行gtg以获取确定性的PR状态:

使用gtg获取PR状态

# 运行gtg并捕获JSON输出
# 注意:默认模式对所有可分析状态返回退出代码0
# 解析JSON的'status'字段以确定实际状态
gtg "$PR_NUMBER" --repo "$OWNER/$REPO" --format json > /tmp/gtg-status.json

# 解析JSON获取详细信息
STATUS=$(jq -r '.status' /tmp/gtg-status.json)
CI_STATE=$(jq -r '.ci_status.state' /tmp/gtg-status.json)
UNRESOLVED=$(jq -r '.threads.unresolved' /tmp/gtg-status.json)
ACTIONABLE_COUNT=$(jq -r '.actionable_comments | length' /tmp/gtg-status.json)

gtg退出代码模式

默认(AI友好):对所有可分析状态返回0,仅错误返回4。 解析JSONstatus字段以确定实际PR状态。

语义模式(-q--semantic-codes:根据不同状态返回不同的退出代码:

退出代码 状态 操作
0 READY → 完成(全部清除!)
1 ACTION_REQUIRED → 处理评论(需要处理的可操作评论)
2 UNRESOLVED_THREADS → 处理评论(需要解决的线程)
3 CI_FAILING → 修复(CI失败)
4 ERROR → 等待用户(API错误)

评估状态转换

推荐方法 - 解析JSON状态

case "$STATUS" in
  READY)
      echo "✅ PR已准备就绪!"
      # → 完成
      ;;
  ACTION_REQUIRED)
      echo "📝 需要处理的可操作评论"
      jq -r '.action_items[]' /tmp/gtg-status.json
      # → 处理评论
      ;;
  UNRESOLVED_THREADS)
      echo "💬 未解决的线程:$UNRESOLVED"
      # → 处理评论
      ;;
  CI_FAILING)
      echo "❌ CI失败:"
      jq -r '.ci_status.checks[] | select(.conclusion == "failure") | "  - \(.name)"' /tmp/gtg-status.json
      # → 修复(如果简单)或等待用户(如果复杂)
      ;;
  ERROR)
      echo "⚠️ 获取PR数据时出错"
      # → 等待用户
      ;;
esac

替代方法 - 为shell脚本使用语义退出代码

# 使用-q用于带有语义退出代码的安静模式
gtg "$PR_NUMBER" --repo "$OWNER/$REPO" -q
GTG_EXIT=$?

case $GTG_EXIT in
  0) echo "✅ READY" ;;
  1) echo "📝 ACTION_REQUIRED" ;;
  2) echo "💬 UNRESOLVED_THREADS" ;;
  3) echo "❌ CI_FAILING" ;;
  4) echo "⚠️ ERROR" ;;
esac

阶段3:修复问题

简单问题(自动修复)

无需用户批准即可修复:

  • Lint失败 → 运行pnpm lint
  • Prettier失败 → 运行pnpm prettier --write
  • 类型错误 → 修复类型
  • 在您编写的代码中测试失败 → 使用TDD修复

复杂问题(需要批准)

修复前需要用户输入:

  • 在您未编写的代码中测试失败
  • 基础设施/配置失败
  • 模糊错误
  • 任何您不确定的事情

修复状态规则

  1. 使用TDD - 调用superpowers:test-driven-development进行代码更改
  2. 保持直到绿色 - 在pnpm lint && pnpm typecheck && pnpm test --run通过前不要离开修复状态
  3. 仅在验证后推送 - 切勿推送本地验证失败的代码
  4. 推送后返回监控 - 让CI运行,继续监控
# 修复后,始终本地验证
pnpm lint && pnpm typecheck && pnpm test --run

# 仅在全部通过时推送
git add -A && git commit -m "fix: <description>" && git push

阶段4:处理评论

检测到新评论时:

  1. 调用goodtogo:handling-pr-comments技能
  2. 该技能处理分类、修复、响应和线程解决
  3. ⚠️ 关键:handling-pr-comments技能包括一个迭代循环
  4. 所有线程必须在返回监控前解决
  5. 如果线程无法解决(需要审阅者澄清),向评论作者询问后续操作
  6. 仅在以下情况返回监控:
    • 所有线程已解决,且
    • 推送后验证确认无新评论出现

迭代强制执行

⚠️ 第1失败模式:在一次通过后返回监控而不检查新评论。

handling-pr-comments技能的阶段7(推送后迭代检查)必须在退出处理评论状态前成功完成。技能将自动迭代:

处理评论:
  → handling-pr-comments技能(阶段1-7)
  → 如果阶段7发现新评论:技能重新运行阶段1-7
  → 如果阶段7确认无新评论:退出到监控

不要手动覆盖或跳过阶段7。如果您发现自己想跳过迭代,您即将犯第1错误。

范围外评论

审阅者可能留下PR差异外代码的评论。handling-pr-comments技能处理这些,但关键点:

  • 默认将范围外视为范围内 - 尊重审阅者反馈
  • 使用ultrathink评估修复是否快速(<30分钟,<3个文件)
  • 如果简单:立即修复并注明原范围外
  • 如果复杂:创建GitHub问题并在线程响应中链接
  • 始终响应并解决 - 不要让范围外线程悬而未决

阶段5:等待用户

需要用户输入时,始终:

  1. 清晰地呈现情况
  2. 提供2-4个选项及其优缺点
  3. 陈述您的推荐
  4. 允许用户选择或提供自己的方法

模板

[描述发生了什么]

**选项:**

1. **[选项名称]**(推荐)
   - [涉及什么]
   - 优点:[好处]
   - 缺点:[缺点]

2. **[选项名称]**
   - [涉及什么]
   - 优点:[好处]
   - 缺点:[缺点]

3. **[选项名称]**
   - [涉及什么]
   - 优点:[好处]
   - 缺点:[缺点]

您希望哪种方法?(或描述不同的方法)

用户响应后

  • 如果用户选择编号选项 → 执行该方法 → 修复
  • 如果用户描述替代方案 → 执行他们的方法 → 修复

阶段6:软超时(4小时)

经过4小时后,暂停并检查点:

**PR守护者检查点**(4小时已过)

当前状态:
- CI:[状态]
- 线程:[X] 已解决,[Y] 未解决
- 提交:[N] 修复提交已推送

**选项:**

1. **继续监控**(推荐)
   - 再继续4小时
   - 优点:PR可能很快被审阅
   - 缺点:占用代理资源

2. **退出并交接**
   - 保存状态报告,干净退出
   - 优点:释放资源
   - 缺点:必须稍后手动重新调用

3. **设置更短检查间隔**
   - 改为1小时而不是4小时检查
   - 优点:更频繁检查点
   - 缺点:更多中断

您希望做什么?(或描述不同的方法)

退出条件

成功(完成)

当所有以下为真时成功退出:

  • ✅ 所有CI检查通过
  • ✅ 所有审阅线程解决
  • ✅ 无待处理问题

报告:

**PR #[编号] 准备好合并** ✅

- CI:所有检查通过
- 审阅:所有线程解决
- 提交:[N] 总计([M] 修复提交)

PR已准备好最终批准和合并。

完成后的RAM清理

PR合并且知识提取任务创建后,调用自动RAM清理以释放资源:

/project:auto-ram-cleanup

原因:开发过程中(测试运行器、构建监视器、语言服务器)积累。合并后清理为下一个任务释放内存。

保持运行的内容

  • Docker容器(需要用于数据库/服务)
  • 基本IDE进程

清理的内容

  • 孤立测试运行器(vitest、jest)
  • 不再需要的构建监视器
  • 重复语言服务器实例
  • 其他开发工具残留

阶段7:合并后知识提取

重要提示:PR合并到主分支后,为知识提取创建一个阻塞BEADS任务。确保在Epic关闭前捕获CodeRabbit学习内容。

当PR合并时

检测PR已合并(或用户合并后):

# 检查PR是否合并
MERGED=$(gh pr view $PR_NUMBER --json merged -q .merged)

if [ "$MERGED" = "true" ]; then
  # 为知识管理创建BEADS任务
  bd create \
    --title="从PR #$PR_NUMBER提取学习内容" \
    --type=task \
    --priority=2 \
    --label="knowledge-extraction"

  # 从输出中记下新任务ID
  CURATION_TASK_ID="<bd创建输出中的id>"

  # 如果有相关Epic,将此任务添加为阻塞
  #(Epic在提取学习内容前无法关闭)
  if [ -n "$EPIC_ID" ]; then
    bd dep add "$EPIC_ID" "$CURATION_TASK_ID"
  fi
fi

报告给用户

创建管理任务时:

**PR #[编号] 成功合并** ✅

创建阻塞任务:[CURATION_TASK_ID]
- 标题:“从PR #[编号]提取学习内容”
- 状态:待处理
- 阻塞:[Epic(如果适用)]

提取学习内容,调用:
```
/project:curate-pr-learnings [编号]
```

该命令将:
1. 获取PR评论(确定性脚本)
2. AI分析并提取学习内容(您的工作)
3. 存储验证的学习内容(确定性脚本)

然后关闭任务:
```bash
bd close [CURATION_TASK_ID]
```

为何重要

  1. 安全:Webhook触发的代码执行是攻击面。CLI/代理调用更安全。
  2. 阻塞任务:Epic在提取学习内容前无法关闭,确保知识捕获。
  3. 代理自主性:代理可以从bd ready接取管理任务并处理。
  4. 人工监督:人类也可以通过CLI脚本手动运行管理。

对于Epic完成:提取对话学习内容

当此PR完成一个Epic(关闭最后一个阻塞任务)时,您还必须从对话历史中提取学习内容。功能工作通常包含最丰富的架构讨论。

检测Epic完成

注意:此模式假设单Epic工作流。如果多个Epic进行中,.[0]选择第一个,可能不是与此PR相关的Epic。 对于多Epic项目,手动将PR的任务关联到其阻塞Epic。

# 检查此PR是否关闭一个Epic(假设单进行中Epic)
EPIC_ID=$(bd list --status=in_progress --type=epic --json | jq -r '.[0].id // empty')

if [ -n "$EPIC_ID" ]; then
  # 检查此PR关闭后Epic是否不再有阻塞
  REMAINING_BLOCKERS=$(bd show "$EPIC_ID" --json | jq '[.blockedBy[] | select(.status != "closed")] | length')

  if [ "$REMAINING_BLOCKERS" -eq 0 ]; then
    echo "此PR完成Epic $EPIC_ID - 需要对话提取"
  fi
fi

如果Epic完成

  1. 为对话提取创建BEADS任务:

    CONV_TASK_ID=$(bd create \
      --title="从Epic $EPIC_ID对话提取学习内容" \
      --type=task \
      --priority=2 \
      --label="knowledge-extraction")
    
    # 阻止Epic直到提取完成
    bd dep add "$EPIC_ID" "$CONV_TASK_ID"
    
  2. 将任务报告给用户:

    **检测到Epic完成** 🎯
    
    此PR完成Epic $EPIC_ID。创建对话提取任务:
    - 任务:$CONV_TASK_ID
    - 标题:“从Epic对话提取学习内容”
    - 状态:阻塞Epic关闭
    
    关闭Epic前,运行:
    /project:extract-learnings --historical --recent 10
    
    然后关闭提取任务:
    bd close $CONV_TASK_ID
    bd close $EPIC_ID
    

为何从对话提取?

  • 战略洞察:讨论的架构决策、权衡
  • 调试发现:调查后找到的根本原因
  • 非明显行为:“原来…”的时刻
  • 集成怪癖:导致问题的API行为

这些学习内容通常不在CodeRabbit评论中 - 它们在来回对话中。

带交接的超时

如果用户在检查点选择退出:

**PR #[编号] 守护者交接**

退出时状态:
- CI:[状态]
- 线程:[X] 已解决,[Y] 未解决
- 最后活动:[时间戳]

恢复:`/project:pr-shepherd [编号]`

调用的技能

情况 技能
新评论 goodtogo:handling-pr-comments
需要代码更改 superpowers:test-driven-development
复杂调试 superpowers:systematic-debugging

强制完成前检查

⚠️ 阻塞:在宣布任何PR准备好前,您必须运行gtg并验证READY状态

# 选项1:解析JSON状态(推荐用于AI代理)
gtg "$PR_NUMBER" --repo "$OWNER/$REPO" --format json > /tmp/gtg-final.json
STATUS=$(jq -r '.status' /tmp/gtg-final.json)

if [ "$STATUS" != "READY" ]; then
  echo "PR未准备就绪:$STATUS"
  jq -r '.action_items[]' /tmp/gtg-final.json
  exit 1
fi

# 选项2:使用语义退出代码(用于shell脚本)
gtg "$PR_NUMBER" --repo "$OWNER/$REPO" -q
echo "退出代码:$?"

gtg退出代码模式

默认模式(AI友好):对所有可分析状态返回0,仅错误返回4。 解析JSONstatus字段以确定实际PR状态。

语义模式-q--semantic-codes):

退出 状态 意义
0 READY ✅ 全部清除 - 准备好!
1 ACTION_REQUIRED ❌ 需要修复的可操作评论
2 UNRESOLVED_THREADS ❌ 未解决的审阅线程
3 CI_FAILING ❌ CI检查失败
4 ERROR ❌ 获取数据时出错

如果状态不是READY,您尚未完成。 解决每个问题:

对于每个无回复的顶级评论(其中in_reply_to_id为null):

  1. 如果可操作 → 修复它并回复确认修复
  2. 如果范围外 → 回复解释推迟(如果需要则创建问题)
  3. 如果不同意 → 回复并解释
  4. 切勿静默忽略

在通过回复解决每个顶级评论前,PR未准备好。

验证清单

退出完成状态前:

  • [ ] 所有CI检查绿色
  • [ ] 所有审阅线程解决
  • [ ] 无待处理用户问题
  • [ ] 最终状态报告给用户

PR合并后(阶段7):

  • [ ] 为知识管理创建BEADS任务
  • [ ] 将任务添加为Epic阻塞(如果适用)
  • [ ] 将管理任务ID报告给用户

所有合并后任务完成后:

  • [ ] 运行/project:auto-ram-cleanup以释放开发资源
  • [ ] 确认Docker容器仍运行(如果需要)

常见错误

🚨 第1错误:返回监控而不检查新评论

  • 推送修复并响应线程后,您必须运行阶段7
  • 自动审阅者(CodeRabbit、Cursor)分析每个提交
  • 新评论通常在你推送后1-2分钟内出现
  • 如果您跳过阶段7,您将错过新评论并过早宣布完成

无本地验证推送

  • 切勿推送未通过pnpm lint && pnpm typecheck && pnpm test --run的代码

自动修复复杂问题

  • 如果不确定,询问。始终通过等待用户处理复杂问题。

忘记调用handling-pr-comments

  • 新评论到达时,委派给该技能。不要内联处理评论。

不向用户提供选项

  • 始终提供2-4个选项及其优缺点。不要只问“我该做什么?”

过早离开修复状态

  • 停留在修复状态直到本地验证通过。不要假设修复有效。

跳过handling-pr-comments迭代循环

  • 该技能有阶段1-7,具有显式迭代循环
  • 阶段7在您修复推送后检查新评论
  • 如果阶段7发现新评论,技能循环回阶段1
  • 不要提前退出 - 让技能完成其完整迭代