gh-pr-clean-loop
GH PR Clean Loop
Goal
Drive an open GitHub pull request to a clean state by repeatedly:
- inspecting CI and review-thread health
- fixing concrete issues
- committing and pushing updates
- resolving only the threads that were actually addressed
- waiting 10 minutes
- polling again
Stop only when the PR has no failing or pending checks and no unresolved review threads, or when you hit a blocker that needs user input.
When to use
Use this skill when the user asks to:
- babysit a PR until it is green
- fix failing GitHub PR checks and review comments
- clear unresolved review threads on a PR
- keep re-polling CI and PR comments until the PR is clean
Preconditions
ghis installed and authenticated for the target repository- the current branch already has an open PR, or the user provides a PR number or URL
- the agent has push access to the branch
- the repo can run the relevant local test/build commands
If authentication fails, stop and ask the user to run gh auth login.
Inputs
cwd: repository root; default.if obviouspr: optional PR number or URL; default to the PR for the current branchpoll interval: default600seconds
Quick start
Run the helper from the repo root:
uv run skills/gh-pr-clean-loop/scripts/pr_health.py --cwd .
Useful variants:
uv run skills/gh-pr-clean-loop/scripts/pr_health.py --cwd . --json
uv run skills/gh-pr-clean-loop/scripts/pr_health.py --cwd . --pr 123
uv run skills/gh-pr-clean-loop/scripts/pr_health.py --cwd . --resolve-thread <thread-id>
Core loop
- Verify repo and PR context
- Run
gh auth status. - Resolve the active PR with
gh pr viewif the user did not provide one. - If no open PR exists for the branch, stop and report that blocker.
- Inspect current PR health
- Run the helper script to collect:
- failing checks
- pending checks
- unresolved review threads
- current review decision
- If the helper is unavailable, fall back to:
gh pr checks <pr> --json bucket,name,state,link,workflowgh api graphqlforreviewThreads
- Triage what to address first
- Prioritize unresolved review threads that point to clear code changes.
- Then address failing CI jobs.
- Treat new top-level PR comments or ambiguous reviewer feedback as blocking if they require product or design decisions.
- Implement the next batch of fixes
- Inspect the referenced files, failing job logs, and local code paths.
- Make the smallest credible change that addresses the problem.
- Run all applicable local validation before committing:
- targeted tests for the changed area
- broader test suites when the failure or touched area warrants it
- lint
- build
- If lint or build is not relevant for the repo, state that explicitly before committing.
- If the issue is ambiguous or the requested change conflicts with requirements, stop and ask the user.
- Commit and push
- Create a focused commit for the batch you actually addressed.
- Do not commit until the applicable tests, lint, and build steps for that batch have passed.
- Push the branch before resolving review threads.
- Do not lump unrelated fixes into one commit just because they appeared in the same poll.
- Resolve addressed review threads
- Resolve only threads that are actually addressed by the pushed change.
- Use the helper script with
--resolve-thread, or the direct mutation:
gh api graphql \
-f query='mutation($threadId:ID!) { resolveReviewThread(input:{threadId:$threadId}) { thread { id isResolved } } }' \
-F threadId='<thread-id>'
- If a thread needs explanation rather than code, add the explanation first and only then resolve it when appropriate.
- Wait and poll again
- Sleep for 10 minutes:
sleep 600
- Re-run the helper script.
- If checks are still pending and there are no new actionable comments, continue waiting and polling.
- If new failures or review threads appear, repeat the loop.
Clean PR exit criteria
Treat the PR as clean only when all of these are true:
- no failing checks
- no pending checks
- no unresolved review threads
reviewDecision can remain stale after fixes, so do not use it as the sole blocker if the actual threads and checks are clean.
Helper script
Use scripts/pr_health.py to summarize PR status and resolve review-thread IDs.
What it reports:
- PR number and URL
- review decision
- failing and pending checks
- unresolved review threads with path, line, URL, author, and a short body excerpt
- whether the PR is currently clean
Exit codes:
0: clean PR1: PR still has failing or pending checks or unresolved review threads2: command or auth failure
Guardrails
- Do not resolve a review thread before the fix is pushed or the reply is posted.
- Do not mark a PR clean while checks are still pending.
- Do not guess at CI failures; read the failing job or log details first.
- Do not skip applicable tests, lint, or build before committing and pushing.
- Do not rewrite or force-push shared branches unless the user explicitly asks.
- Stop and ask the user when a comment implies a product decision, architectural disagreement, or conflicting reviewer guidance.
More from dolesshq/self-obsolescence
lint-build-loop
Run `npm run lint && npm run build` in a loop, fixing errors until both succeed. Use when the user asks to iterate on lint/build failures.
14review-plan-implementation
Review an implemented .plan.md by executing the instructions in its ## Reviewer Handoff section.
14execute-plan
Execute an existing plan file. Use when a user asks to carry out a .plan.md task list.
13supabase-reset-test-gen-loop
Iteratively run a local Supabase reset, database tests, and type generation until they succeed, fixing issues between runs. Use when asked to reset the local Supabase DB, run `supabase test db`, and regenerate types (`npm run gen-types`) in a loop.
13fetch-rules
Fetch and apply Cursor-style workspace rules supporting all rule formats (.cursor/rules/*.md, *.mdc, AGENTS.md, and legacy .cursorrules).
12create-plan
Create a concise plan. Use when a user explicitly asks for a plan related to a coding task.
12