skills/ah-resolve-pr-review/SKILL.md
Resolve unresolved PR conversations with the "ah" prefix. Use for "ah resolve pr review", or when resolving, addressing, or fixing PR review feedback or unresolved threads.
npx skillsauth add arinhubcom/arinhub ah-resolve-pr-reviewInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Resolve unresolved review threads on a PR. Read each comment, grasp reviewer intent, build fix plan. Present plan to user for approval before any code change. After approval: implement fixes, reply to each thread explaining what was done, mark threads resolved on GitHub. Use full PR context, linked issue, existing codebase for clean idiomatic fixes.
123, #123, full URL. If omitted, script auto-detects PR from current branch.REPO_NAME=$(basename -s .git "$(git remote get-url origin)")
PLANS_DIR=~/.agents/arinhub/plans
mkdir -p "${PLANS_DIR}"
First, save current branch and stash state for later restore:
ORIGINAL_BRANCH=$(git branch --show-current)
STASH_MSG="ah-resolve-pr-review: auto-stash before checkout"
If user provided specific PR number or URL, checkout that branch:
# Stash uncommitted changes before switching branches
git stash --include-untracked -m "${STASH_MSG}"
if ! gh pr checkout <PR_NUMBER>; then
STASH_INDEX=$(git stash list | grep -m1 "${STASH_MSG}" | sed 's/stash@{\([0-9]*\)}.*/\1/')
[ -n "$STASH_INDEX" ] && git stash pop "stash@{$STASH_INDEX}"
echo "ERROR: Failed to check out PR. Aborting."
exit 1
fi
If no PR specified, current branch is the PR branch. No checkout or stash needed.
Then run fetch script (resolve path relative to this SKILL.md's directory). Writes full data bundle to file, prints only compact summary:
python3 <skill_dir>/scripts/fetch_pr_data.py /tmp/pr_data.json
If script fails with auth error, stop and ask user to run gh auth login.
stdout is bounded summary only -- read it directly: PR number/title/state/url, branch pair, counts (files, threads with unresolved/resolved breakdown, reviews, comments, linked issues), index of unresolved threads (path:line [outdated] :: <truncated first comment>). Drives validation (step 2) and thread-fix planning without loading heavy bundle into context.
Full JSON file (/tmp/pr_data.json) holds complete unchanged data. Read selectively with jq only for threads you fix -- never cat whole file (contains full diff and every diffHunk). File shape:
pull_request -- metadata: number, title, body, url, state, base_branch, head_branch, files, owner, repodiff -- full PR diff string (read per-file on demand: jq -r .diff or prefer gh pr diff <PR> -- <path>)review_threads -- object with total, unresolved_count, resolved_count, unresolved (array of thread objects), resolved
id (GraphQL node ID for resolve mutation), isResolved, isOutdated, subjectType (LINE or FILE), path, line, startLine, diffSide, startDiffSide, originalLine, originalStartLine, resolvedByid (GraphQL node ID), databaseId (numeric -- use for REST API replies), body, diffHunk, createdAt, updatedAt, author, path, originalPositionreviews -- simplified review submissionsconversation_comments -- simplified issue commentslinked_issues -- full details of linked issuesExample -- pull just unresolved threads (no diff, no resolved) at step 4:
jq '.review_threads.unresolved' /tmp/pr_data.json
Set PR_NUMBER for later steps. If user provided PR number/URL, use that. Otherwise take from summary's PR #<n> header (or jq -r .pull_request.number /tmp/pr_data.json).
Check pull_request.state. If not OPEN, abort and inform user that only open PRs can be resolved.
If review_threads.unresolved_count is 0, inform user there are no unresolved conversations and stop.
Before fixes, build mental model of codebase so fixes reuse existing patterns rather than duplicate.
Discover project layout by checking which directories exist at project root -- do not assume structure like src/. Common layouts:
src/, app/, lib/, packages/, modules/package.json workspaces field or pnpm-workspace.yamlpages/, routes/, api/, server/, client/Focus scan on directories tied to files in unresolved threads. For each file touched by an unresolved conversation:
Read key config files relevant to changes (package.json, tsconfig.json, etc.). Informs whether existing utilities, hooks, components, CSS classes, or shared functions should be reused instead of writing new code.
Group unresolved threads by path (file) so each file is read once and all related threads processed together. Avoids redundant reads, keeps consistency across same-file fixes.
For each file group, read file once, then process each thread in group.
File-level threads (subjectType is FILE): comments apply to whole file, not a specific line. line and startLine are null. Skip line-location logic in step 4a; treat entire file as context. Reviewer's comment body is sole guide.
If isOutdated is true, thread references code that since changed. line/startLine may no longer match current file:
diffHunk and comment context to locate relevant code -- search for code patterns mentioned rather than original line numbers.Already addressed with reason.Read full thread (all comments and replies). Determine:
Fixable -- request clear, change within scope, enough info to implement correctly.
Not fixable -- common reasons:
Do NOT implement yet. Create detailed fix plan per fixable thread:
suggestion block, include verbatim in plan.Per thread, record:
id from GraphQL -- node ID for resolve mutation)Fixable, Not fixable, or Already addressedAssemble plan file path:
PLAN_FILE="${PLANS_DIR}/plan-resolve-pr-review-${REPO_NAME}-${PR_NUMBER}.md"
Write complete fix plan to ${PLAN_FILE} using this format:
## Fix Plan: PR #<number>
**Threads analyzed:** <total> | Fixable: <count> | Not fixable: <count> | Already addressed: <count>
### Planned Fixes
| # | File | Line(s) | Reviewer | Request Summary | Planned Change |
|---|------|---------|----------|-----------------|----------------|
| 1 | `src/auth.ts` | 42 | @reviewer | Add input validation | Use existing `validateInput()` from `utils/validation.ts` |
| 2 | `src/api.ts` | 15-20 | @reviewer | Rename variable | Rename `data` to `userData` per reviewer's suggestion |
### Not Fixable / Already Addressed
| # | File | Line(s) | Reviewer | Request Summary | Reason |
|---|------|---------|----------|-----------------|--------|
| 3 | `src/api.ts` | 30 | @reviewer | Unclear naming suggestion | Question without clear direction; needs clarification |
Display only a link to file in chat:
Plan saved to: ${PLAN_FILE}
Spawn a plan-validator subagent (Opus, low) with these instructions:
${PLAN_FILE}AGENTS.md files: for each file path in plan, walk up from that file's directory to repo root, collecting any AGENTS.md found. Deduplicate (root AGENTS.md appears for every path).AGENTS.md fileAGENTS.md filesAfter validator returns, review findings:
${PLAN_FILE} to correct them before proceeding.Use AskUserQuestion tool to ask user for approval:
${PLAN_FILE})Handle response:
${PLAN_FILE} per feedback, present again for approval.Apply only fixes approved by user in step 5. Per approved fix:
suggestion block, apply exactly unless it introduces a bug or violates project conventions.After each fix, update status from Fixable to Fixed or Partially fixed.
After processing all conversations, verify changes are sound.
Read package.json for available verification scripts. Determine package manager by lock files (pnpm-lock.yaml, package-lock.json, yarn.lock, bun.lockb).
Run only scripts that exist in package.json. Check these common script names in order of preference:
preflighttypecheck, type-check, tsclinttest, test:unitbuild, preflight:buildIf no verification scripts found, note in report and skip verification. Do not silently assume verification passed.
If verification fails, determine which fix caused failure. Fix regression if possible. If a fix cannot be corrected without new issues, revert it and update thread outcome to Not fixable with reason (e.g., "Fix caused type error; reverted").
For each thread Fixed or Already addressed, post reply and resolve on GitHub. Closes feedback loop for reviewer.
Post concise reply explaining what was done. Use first comment's databaseId (numeric ID) from thread -- do not use GraphQL node id:
gh api repos/<owner>/<repo>/pulls/<pr_number>/comments/<database_id>/replies \
-f body="<reply_message>"
Reply format by outcome:
validateInput() from utils/validation.ts."Do not reply to Not fixable or Partially fixed threads -- those need human follow-up.
After replying, resolve thread using its GraphQL node ID (the id field from review thread data):
gh api graphql -f query='
mutation($threadId: ID!) {
resolveReviewThread(input: {threadId: $threadId}) {
thread { isResolved }
}
}
' -f threadId="<thread_id>"
If resolve mutation fails (e.g., permissions), log failure but do not abort. Reply is still valuable even if auto-resolve not possible.
Present summary using PR metadata from JSON output:
## PR Review Resolution: #<number>
**PR:** <title> (<url>)
**Branch:** <head_branch>
**Linked Issue:** #<issue_number> (or "None found")
**Threads processed:** <total> | Fixed: <count> | Not fixable: <count> | Already addressed: <count> | Partially fixed: <count>
### Resolution Details
| # | File | Line(s) | Reviewer | Request Summary | Outcome | Notes |
|---|------|---------|----------|-----------------|---------|-------|
| 1 | `src/auth.ts` | 42 | @reviewer | Add input validation | Fixed | Used existing `validateInput()` from `utils/validation.ts` |
| 2 | `src/api.ts` | 15-20 | @reviewer | Unclear naming suggestion | Not fixable | Question without clear direction; needs clarification |
### Not Fixable Items
For each "Not fixable" conversation, explain clearly enough that the user can follow up with the reviewer:
1. **`src/api.ts:15-20`** (@reviewer): "Should we rename this?" -- This is a question, not a directive. The reviewer needs to specify the preferred name before a change can be made.
### Resolved on GitHub
List threads that were replied to and resolved via the API. If any resolve mutations failed, note which threads could not be auto-resolved.
After report, ask user:
Do not commit or push automatically -- wait for user's decision.
Only if a branch checkout was performed in Step 1 (i.e., user provided specific PR number/URL and original branch differed). If current branch was already PR branch, skip this step.
After user decides (or if process aborted):
git checkout "${ORIGINAL_BRANCH}"
# Pop the stash if one was created
STASH_INDEX=$(git stash list | grep -m1 "${STASH_MSG}" | sed 's/stash@{\([0-9]*\)}.*/\1/')
if [ -n "$STASH_INDEX" ]; then
if ! git stash pop "stash@{$STASH_INDEX}"; then
echo "WARNING: Stash pop failed due to conflicts. Your stashed changes are preserved in stash@{$STASH_INDEX}."
echo "Resolve conflicts manually, then run: git stash drop 'stash@{$STASH_INDEX}'"
fi
fi
If git stash pop fails due to merge conflicts, inform user and preserve stash for manual resolution.
Skip this step entirely if user chose to stay on PR branch.
development
Use when: (1) building a skill/command that orchestrates other skills by spawning subagents, (2) a delegated sub-skill reads git working-tree state (e.g. `git branch --show-current`) instead of taking it as an argument, (3) a sub-skill is supposed to "reflect on this session" / capture session learnings (like revise-claude-md) but runs in a subagent, (4) base branch ends up wrong or a session-reflection step sees an empty/trivial context. Keywords: orchestrator, subagent isolated context, git branch --show-current, base branch checkout, revise-claude-md, this session.
development
Run the full ArinHub feature-development pipeline end-to-end with the "ah" prefix. Use for "ah workflow", "ah run workflow", "ah full workflow", a GitHub issue URL to take from issue to PR, or any request to run the whole ah pipeline at once. Takes a feature description + issue number + base branch, OR a GitHub issue URL (resolved via references/resolve-gh-issue.md). Sequentially launches subagents: ah-create-prd-adr -> ah-create-tasks -> ah-implement-tasks -> optional ah-check-qa verification -> ah-finalize-code (creates the PR), anchored with /goal and guarded by retry + escalation.
testing
Verify that a PR or local changes fully implement requirements from a linked GitHub issue, with the "ah" prefix. Use for "ah verify requirements coverage", "ah verify requirements coverage issue 42", "ah verify requirements coverage PR 123", or both ("PR 123, issue 42").
development
Submit a completed code review with line-specific comments and suggestions to a GitHub PR, with the "ah" prefix. Use for "ah submit code review 123".