跳到正文
cccskills
免费在 GitHub 公开中文介绍

pr-polish

反复审查和修复PR,检查未解决的讨论、评论回复、自动检查及合并冲突,并等待延迟到达的评论,将PR整理到可以合并的状态。

原文查看原文说明

Alternate /pr-review and /pr-address on a PR until the PR is truly mergeable — no new review findings, zero unresolved inline threads, zero unaddressed top-level reviews or issue comments, all CI checks green, and two consecutive quiet polls after CI settles. Use when the user wants a PR polished to merge-ready without setting a fixed number of rounds.

集成工具GitHubSentry

实测评分 未实测

查看安装方法

适用场景

  • 将PR整理到可合并状态
  • 反复修复直到没有新问题
  • 处理延迟到达的机器人审查
  • 检查CI失败和合并冲突

中文介绍

功能

这项技能交替执行/pr-review和/pr-address,将PR整理到可以合并的状态。它反复审查和修复,直到没有新问题,并检查逐行讨论是否解决、审查和评论是否得到回复、CI自动检查的结果以及合并冲突。它会查询GitHub的实际状态,不会仅凭各步骤的摘要判断工作已经完成。

适用场景

适合希望一次委托完成审查、修复和再次检查的情况。CI结束后,它会以至少60秒的间隔,连续两次确认没有新反馈,以便处理延迟到达的审查。若已请求的机器人审查尚未回复,会在等待时限内继续等候。

使用示例

  • “反复审查并修复这个PR,直到没有新问题。”
  • “检查未解决的评论和CI,将PR整理到可以合并的状态。”

注意事项

该流程使用/pr-review、/pr-address、GitHub CLI的gh、jq等工具,会提交并推送修改,也会回复评论。最多重复10轮,等待已请求的机器人审查最多60分钟。完成条件不包含实际合并PR。

本介绍由 AI(OpenAI Codex)根据公开的 SKILL.md 撰写。准确的规格请查看下方原文。

文档检查

AI 根据 SKILL.md 的内容检查了需要注意的操作和使用前提。评分只依据实际运行的结果(实测对比)。

安全性发送数据、删除文件、执行命令等是否有说明
C需确认发布审查及可选的gh pr comment发送操作均没有事前确认步骤。
安装难易度所需工具和 API 密钥是否少且有说明
B部分不足依赖pr-review、pr-address、gh和jq,但未提供安装或身份验证步骤。

不计入评分。 由 AI(OpenAI Codex)于 2026年10月23日 评估。仅供参考,安装前请同时查看原文。

如果您认为评估有误,请申请复核

请写明哪一项有误以及原因。无需登录。我们会对照 SKILL.md 重新评估,并在此处更新结果。

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

包含的文件(1)

  • SKILL.md19.6 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

PR Polish

Goal. Drive a PR to merge-ready by alternating /pr-review and /pr-address until all of the following hold:

  1. The most recent /pr-review produces zero new findings (no new inline comments, no new top-level reviews with a non-empty body).
  2. Every inline review thread reachable via GraphQL reports isResolved: true.
  3. Every non-bot, non-author top-level review has been acknowledged (replied-to) OR resolved via a thread it spawned.
  4. Every non-bot, non-author issue comment has been acknowledged (replied-to).
  5. Every CI check is conclusion: "success" or "skipped" / "neutral" — none "failure" or still pending.
  6. Two consecutive post-CI polls (≥60s apart) stay clean — no new threads, no new non-empty reviews, no new issue comments. Bots (coderabbitai, sentry, autogpt-pr-reviewer) frequently post late after CI settles; a single green snapshot is not sufficient.
  7. No requested-but-unanswered review. If a /review comment was posted on the PR and the review bot has not replied yet, quiet polls do not count toward condition 6 — keep polling until the review lands or the wait budget expires. See Waiting on a requested bot review.

Do not stop at a fixed number of rounds. If round N introduces new comments, round N+1 is required. Cap at _MAX_ROUNDS = 10 as a safety valve, but expect 2–5 in practice.

TodoWrite

Before starting, write two todos so the user can see the loop progression:

  • Round {current}: /pr-review + /pr-address on PR #{N} — current iteration.
  • Final polish polling: 2 consecutive clean polls, CI green, 0 unresolved — runs after the last non-empty review round.

Update the current round counter at the start of each iteration; mark completed only when the round's address step finishes (all new threads addressed + resolved).

Find the PR

ARG_PR="${ARG:-}"
# Normalize URL → numeric ID if the skill arg is a pull-request URL.
if [[ "$ARG_PR" =~ ^https?://github\.com/[^/]+/[^/]+/pull/([0-9]+) ]]; then
  ARG_PR="${BASH_REMATCH[1]}"
fi
PR="${ARG_PR:-$(gh pr list --head "$(git branch --show-current)" --repo Significant-Gravitas/AutoGPT --json number --jq '.[0].number')}"
if [ -z "$PR" ] || [ "$PR" = "null" ]; then
  echo "No PR found for current branch. Provide a PR number or URL as the skill arg."
  exit 1
fi
echo "Polishing PR #$PR"

The outer loop

round = 0
while round < _MAX_ROUNDS:
    round += 1
    baseline = snapshot_state(PR)   # see "Snapshotting state" below
    invoke_skill("pr-review", PR)   # posts findings as inline comments / top-level review
    findings = diff_state(PR, baseline)
    if findings.total == 0:
        break  # no new findings → go to polish polling
    invoke_skill("pr-address", PR)  # resolves every unresolved thread + CI failure
# Post-loop: polish polling (see below).
polish_polling(PR)

Optional: the review bot

invoke_skill("pr-review", PR) is the agent's own review and always runs every round. In addition to it, the repo's review bot can be summoned on demand by commenting /review on the PR (see the open-pr skill):

gh pr comment "${PR}" --body "/review"

This is an option, not a required step, and it is not a substitute for the /pr-review round — use it when you want a second opinion the outer loop cannot produce itself, or when the PR carries no bot findings at all yet. Bot findings land as inline threads and top-level reviews, exactly like the agent's own findings, so both feed the same invoke_skill("pr-address", PR) step — no separate handling is needed. If you do request one, the exit conditions must wait for it; see Waiting on a requested bot review.

Snapshotting state

Before each /pr-review, capture a baseline so the diff after the review reflects only what the review just added (not pre-existing threads):

# Inline threads — total count + latest databaseId per thread
gh api graphql -f query="
{
  repository(owner: \"Significant-Gravitas\", name: \"AutoGPT\") {
    pullRequest(number: ${PR}) {
      reviewThreads(first: 100) {
        totalCount
        nodes {
          id
          isResolved
          comments(last: 1) { nodes { databaseId } }
        }
      }
    }
  }
}" > /tmp/baseline_threads.json

# Top-level reviews — count + latest id per non-empty review
gh api "repos/Significant-Gravitas/AutoGPT/pulls/${PR}/reviews" --paginate \
  --jq '[.[] | select((.body // "") != "") | {id, user: .user.login, state, submitted_at}]' \
  > /tmp/baseline_reviews.json

# Issue comments — count + latest id per non-bot, non-author comment.
# Bots are filtered by User.type == "Bot" (GitHub sets this for app/bot
# accounts like coderabbitai, github-actions, sentry-io). The author is
# filtered by comparing login to the PR author — export it so jq can see it.
AUTHOR=$(gh api "repos/Significant-Gravitas/AutoGPT/pulls/${PR}" --jq '.user.login')
# Slash-command triggers are excluded here too: a `/review` posted by a
# maintainer is non-bot and non-author, so without this it enters the baseline
# and later registers as a "new finding", forcing an address round over a
# comment with nothing to address.
gh api "repos/Significant-Gravitas/AutoGPT/issues/${PR}/comments" --paginate --slurp \
  | jq --arg author "$AUTHOR" \
      '[.[][] | select(.user.type != "Bot" and .user.login != $author)
             | select((.body // "") | test("^\\s*/[a-z-]+\\s*$") | not)
             | {id, user: .user.login, created_at}]' \
  > /tmp/baseline_issue_comments.json

Diffing after a review

After /pr-review runs, any of these counting as "new findings" means another address round is needed:

  • New inline thread id not in the baseline.
  • An existing thread whose latest comment databaseId is higher than the baseline's (new reply on an old thread).
  • A new top-level review id with a non-empty body.
  • A new issue comment id from a non-bot, non-author user.

If any of the four buckets is non-empty → not done; invoke /pr-address and loop.

Polish polling

Once /pr-review produces zero new findings, do not exit yet. Bots (coderabbitai, sentry, autogpt-pr-reviewer) commonly post late reviews after CI settles — 30–90 seconds after the final push. Poll at 60-second intervals:

NON_SUCCESS_TERMINAL = {"failure", "cancelled", "timed_out", "action_required", "startup_failure"}
clean_polls = 0
required_clean = 2
while clean_polls < required_clean:
    # 1. CI gate — any terminal non-success conclusion (not just "failure")
    # must trigger /pr-address. "success", "skipped", "neutral" are clean;
    # anything else (including cancelled, timed_out, action_required) is a
    # blocker that won't self-resolve.
    ci = fetch_check_runs(PR)
    if any ci.conclusion in NON_SUCCESS_TERMINAL:
        invoke_skill("pr-address", PR)  # address failures + any new comments
        baseline = snapshot_state(PR)   # reset — push during address invalidates old baseline
        clean_polls = 0
        continue
    if any ci.conclusion is None (still in_progress):
        sleep 60; continue  # wait without counting this as clean

    # 2. Comment / thread gate
    threads = fetch_unresolved_threads(PR)
    new_issue_comments = diff_against_baseline(issue_comments)
    new_reviews = diff_against_baseline(reviews)
    if threads or new_issue_comments or new_reviews:
        invoke_skill("pr-address", PR)
        baseline = snapshot_state(PR)   # reset — the address loop just dealt with these,
                                        # otherwise they stay "new" relative to the old baseline forever
        clean_polls = 0
        continue

    # 3. Mergeability gate
    mergeable = gh api repos/.../pulls/${PR} --jq '.mergeable'
    if mergeable == false (CONFLICTING):
        resolve_conflicts(PR)  # see pr-address skill
        clean_polls = 0
        continue
    if mergeable is null (UNKNOWN):
        sleep 60; continue

    # 4. Pending-review gate — a /review with no bot answer yet.
    # Quiet is exactly what a bot still thinking looks like, so don't bank
    # a clean poll on it. review_requested_but_unanswered() already returns
    # false once REVIEW_WAIT_BUDGET is spent, so the loop cannot hang here.
    if review_requested_but_unanswered(PR):
        sleep 60; continue

    clean_polls += 1
    sleep 60

Only after clean_polls == 2 do you report ORCHESTRATOR:DONE.

Concrete CI fetch (don't parse gh pr checks text columns)

The fetch_check_runs(PR) step above must use --json, not the default text output. Job names can contain spaces and parentheses (e.g. test (3.11), Analyze (python)), so gh pr checks $PR | awk '{print $2}' extracts (3.11) instead of the status — leading to a clean-poll firing while jobs are still pending.

# Reliable: use --json so columns are unambiguous.
ci_json=$(gh pr checks $PR --repo Significant-Gravitas/AutoGPT --json name,state,bucket)
pending=$(echo "$ci_json" | jq '[.[] | select(.bucket == "pending")] | length')
failed=$(echo "$ci_json" | jq '[.[] | select(.bucket == "fail" or .bucket == "cancel")] | length')

# Buckets are: pass | fail | pending | cancel | skipping
# (NOTE: gh pr checks does NOT expose `conclusion` as a JSON field —
# only `bucket`. Don't confuse with the GitHub REST API's check_runs
# endpoint, which DOES use conclusion.)

Map back to the pseudocode above: bucket == "pending" is ci.conclusion is None (still in_progress); bucket in {"fail", "cancel"} is ci.conclusion in NON_SUCCESS_TERMINAL; bucket in {"pass", "skipping"} is clean.

Waiting on a requested bot review

autogpt-pr-reviewer[bot] typically takes ~30 minutes to answer a /review — far longer than the 60-second poll interval, so without this gate two clean polls would report ORCHESTRATOR:DONE while the requested review is still in flight.

review_requested_but_unanswered(PR) is:

Recompute from the API on every poll — never track elapsed time in a loop variable, which is how this gate becomes an infinite wait. --paginate concatenates one array per page, so last picks the last item of the final page rather than the newest overall; use --slurp and max_by. An answer is either a top-level review or an inline review comment, whichever is later — an inline-only reply is still an answer, and counting only top-level reviews left the gate waiting after its threads had already been addressed.

# `--slurp` cannot be combined with `--jq`; pipe to standalone jq instead.
REQUESTED_AT=$(gh api "repos/Significant-Gravitas/AutoGPT/issues/${PR}/comments" --paginate --slurp \
  | jq -r '[.[][] | select((.body // "") | test("^\\s*/review\\s*$"))] | max_by(.created_at) | .created_at // empty')
REVIEWED_AT=$(gh api "repos/Significant-Gravitas/AutoGPT/pulls/${PR}/reviews" --paginate --slurp \
  | jq -r '[.[][] | select(.user.login == "autogpt-pr-reviewer[bot]")] | max_by(.submitted_at) | .submitted_at // empty')
COMMENTED_AT=$(gh api "repos/Significant-Gravitas/AutoGPT/pulls/${PR}/comments" --paginate --slurp \
  | jq -r '[.[][] | select(.user.login == "autogpt-pr-reviewer[bot]")] | max_by(.created_at) | .created_at // empty')
ANSWERED_AT=$(printf '%s\n%s\n' "$REVIEWED_AT" "$COMMENTED_AT" | grep -v '^$' | sort | tail -1)

# Pending iff a request exists and no answer is strictly newer than it.
# Start every poll from `false`: a stale `true` from the previous poll would
# otherwise keep the gate waiting after the answer has already landed.
# `[ a \< b ]` is not portable (fails under zsh), so compare via sort.
pending=false
NEWEST=$(printf '%s\n%s\n' "$REQUESTED_AT" "$ANSWERED_AT" | grep -v '^$' | sort | tail -1)
if [ -n "$REQUESTED_AT" ] && { [ -z "$ANSWERED_AT" ] || [ "$NEWEST" = "$REQUESTED_AT" ]; }; then
  pending=true
fi

REVIEW_WAIT_BUDGET = 60 minutes, measured as now - REQUESTED_AT:

# Only meaningful when a request exists: GNU date reads an empty string as
# "now", BSD date errors, and either way there is nothing to time out.
if [ -n "$REQUESTED_AT" ]; then
  WAITED=$(( $(date +%s) - $(date -u -j -f "%Y-%m-%dT%H:%M:%SZ" "$REQUESTED_AT" +%s 2>/dev/null || date -u -d "$REQUESTED_AT" +%s) ))
  [ "$WAITED" -ge 3600 ] && pending=false   # budget spent — stop waiting
fi

An observed reply on this repo took 46 minutes, so a 45-minute budget would have abandoned a review that was about to arrive. 60 gives headroom.

Past the budget, stop waiting, resume counting clean polls normally, and note in the final report that the requested bot review never arrived. The loop must never hang on a bot.

Never post a second /review while one is unanswered. Check review_requested_but_unanswered(PR) before triggering, not just before exiting — otherwise each round requests another review and the bot answers a queue of duplicates.

Why 2 clean polls, not 1

A single green snapshot can be misleading — the final CI check often completes ~30s before a bot posts its delayed review. One quiet cycle does not prove the PR is stable; two consecutive cycles with no new threads, reviews, or issue comments arriving gives high confidence nothing else is incoming.

Why checking every source each poll

/pr-address polling inside a single round already re-checks its own comments, but /pr-polish sits a level above and must also catch:

  • New top-level reviews (autogpt-pr-reviewer sometimes posts structured feedback only after several CI green cycles).
  • Issue comments from human reviewers (not caught by inline thread polling).
  • Sentry bug predictions that land on new line numbers post-push.
  • Merge conflicts introduced by a race between your push and a merge to dev.

Invocation pattern

Delegate to existing skills with the Skill tool; do not re-implement the review or address logic inline. This keeps the polish loop focused on orchestration and lets the child skills evolve independently.

Skill(skill="pr-review",  args=pr_url)
Skill(skill="pr-address", args=pr_url)

After each child invocation, re-query GitHub state directly — never trust a summary for the stop condition. The orchestrator's ORCHESTRATOR:DONE is verified against actual GraphQL / REST responses per the rules in pr-address's "Verify actual count before outputting ORCHESTRATOR:DONE" section.

Auto-continue: do NOT end your response between child skills

/pr-polish is a single orchestration task — one invocation drives the PR all the way to merge-ready. When a child Skill() call returns control to you:

  • Do NOT summarize and stop.
  • Do NOT wait for user confirmation to continue.
  • Immediately, in the same response, perform the next loop step: state diff → decide next action → next Skill() call or polling sleep.

The child skill returning is a loop iteration boundary, not a conversation turn boundary. You are expected to keep going until one of the exit conditions in the opening section is met (2 consecutive clean polls, _MAX_ROUNDS hit, or an unrecoverable error).

If the user needs to approve a risky action mid-loop (e.g., a force-push or a destructive git operation), pause there — but not at the routine "round N finished, round N+1 needed" boundary. Those are silent transitions.

Run /pr-polish in the foreground — never in a background agent

Spawning /pr-polish inside an Agent(subagent_type="general-purpose") background task does not work. Background agents don't inherit the parent's slash-command registry, so Skill(skill="pr-review") and Skill(skill="pr-address") calls aren't available — the agent has to manually replicate the child skills' logic, which is fragile and tends to stall on the first network or rate-limit hiccup. Symptom: the background task reports stalled: no progress for 600s mid-review.

Run /pr-polish inline in the foreground conversation. If the user asks for "/pr-polish + /pr-test in parallel", split them: foreground /pr-polish, and ONLY then can the test step go to a background agent (because /pr-test doesn't itself need to invoke skills).

You MUST invoke Skill(pr-review) every round — even when bot reviews already exist

A common failure mode: CodeRabbit / autogpt-pr-reviewer / Sentry have already posted findings on the PR, and the orchestrator skips the Skill(pr-review) step on the assumption that "review has been done." That's wrong — the outer loop's purpose is to layer the agent's own review on top of the bot reviews, catching issues the bots miss (architecture, naming, cross-file invariants, hidden coupling). If the orchestrator only addresses bot findings without ever running its own review, the loop converges to "bot-clean" but not "agent-reviewed-clean," and the user reasonably asks "did /pr-polish even read the diff?"

Self-check before reporting ORCHESTRATOR:DONE: confirm at least one Skill(skill="pr-review") call appears in the current orchestration. If none, the loop is incomplete — go back and run one round.

GitHub rate limits

This skill issues many GraphQL calls (one review-thread query per outer iteration plus per-poll queries inside polish polling). Expect the GraphQL budget to be tight on large PRs. When gh api rate_limit --jq .resources.graphql.remaining drops below ~200, back off:

  • Fall back to REST for reads (flat /pulls/{N}/comments, /pulls/{N}/reviews, /issues/{N}/comments) per the pr-address skill's GraphQL-fallback section.
  • Queue thread resolutions (GraphQL-only) until the budget resets; keep making progress on fixes + REST replies meanwhile.
  • sleep 5 between any batch of ≥20 writes to avoid secondary rate limits.

Safety valves

  • _MAX_ROUNDS = 10 — if review+address rounds exceed this, stop and escalate to the user with a summary of what's still unresolved. A PR that cannot converge in 10 rounds has systemic issues that need human judgment.
  • After each commit, run poetry run format / pnpm format && pnpm lint && pnpm types per the target codebase's conventions. A failing format check is CI failure that will never self-resolve.
  • Every /pr-review round checks for duplicate concerns first (via pr-review's own "Fetch existing review comments" step) so the loop does not re-post the same finding that a prior round already resolved.

Reporting

When the skill finishes (either via two clean polls or hitting _MAX_ROUNDS), produce a compact summary:

PR #{N} polish complete ({rounds_completed} rounds):
- {X} inline threads opened and resolved
- {Y} CI failures fixed
- {Z} new commits pushed
Final state: CI green, {total} threads all resolved, mergeable.

If exiting via _MAX_ROUNDS, flag explicitly:

PR #{N} polish stopped at {_MAX_ROUNDS} rounds — NOT merge-ready:
- {N} threads still unresolved: {titles}
- CI status: {summary}
Needs human review.

When to use this skill

Use when the user says any of:

  • "polish this PR"
  • "keep reviewing and addressing until it's mergeable"
  • "loop /pr-review + /pr-address until done"
  • "make sure the PR is actually merge-ready"

Do not use when:

  • User wants just one review pass (→ /pr-review).
  • User wants to address already-posted comments without further self-review (→ /pr-address).
  • A fixed round count is explicitly requested (e.g., "do 3 rounds") — honour the count instead of converging.

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

open-pr

免费有简介

检查代码变更的测试情况及对现有功能的影响,按仓库模板创建PR,并继续处理评审请求、反馈意见和CI检查。

  • 按指定模板创建PR
  • 检查现有功能与新功能的测试
  • 本地验证受限时请求机器人评审
Significant-Gravitas/AutoGPT18.8万2026年10月24日 更新

orchestrate

免费有简介

在独立工作目录中运行多个Claude Code,统一分配开发任务、监控进度、协助恢复停止的会话,并检查PR测试及评审反馈的处理情况。

  • 向多个代理分配开发任务
  • 查看进度及空闲worktree
  • 恢复停止工作的代理
Significant-Gravitas/AutoGPT18.8万2026年10月24日 更新

perf-compare

免费有简介

利用Sentry测量数据比较变更前后或不同环境的速度与失败率,考虑统计波动,判定加速、减速、未检测到变化或数据不足,并输出比较结果。

  • 比较发布前后的性能
  • 验证预览环境与对照环境
  • 检查其他操作是否变慢
Significant-Gravitas/AutoGPT18.8万2026年10月24日 更新

pr-address

免费有简介

收集PR审查意见,推进代码修改、提交、回复及讨论串解决,同时持续检查CI失败、合并冲突和新增评论,跟进直至审查事项处理完成。

  • 修改PR审查指出的问题
  • 回复人工和机器人审查
  • 调查并修复推送后的CI失败
Significant-Gravitas/AutoGPT18.8万2026年10月24日 更新

pr-review

免费有简介

审查拉取请求的目的和代码差异,检查正确性、安全性、设计及测试,避免重复已有评论,并将标注严重程度的问题发布到对应代码行。

  • 合并前审查拉取请求
  • 检查代码变更的安全性
  • 查找边界情况的测试缺口
Significant-Gravitas/AutoGPT18.8万2026年10月24日 更新

pr-test

免费有简介

在运行中的系统上通过浏览器和API验证PR或分支变更,对照界面、接口及存储数据的变化,并附上操作前后截图报告结果。

  • 通过浏览器和API完整测试PR
  • 对照界面、API及存储数据的变化
  • 验证无效输入等异常情况
Significant-Gravitas/AutoGPT18.8万2026年10月24日 更新

查看 Significant-Gravitas 的全部技能

报告此技能的问题