정보
이 스킬은 GitHub Copilot 풀 리퀘스트 리뷰를 자동화하며, 발견된 문제를 별도의 커밋으로 체계적으로 수정하고, 수정된 SHA로 응답하며, 스레드를 해결하고, 재검토를 요청합니다. GraphQL 변환을 처리하고, 스레드 ID를 구분하며, 봇의 판단을 정확히 해석합니다. 병합 전에 감사 가능한 기록을 남기며 봇 리뷰를 자동으로 완료 상태로 이끌 때 사용하세요.
빠른 설치
Claude Code
추천npx skills add pjt222/agent-almanac -a claude-code/plugin add https://github.com/pjt222/agent-almanacgit clone https://github.com/pjt222/agent-almanac.git ~/.claude/skills/run-copilot-review-loopClaude Code에서 이 명령을 복사하여 붙여넣어 스킬을 설치하세요
문서
Run the Copilot Review Loop
Drive a GitHub Copilot PR review to a clean pass through a deterministic loop: fix → reply → resolve → re-request → poll. Each finding gets its own commit, each thread gets a reply citing the fix sha, and the loop terminates on a verified fresh re-review — not on the stale one that was already there. The same loop works for any bot reviewer with a stable slug.
When to Use
- Copilot has left review comments on your PR and you want to drive them to a clean pass without babysitting the PR page
- Bot review threads must be closed out before merge with an auditable fix → reply → resolve trail
- You need to confirm a re-review landed on the new HEAD (the reviews list still contains the old review, so "a Copilot review exists" proves nothing)
- Adapting the same mechanics to another bot reviewer that exposes review threads and a reviewer slug
Inputs
- Required: A PR with an open bot review (PR number, or inferred from the current branch via
gh pr view --json number) - Required: Authenticated
ghCLI with access to the repository (the loop relies on the existing auth — no extra credentials) - Optional: Reviewer slug (default:
copilot-pull-request-reviewer[bot]) - Optional: Poll budget (default: ~20 iterations x 25 s ≈ 8 minutes)
Replace OWNER, REPO, and PR in the commands below with the repository owner, name, and PR number. See references/EXAMPLES.md for inferring all three from the current branch.
Procedure
Step 1: Locate the PR and Baseline the Bot's Latest Review
Capture the submitted_at of the bot's most recent review before you change anything. This baseline is what later distinguishes a fresh re-review from the stale review that triggered this loop.
# Infer the PR number from the current branch
gh pr view --json number --jq '.number'
# Baseline: latest Copilot review timestamp (may be null if none yet)
BASE=$(gh api repos/OWNER/REPO/pulls/PR/reviews \
--jq '[.[]|select(.user.login=="copilot-pull-request-reviewer[bot]")]|last|.submitted_at')
echo "baseline: $BASE"
Expected: PR number resolved; BASE holds an ISO-8601 timestamp (or null when the bot has not reviewed yet — then any future review counts as new).
On failure: gh pr view errors when the current branch has no PR — pass the number explicitly. If the reviews list contains no bot entries at all, Copilot review may not be enabled on the repository; request it once (Step 6) before running the loop.
Step 2: List Open Review Threads with Both IDs
Every review thread carries two distinct identifiers, and they are never interchangeable:
- the thread node-id (
PRRT_...) — consumed by the GraphQLresolveReviewThreadmutation (Step 5) - the comment databaseId (numeric) — consumed by the REST replies endpoint (Step 4)
gh api graphql -f query='query { repository(owner:"OWNER",name:"REPO"){
pullRequest(number:PR){ reviewThreads(first:40){ nodes {
id isResolved comments(first:1){ nodes { databaseId path line } } } } } } }' \
| jq -r '.data.repository.pullRequest.reviewThreads.nodes[]
| select(.isResolved==false)
| "\(.comments.nodes[0].databaseId) \(.id) \(.comments.nodes[0].path)"'
Expected: One line per unresolved thread: <databaseId> <PRRT_nodeId> <path>. Empty output means no open threads — skip to Step 8 to read the verdict.
On failure: GraphQL errors about owner/name/number mean the OWNER/REPO/PR placeholders were not replaced (note: number:PR takes a bare integer, not a quoted string). If the PR has more than 40 threads, raise first:40 or paginate.
Step 3: Fix Each Finding — One Commit per Finding
Read each finding and fix it in its own commit, so each thread reply in Step 4 can cite an exact sha. Record the thread → sha mapping as you go.
# Read the finding body (single-comment GET takes no PR number, unlike the Step 4 replies POST)
gh api repos/OWNER/REPO/pulls/comments/<databaseId> --jq '.body'
# ...make the change, then commit it alone...
git add <files>
git commit -m "fix: <what the finding asked for>"
git rev-parse --short HEAD # record this sha for the thread's reply
Make the claim honest everywhere. When a finding cites the PR description (or a README, a doc comment, a changelog line), fixing only the code leaves the overstated claim standing. Edit every place the claim appears — for the PR description:
gh pr edit PR --body-file <corrected-body.md>
Expected: git log shows one commit per finding, and you hold a mapping of <databaseId>/<PRRT_nodeId> → fix sha. Any claim a finding cited is corrected at every location, not just in code.
On failure: If you disagree with a finding, make no commit — reply in Step 4 with your reasoning instead, then resolve. If one change genuinely closes two threads, cite the same sha in both replies rather than splitting a coherent commit.
Step 4: Reply to Each Thread with the Fix Sha
Reply via REST using the thread's first comment's databaseId (the numeric id from Step 2 — not the PRRT_... node-id):
gh api --method POST "repos/OWNER/REPO/pulls/PR/comments/<databaseId>/replies" -f body="Fixed in <sha> — <what changed>."
Expected: HTTP 201; the reply appears under the thread on the PR page. The sha link resolves once the branch is pushed (Step 6).
On failure: A 404 here almost always means the wrong ID type — a PRRT_... node-id was used where the numeric comment databaseId belongs. Re-read the Step 2 output: first column replies, second column resolves.
Step 5: Resolve Each Thread
Resolve via GraphQL using the thread node-id (PRRT_...):
gh api graphql -f query='mutation { resolveReviewThread(input:{threadId:"<PRRT_nodeId>"}){ thread { isResolved } } }'
Expected: Response contains "isResolved": true for each thread.
On failure: Could not resolve to a node with the global id means a numeric databaseId was passed where the PRRT_... node-id belongs. If a thread is already resolved, note that the bot auto-resolves threads on push — if you pushed before this step, re-run the Step 2 query and only mutate threads still reported isResolved==false.
Step 6: Push the Fixes and Re-Request the Review
Push first, then re-request — the bot reviews whatever HEAD it sees at request time:
git push
gh api --method POST repos/OWNER/REPO/pulls/PR/requested_reviewers -f "reviewers[]=copilot-pull-request-reviewer[bot]"
Note the two forms of the same identity: the POST takes the literal slug copilot-pull-request-reviewer[bot], but the pending entry then appears in requested_reviewers under the user form Copilot, while submitted reviews carry user.login == "copilot-pull-request-reviewer[bot]".
Expected: Push accepted; the PR's requested_reviewers now lists Copilot. Pushing may auto-resolve remaining open threads — that is normal bot behavior, not an error.
On failure: A 422 means the slug is misspelled or Copilot code review is not enabled for the repository. If you re-requested before pushing, the bot reviewed the stale HEAD — push, then POST the re-request again.
Step 7: Poll for the Async Re-Review
The re-review is asynchronous (typically 30 s to a few minutes). Poll against the Step 1 baseline; exit when a newer bot review lands, or when the bot drops out of requested_reviewers (it finished without posting new comments):
for i in $(seq 1 20); do # 20 x 25s ≈ 8 min budget
sleep 25
LATEST=$(gh api repos/OWNER/REPO/pulls/PR/reviews \
--jq '[.[]|select(.user.login=="copilot-pull-request-reviewer[bot]")]|last|.submitted_at')
if [ "$LATEST" != "$BASE" ] && [ "$LATEST" != "null" ]; then
echo "re-review landed: $LATEST"; break
fi
REQUESTED=$(gh api repos/OWNER/REPO/pulls/PR \
--jq '[.requested_reviewers[].login] | any(. == "Copilot")')
if [ "$REQUESTED" = "false" ]; then
echo "Copilot left requested_reviewers — finished, no new comments"; break
fi
done
Expected: The loop exits within a few minutes on one of the two conditions. Without a pre-change baseline the check is meaningless — the old review already satisfies "a Copilot review exists".
On failure: On timeout, check the PR page — the request may have been dropped; re-request (Step 6) and poll again. Keep the sleep at ~20-30 s; hammering the API tighter gains nothing and burns rate limit. See references/EXAMPLES.md for a poll variant with exit codes and finding printout.
Step 8: Read the Verdict and Decide
gh api repos/OWNER/REPO/pulls/PR/reviews \
--jq '[.[]|select(.user.login=="copilot-pull-request-reviewer[bot]")]|last|{state,submitted_at,body}'
Interpret the result against how the bot actually reports:
COMMENTEDis the bot's terminal state. Copilot does not returnAPPROVEDorCHANGES_REQUESTED; aCOMMENTEDreview is not a rejection.- Boilerplate is not a finding. A review body announcing "0 new comments" and/or the standing "human review recommended" style banner is fixed bot messaging — it does not block the PR.
- Clean pass = the fresh review introduced zero new comments and the Step 2 thread query returns no unresolved threads.
- New threads = re-enter the loop at Step 2 with the new findings.
Expected: An unambiguous verdict: clean pass (stop) or a concrete list of new threads (iterate).
On failure: When the prose is ambiguous, do not parse it — count unresolved threads with the Step 2 query. The thread count is ground truth; the review body is commentary.
Validation
- Step 2 GraphQL query returns zero unresolved threads
-
git logshows one commit per addressed finding - Every thread carries a reply citing the fix commit sha (or won't-fix reasoning)
- PR description (and any other cited location) corrected where a finding referenced it
- Latest bot review
submitted_atis newer than the Step 1 baseline, or the bot is no longer inrequested_reviewers - Final verdict read via Step 8 and interpreted as a clean pass, not merely assumed from
COMMENTED
Common Pitfalls
- ID-type confusion: The single most common failure. The REST replies endpoint 404s when fed a
PRRT_...thread node-id; theresolveReviewThreadmutation errors when fed a numeric comment databaseId. Reply with the databaseId, resolve with the node-id. - Reading
COMMENTEDas a failing verdict: Copilot never approves;COMMENTEDplus a "human review recommended" banner is its normal clean output. Treating it as a blocking finding stalls the merge on boilerplate. - Polling without a baseline: The reviews list still contains the pre-fix review, so a poll that merely checks "does a Copilot review exist" succeeds instantly against stale data and reports a false clean pass. Baseline
submitted_atbefore re-requesting. - Re-requesting before pushing: The bot reviews the HEAD it sees at request time. Re-request first and it re-reviews the unfixed code — the same findings come straight back.
- Squashing all fixes into one commit: Replies can no longer cite a per-finding sha, and the audit trail from finding to fix dissolves. One commit per finding.
- Fixing the code but not the claim: A finding that cites the PR description is only half-fixed by a code change — edit the description too, or the dishonest claim survives and gets re-flagged.
- Fighting the auto-resolve: The bot auto-resolves threads on push. Threads vanishing after
git pushis expected; re-checkisResolvedbefore mutating instead of treating it as data loss.
Related Skills
create-pull-request- opens and manages the PR this loop drives to a clean passreview-pull-request- the human/agent-driven review counterpart to this bot loopverify-web-app-runtime- runtime-verify the fix actually works before replying "Fixed in<sha>"- Copilot Review Loop guide - narrative walkthrough, provenance, and when the loop pays off
GitHub 저장소
Frequently asked questions
What is the run-copilot-review-loop skill?
run-copilot-review-loop is a Claude Skill by pjt222. Skills package instructions and resources that Claude loads on demand, so Claude can perform run-copilot-review-loop-related tasks without extra prompting.
How do I install run-copilot-review-loop?
Use the install commands on this page: add run-copilot-review-loop to Claude Code as a plugin, or clone its repository into your skills directory, then restart Claude so it picks up the skill.
What category does run-copilot-review-loop belong to?
run-copilot-review-loop is in the Other category, tagged ai, api and data.
Is run-copilot-review-loop free to use?
Yes. run-copilot-review-loop is listed on AIMCP and free to install. It runs inside Claude, so no separate service account is required to use the skill itself.
연관 스킬
LlamaGuard는 폭력 및 혐오 발언 등 6가지 안전 범주에서 LLM 입력과 출력을 조정하기 위한 Meta의 70-80억 파라미터 모델입니다. 94-95% 정확도를 제공하며 vLLM, Hugging Face 또는 Amazon SageMaker를 사용해 배포할 수 있습니다. 이 기술을 사용하여 AI 애플리케이션에 콘텐츠 필터링 및 안전 가드레일을 손쉽게 통합하세요.
이 Claude Skill은 리소스 적정화, 태깅 전략, 지출 분석을 통해 개발자들이 클라우드 비용을 최적화할 수 있도록 지원합니다. AWS, Azure, GCP에서 클라우드 비용을 절감하고 비용 거버넌스를 구현하기 위한 프레임워크를 제공합니다. 인프라 비용을 분석하거나, 리소스를 적정화하거나, 예산 제약을 충족해야 할 때 사용하세요.
이 Claude Skill은 스프레드, 오버/언더, 프로프 베트를 포함한 스포츠 베팅 시장을 분석합니다. 역사적 추이와 상황별 통계를 검토하여 가치 베트를 발견하고, 교육적 목적으로 실행 가능한 권장 사항이 담긴 구조화된 마크다운 결과를 제공합니다. 개발자는 이 기능을 스포츠 베팅 분석 도구에 활용할 수 있으며, 단순히 엔터테인먼트/교육 목적으로만 설계되었음을 유의해야 합니다.
이 스킬은 bitsandbytes를 사용하여 LLM을 8비트 또는 4비트 정밀도로 양자화하며, 최소한의 정확도 손실로 50-75%의 메모리 감소를 달성합니다. 제한된 GPU 메모리에서 더 큰 모델을 실행하거나 추론을 가속화하는 데 이상적이며, INT8, NF4, FP4와 같은 형식을 지원합니다. 이 스킬은 HuggingFace Transformers와 통합되어 QLoRA 학습 및 8비트 옵티마이저를 가능하게 합니다.
