"Address pull request review feedback from humans or bots. Use when existing comments, requested changes, unresolved review threads, or CodeRabbit/codex review findings need code fixes, verification, push updates, and thread resolution. SKIP fresh code-review requests with no existing feedback; use review-deep."
Resources
9Install
npx skillscat add gopherguides/gopher-ai/address-review Install via the SkillsCat registry.
This skill automates responding to pull request review comments by fetching existing feedback from humans or bots, applying code fixes, verifying changes, pushing updates, and resolving review threads. It should be used when a PR has outstanding review comments or requested changes that need to be addressed, but skipped for fresh code-review requests without prior feedback.
Address PR Review Comments
Plugin Resource Resolution
<PLUGIN_ROOT> is notation. Replace it with a concrete absolute plugin root before every resource read or command:
- Codex: Start from the directory containing the absolute selected
SKILL.mdpath, then ascend two directories (skills/<name>-> plugin root). - Claude Code: Bind it to the injected
${CLAUDE_PLUGIN_ROOT}value.
Before requesting decisions or delegating work, read<PLUGIN_ROOT>/lib/driver-interaction.md and follow its
cross-platform capability-binding rules.
Read <PLUGIN_ROOT>/lib/decision-gates.md before resolving any workflow
choice.
Bind the invocation arguments as SKILL_ARGS for $go-workflow:address-review by
reading <PLUGIN_ROOT>/lib/skill-arguments.md with this Claude Code compatibility payload:
$ARGUMENTS
source "<PLUGIN_ROOT>/lib/github-rest.sh"Output Durability
Replies to review comments and any new commit messages describe what behavior changed and why, not file paths or line numbers. A reviewer reading the reply six months later, after the file in question has moved, must still understand what was fixed.
If SKILL_ARGS is empty or not provided:
Auto-detect PR from current branch:
CURRENT_CHECKOUT_ROOT=$(git rev-parse --show-toplevel)
WORKTREE_PATH="$CURRENT_CHECKOUT_ROOT"
CURRENT_PR_JSON=$(cd "$WORKTREE_PATH" && github_current_pr 2>/dev/null) || true
jq -r '.number' <<< "$CURRENT_PR_JSON" 2>/dev/nullIf no PR is found, display usage:
Claude Code: /go-workflow:address-review [PR-number] [--no-watch]
Codex: $go-workflow:address-review [PR-number] [--no-watch]
Example: /address-review 123 or just /address-review on a PR branch. Add --no-watch to exit after one fix cycle instead of watching for bot re-reviews.
This is a missing-intent gate. Request: "No PR was found for the current
branch. What PR number should I address?" If structured input is unavailable,
ask in the final response and stop before loop initialization or a completion
claim.
If PR number is available (from SKILL_ARGS or auto-detected):
Parse Arguments
WATCH_MODE=true
PR_ARG=""
for arg in $SKILL_ARGS; do
case "$arg" in
--no-watch) WATCH_MODE=false ;;
*) PR_ARG="$arg" ;;
esac
done
echo "WATCH_MODE=$WATCH_MODE PR_ARG=$PR_ARG"Security Validation
!if [ -n "$PR_ARG" ] && ! echo "$PR_ARG" | grep -qE '^[0-9]+$'; then echo "Error: PR number must be numeric"; exit 1; fi
Resolve PR Number
CURRENT_CHECKOUT_ROOT=$(git rev-parse --show-toplevel)
ORIGINAL_REPO_ROOT=$(git -C "$CURRENT_CHECKOUT_ROOT" worktree list --porcelain | awk '/^worktree / {sub(/^worktree /, ""); print; exit}')
WORKTREE_PATH="${WORKTREE_PATH:-$CURRENT_CHECKOUT_ROOT}"
if [ -z "$ORIGINAL_REPO_ROOT" ] || [ "${ORIGINAL_REPO_ROOT#/}" = "$ORIGINAL_REPO_ROOT" ] ||
[ -z "$WORKTREE_PATH" ] || [ "${WORKTREE_PATH#/}" = "$WORKTREE_PATH" ] || [ ! -d "$WORKTREE_PATH" ]; then
echo "ERROR: Could not resolve absolute repository paths."
exit 1
fi
CURRENT_REPO_SLUG=$(cd "$WORKTREE_PATH" && gh api "repos/{owner}/{repo}" --jq '.full_name')
REPO_SLUG="${REPO_SLUG:-$CURRENT_REPO_SLUG}"
if [ -n "$PR_ARG" ]; then
RESOLVED_PR="$PR_ARG"
elif CURRENT_PR_JSON=$(cd "$WORKTREE_PATH" && github_current_pr 2>/dev/null); then
RESOLVED_PR=$(jq -er '.number' <<< "$CURRENT_PR_JSON")
else
RESOLVED_PR="auto"
fi
PR_NUM="$RESOLVED_PR"
echo "Resolved PR: $RESOLVED_PR"Embedded Workflow Contract
Address-review is embedded only when both caller variables are explicitly set.
Never infer composition from a generic inherited STATE_FILE:
EMBEDDED_WORKFLOW=false
source "<PLUGIN_ROOT>/lib/loop-state.sh"
RESOLVED_ORIGINAL_REPO_ROOT=$(git -C "$CURRENT_CHECKOUT_ROOT" worktree list --porcelain | awk '/^worktree / { sub(/^worktree /, ""); print; exit }')
if [ -z "$RESOLVED_ORIGINAL_REPO_ROOT" ] || [ "${RESOLVED_ORIGINAL_REPO_ROOT#/}" = "$RESOLVED_ORIGINAL_REPO_ROOT" ] || [ ! -d "$RESOLVED_ORIGINAL_REPO_ROOT" ]; then
echo "Error: Could not resolve the absolute primary worktree root."
exit 1
fi
if [ -n "${CALLER_LOOP_STATE_FILE:-}" ] && [ -n "${CALLER_WORKFLOW_STATE_PATH:-}" ]; then
EMBEDDED_WORKFLOW=true
STATE_FILE="$CALLER_LOOP_STATE_FILE"
WORKFLOW_STATE_PATH=$(child_workflow_path "$CALLER_WORKFLOW_STATE_PATH" "address_review")
initialize_workflow_state "$STATE_FILE" "$WORKFLOW_STATE_PATH"
ORIGINAL_REPO_ROOT=$(get_loop_field "$STATE_FILE" "original_repo_root" '[]')
WORKTREE_PATH=$(get_loop_field "$STATE_FILE" "worktree_path" '[]')
REPO_SLUG=$(get_loop_field "$STATE_FILE" "repo_slug" '[]')
elif [ -n "${CALLER_LOOP_STATE_FILE:-}" ] || [ -n "${CALLER_WORKFLOW_STATE_PATH:-}" ]; then
echo "Error: Embedded address-review requires both caller state variables."
exit 1
else
ORIGINAL_REPO_ROOT="$RESOLVED_ORIGINAL_REPO_ROOT"
WORKTREE_PATH="$CURRENT_CHECKOUT_ROOT"
REPO_SLUG=$(cd "$WORKTREE_PATH" && gh api "repos/{owner}/{repo}" --jq '.full_name')
STATE_FILE="$ORIGINAL_REPO_ROOT/.local/state/address-review-${RESOLVED_PR:-auto}.loop.local.json"
mkdir -p "$(dirname "$STATE_FILE")"
STATE_FILE=$(cd "$(dirname "$STATE_FILE")" && pwd)/$(basename "$STATE_FILE")
WORKFLOW_STATE_PATH='[]'
fi
LOOP_STATE_FILE="$STATE_FILE"When embedded, every phase and field operation uses STATE_FILE plusWORKFLOW_STATE_PATH. Address-review never changes the root completion promise
or terminal allowlist, never initializes another loop, and returns only throughset_workflow_result "$STATE_FILE" "$WORKFLOW_STATE_PATH" RESULT REASON PHASE.
Loop Initialization & Re-entry
Read loop-management.md for loop setup and phase re-entry logic. Key behavior:
- If resuming
watchingphase in watch mode → skip to Step 12 (watch loop) - If resuming
watchingphase in no-watch mode → clear phase, run full fix cycle - Otherwise → continue normally
Hard Invariant Failure
When this skill or a supporting file reportsWORKFLOW_RESULT=INCOMPLETE, persist the supplied reason:
INVARIANT_STATE_FILE="${STATE_FILE:-${LOOP_STATE_FILE:-}}"
if [ -z "$INVARIANT_STATE_FILE" ] || [ ! -f "$INVARIANT_STATE_FILE" ]; then
echo "Error: Cannot persist address-review invariant failure without loop state."
exit 1
fi
source "<PLUGIN_ROOT>/lib/loop-state.sh"
if [ "$EMBEDDED_WORKFLOW" = "true" ]; then
set_workflow_result "$STATE_FILE" "$WORKFLOW_STATE_PATH" "incomplete" "$WORKFLOW_REASON" "incomplete"
echo "ADDRESS_REVIEW_RESULT=incomplete"
echo "ADDRESS_REVIEW_REASON=$WORKFLOW_REASON"
else
set_loop_terminal_result "$STATE_FILE" "incomplete" "$WORKFLOW_REASON" "incomplete" "INCOMPLETE"
echo "<done>INCOMPLETE</done>"
fiStop after this block. Never fetch feedback, edit files, push, or claim
completion from an invariant-failure path. The embedded branch returns the
structured incomplete state and emits no terminal marker.
Context & Bot Discovery
Read setup-and-discovery.md for REST PR context gathering, mode banner display, and bot discovery from REST formal reviews plus GraphQL review threads. Match discovered authors against bot-registry.md.
Store the matched bot logins in DETECTED_BOTS; leave it empty when the
registry match finds none.
Step 1: Checkout PR Branch and Rebase
Read checkout-rebase.md for the full procedure: fetch and checkout the REST-declared PR head without overwriting local work, preserve fork/base metadata, check if behind, rebase + force-push if needed, and wait for CI after rebase.
Step 2: Fetch All Review Feedback
Read fetch-feedback.md for GraphQL review threads (line-specific, auto-resolvable) and REST formal reviews (CHANGES_REQUESTED).
Steps 3-9: Fix Cycle
Read fix-cycle.md for the complete fix cycle:
- Step 3: Categorize comments into Group A (resolvable threads) and Group B (pending reviews)
- Clean-review path: Set
REVIEW_CLEAN=true, persistreview_clean=trueto the active state, skip inapplicable mutation work, and continue through local verification, CI, and Step 11 - Step 4: Address each comment — parallel dispatch for 3+ comments on different files, sequential otherwise. Understand request, locate code, make minimal fix, validate against feedback
- Step 4.5: Generate tests for testable fixes (read
test-generation.md) - Step 5: Verify locally —
go -C "$WORKTREE_PATH" build,go -C "$WORKTREE_PATH" test, and a worktree-scopedgolangci-lint - Step 6: Commit and push, capture
BOT_REVIEW_BASELINEtimestamp - Step 7: Watch CI — retry up to 3x if no checks reported
- Step 8: Reply to each comment
- Step 9: Resolve review threads via GraphQL (Group A only)
Step 10: Request Re-review
Read bot-registry.md for the full re-review procedure (Steps 10a-10e) including bot detection, opt-out checks, and data-driven re-review triggering.
Step 11: Verify Completion
Confirm all resolvable threads are resolved and CI is passing:
PR_JSON=$(cd "$WORKTREE_PATH" && github_pr "$PR_NUM") || {
WORKFLOW_RESULT=INCOMPLETE
WORKFLOW_REASON=pr-metadata-api-failure
}
if [ -z "${WORKFLOW_REASON:-}" ]; then
PR_HEAD_SHA=$(jq -er '.head.sha' <<< "$PR_JSON") || {
WORKFLOW_RESULT=INCOMPLETE
WORKFLOW_REASON=invalid-pr-metadata
}
fi
if [ -z "${WORKFLOW_REASON:-}" ]; then
REVIEW_HEAD_EXPECTATION="${EXPECTED_REVIEW_HEAD:-$(git -C "$WORKTREE_PATH" rev-parse HEAD)}"
fi
if [ -z "${WORKFLOW_REASON:-}" ] &&
[ "$PR_HEAD_SHA" != "$REVIEW_HEAD_EXPECTATION" ]; then
WORKFLOW_RESULT=INCOMPLETE
WORKFLOW_REASON=pr-head-shift
fi
if [ -z "${WORKFLOW_REASON:-}" ]; then
OWNER=$(jq -er '.base.repo.owner.login' <<< "$PR_JSON")
REPO=$(jq -er '.base.repo.name' <<< "$PR_JSON")
(cd "$WORKTREE_PATH" && gh api graphql -f query='
query($owner: String!, $repo: String!, $pr: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $pr) {
reviewThreads(first: 100) {
nodes { isResolved }
}
}
}
}
' -f owner="$OWNER" -f repo="$REPO" -F pr="$PR_NUM") | jq '.data.repository.pullRequest.reviewThreads.nodes | map(select(.isResolved == false)) | length'
fiPin completion checks to the exact published PR head:
if [ -z "${WORKFLOW_REASON:-}" ]; then
CHECK_STATUS=0
CHECKS_JSON=$(cd "$WORKTREE_PATH" && github_watch_pr_checks "$PR_NUM" "$PR_HEAD_SHA") || CHECK_STATUS=$?
case "$CHECK_STATUS" in
0) printf '%s\n' "$CHECKS_JSON" | jq '.' ;;
1) echo "CI failed. Return to the fix cycle and do not claim completion." ;;
2) WORKFLOW_RESULT=INCOMPLETE; WORKFLOW_REASON=checks-registration-timeout ;;
3) WORKFLOW_RESULT=INCOMPLETE; WORKFLOW_REASON=checks-api-failure ;;
4) WORKFLOW_RESULT=INCOMPLETE; WORKFLOW_REASON=pr-head-shift ;;
*) WORKFLOW_RESULT=INCOMPLETE; WORKFLOW_REASON=checks-unknown-failure ;;
esac
fiFor metadata failures, an EXPECTED_REVIEW_HEAD mismatch, statuses 2-4, or an
unknown status, follow Hard Invariant Failure. A registration timeout, API
failure, or PR head shift is never a successful CI result.
Step 12: Watch for Bot Re-review
Skip if WATCH_MODE is false or no review bots were detected.
Read watch-loop.md for Phase Transition logic, bot polling, quiet period detection, timeout handling, and re-trigger procedures.
Embedded Consumer Contract
When ship, e2e-verify, or another workflow executes Steps 2-11, return control
to the caller after Step 11 and emit no terminal marker. The caller remains the
top-level owner of its later verification, posting, merge, and completion
gates.
On the no-feedback path, return REVIEW_CLEAN=true and persistreview_clean=true to the caller's STATE_FILE when available. Embedded
consumers skip the inapplicable edit, commit, reply, resolution, and re-review
steps, but still execute Step 5 local verification, Step 7 CI, and Step 11
completion verification before regaining control.
Completion Criteria
The standalone address-review owns its final marker only after Step 11 and all
applicable completion criteria pass. Embedded consumers follow the contract
above instead.
With --no-watch:
Output <done>COMPLETE</done> when: branch rebased; local verification passes;
CI is green; Step 11 confirms no unresolved threads; and, when feedback was
found, all feedback is addressed, fixes are validated and pushed, replies are
posted, threads are resolved, and re-review is requested. A clean review skips
only those feedback-specific actions.
Default (watch mode):
All above, PLUS all detected review bots signaled approval per bot-registry.md.
When all criteria are met:
if [ "$EMBEDDED_WORKFLOW" = "true" ]; then
set_workflow_result "$STATE_FILE" "$WORKFLOW_STATE_PATH" "complete" "" "completed"
echo "ADDRESS_REVIEW_RESULT=complete"
else
set_loop_terminal_result "$STATE_FILE" "complete" "" "completed" "COMPLETE"
echo "<done>COMPLETE</done>"
fiIf the user exits or skips a bot before all detected bots approve, follow the
Incomplete Approval Outcome procedure in watch-loop.md. Persistapproval_result and approval_reason; standalone address-review emits its
allowlisted INCOMPLETE marker while embedded address-review returns its
structured failure without a marker.
Safety: If 15+ iterations complete without success, document the blocking
evidence and stop incomplete. Do not bypass review or approval criteria.
Supporting Files
bot-registry.md— Bot registry table, detection logic, and Step 10 re-review procedurestest-generation.md— Step 4.5 test generation guidelines and testability ruleswatch-loop.md— Phase Transition logic and Step 12 watch loop proceduresloop-management.md— Loop initialization and re-entry check logicsetup-and-discovery.md— PR context gathering, mode banner, and bot discoverycheckout-rebase.md— Step 1 checkout and rebase procedurefetch-feedback.md— Step 2 GraphQL queries for review feedbackfix-cycle.md— Steps 3-9 categorize, fix, verify, commit, CI, reply, resolve