kramme-cc-workflow/skills/kramme:pr:github-review-reply/SKILL.md
Maps GitHub PR review feedback from humans, bots, and apps, including inline review threads, review-summary comments, and general PR comments; facilitates needed code changes; drafts and humanizes action-based responses; and optionally posts replies or resolves addressed inline threads with gh. Use when reviewers left GitHub comments that need triage, implementation, or response. Not for fixing CI, generating internal review findings, or resolving local REVIEW_OVERVIEW.md findings.
npx skillsauth add abildtoft/kramme-cc-workflow kramme:pr:github-review-replyInstall 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.
Map GitHub pull request review feedback from humans, bots, and apps; facilitate needed code changes; draft clear action-based replies; and optionally post replies or resolve addressed inline threads.
Use this skill for online GitHub review feedback where the user wants review comments addressed and answered. Feedback includes inline review threads, pull-request review-summary comments, and general PR comments. The preferred flow is implementation-first: if a thread or comment needs a code change, make or delegate that change before drafting the reply so the reply describes completed work, not planned work.
If implementation is disabled or blocked, classify the item honestly and do not post a reply that implies the change has already happened.
Parse $ARGUMENTS before fetching data.
Flags:
--auto - implement needed code changes, post ready replies/comments after required confirmation, and resolve inline threads marked safe after posting. Equivalent to --implement --post --resolve, but it never waives mandatory confirmation for human-origin feedback.--post - after drafting, post approved replies to GitHub. For human-origin feedback, confirmation is still mandatory before posting.--resolve - after posting, resolve inline threads that are fully addressed. If used without --post, ask for explicit confirmation before resolving existing addressed inline threads.--implement - implement code-change items before drafting replies.--no-implement - skip implementation and produce a reply plan only.--inline - reply in chat only; do not write GITHUB_REVIEW_REPLY_PLAN.md.--include-bots - include bot and app review comments. This is the default and the flag is retained for compatibility.--human-only - exclude bot/app-only feedback. Keep mixed-origin items only for their human non-author feedback.--all - include resolved inline threads, comments already answered by the branch author, and older summary/general comments. Default: unresolved and awaiting-author feedback only.--only <login> - include only feedback whose latest applicable non-author comment is from this login. With --human-only, "applicable" means the latest human non-author feedback; bot/app comments are context only.The remaining payload may be a PR URL, PR number, or additional instructions such as "only reply to Sarah" or "do not resolve design comments."
Defaults: AUTO=false, IMPLEMENT=plan-only, POST=false, RESOLVE=false, INLINE=false, INCLUDE_BOTS=true, HUMAN_ONLY=false, INCLUDE_ALL=false.
If --human-only is present, set HUMAN_ONLY=true and INCLUDE_BOTS=false. If both --human-only and --include-bots are present, stop and ask the user to choose one filter mode; bot and app comments are included by default.
If --auto is present, set AUTO=true, IMPLEMENT=implement, POST=true, and RESOLVE=true. If both --auto and --no-implement are present, stop and ask the user to choose one mode; --auto owns implementation because it posts completion replies and resolves addressed threads.
IMPLEMENT=plan-only is the default: map feedback and draft replies, but do not edit code. Implement needed code changes only when --implement is set or the request explicitly asks to address, handle, or fix the feedback (e.g. "address these comments", "fix Sarah's findings"). A bare invocation — just a PR URL, or no payload — never edits code. --implement forces implementation; --no-implement is the explicit form of the plan-only default.
Confirm required tooling before any GitHub call. gh must be installed and authenticated, and jq must be available because every step below parses gh output with it:
if ! command -v gh > /dev/null; then
echo "gh CLI not installed. Install from https://cli.github.com and run \`gh auth login\`." >&2
exit 1
fi
if ! command -v jq > /dev/null; then
echo "jq not installed. Install it first (e.g. \`brew install jq\` or \`apt-get install jq\`)." >&2
exit 1
fi
If the payload contains a GitHub PR URL or number, set PR_SELECTOR to that value. Otherwise leave PR_SELECTOR empty so gh pr view uses the current branch.
Capture the PR context:
PR_CONTEXT_JSON=$(gh pr view ${PR_SELECTOR:+"$PR_SELECTOR"} --json number,url,title,baseRefName,headRefName,reviewDecision,author)
PR_NUMBER=$(printf '%s\n' "$PR_CONTEXT_JSON" | jq -r '.number // empty')
PR_URL=$(printf '%s\n' "$PR_CONTEXT_JSON" | jq -r '.url // empty')
BASE_BRANCH=$(printf '%s\n' "$PR_CONTEXT_JSON" | jq -r '.baseRefName // empty')
PR_AUTHOR=$(printf '%s\n' "$PR_CONTEXT_JSON" | jq -r '.author.login // empty')
If no PR is found, or PR_NUMBER, BASE_BRANCH, PR_URL, or PR_AUTHOR is empty, ask the user for a PR URL and stop.
Capture repository and actor context. Derive OWNER and REPO from PR_URL so a URL for another repository does not accidentally target the current checkout's repository:
REPO_NWO=$(printf '%s\n' "$PR_URL" | sed -E 's#^https://github.com/([^/]+/[^/]+)/pull/[0-9]+.*#\1#')
if [ -z "$REPO_NWO" ] || [ "$REPO_NWO" = "$PR_URL" ]; then
echo "Could not parse repository from PR URL: $PR_URL" >&2
exit 1
fi
OWNER="${REPO_NWO%%/*}"
REPO="${REPO_NWO#*/}"
SELF=$(gh api user --jq .login)
Fetch the PR base branch if available so local code inspection has the same context as the reviewer:
git fetch origin "refs/heads/${BASE_BRANCH}:refs/remotes/origin/${BASE_BRANCH}"
Fetch inline review comments, GraphQL review thread metadata, review-summary comments, and general PR comments.
REST comments - use this for stable comment IDs, node IDs, paths, line numbers, diff hunks, URLs, and in_reply_to_id:
gh api --paginate "repos/$OWNER/$REPO/pulls/$PR_NUMBER/comments"
Review summaries - use this for summary-level review bodies, reviewer verdicts, review IDs, and HTML URLs that are not anchored to a line:
gh api --paginate "repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews"
General PR comments - use this for top-level PR discussion, comment IDs, and HTML URLs that may contain review feedback outside the review API:
gh api --paginate "repos/$OWNER/$REPO/issues/$PR_NUMBER/comments"
GraphQL threads - use this for thread IDs and resolution state:
gh api graphql -f owner="$OWNER" -f name="$REPO" -F number="$PR_NUMBER" -f query='
query($owner: String!, $name: String!, $number: Int!, $cursor: String) {
repository(owner: $owner, name: $name) {
pullRequest(number: $number) {
reviewThreads(first: 100, after: $cursor) {
pageInfo { hasNextPage endCursor }
nodes {
id
isResolved
comments(first: 100) {
nodes {
id
body
url
createdAt
author { login __typename }
}
}
}
}
}
}
}'
If hasNextPage=true, repeat the query with the returned endCursor until all review threads are fetched.
If GraphQL fails but REST succeeds, resolution state is unknown for inline threads. If --all is not set, exclude inline threads from the default filtered set, continue with review-summary and general PR comments, and report that inline threads were skipped because the unresolved-thread filter could not be applied. If --all is set, include REST-only inline threads, mark them Thread ID: unavailable and Resolution state: unknown, and do not resolve threads automatically. Review-summary and general PR comments can still be mapped and answered, but they never have a review-thread ID and are never resolved.
Group feedback into actionable items.
REST.node_id equals GraphQL.id).in_reply_to_id where present; root comments have no in_reply_to_id.review-summary item. Ignore empty approval/comment shells with no actionable body.general-comment item.html_url when available and GraphQL url as the fallback. For review-summary and general-comment items, use the REST html_url. Label links clearly enough to distinguish multiple comments, such as [@alice root], [@bob reply], [@alice review], or [@alice comment].Human confirmation required: yes whenever any human non-author feedback is being answered, including human replies inside bot/app-rooted inline threads. This derived confirmation field controls the mandatory posting confirmation in Step 8.PR_AUTHOR. Also identify the latest human non-author comment separately, because --human-only keeps mixed-origin items for their human feedback while treating bot/app comments as context.SELF or PR_AUTHOR. Keep items that contain reviewer feedback from any other human, bot, or app even when SELF or PR_AUTHOR also participated.HUMAN_ONLY=true, exclude items with no human non-author feedback. For mixed-origin items, keep the item but answer only the human non-author feedback; use bot/app comments only as context when needed.--all is set, exclude inline threads that are already resolved or whose latest non-author comment is older than a later reply from PR_AUTHOR; exclude review-summary and general-comment items when a later author reply clearly answers them. In REST-only fallback, Step 2 has already excluded inline threads unless --all was set, so still apply the author-reply filter to review-summary and general-comment items.--only <login> after all other filtering. If HUMAN_ONLY=true, compare <login> against the latest human non-author comment so a later bot/app comment does not drop selected human feedback from a mixed-origin thread; otherwise compare against the latest non-author comment.If no items remain after filtering, report that no unanswered review feedback was found and stop.
For every remaining item, inspect the relevant code and branch diff before drafting a reply.
Use these commands as needed:
git diff "origin/$BASE_BRANCH"...HEAD -- "$PATH"
sed -n '<start>,<end>p' "$PATH"
Classify each item as exactly one:
already-addressed - the requested code change is present in the current branch or the reviewer misunderstood code that is already correct.needs-code-change - the reviewer is right and the branch does not yet address it.explanation-needed - no code change is needed, but the reviewer deserves a concrete explanation.disagree - the suggested change would make the code worse, contradict requirements, or add out-of-scope churn.question-for-reviewer - the item cannot be answered without reviewer or product clarification.duplicate - another item covers the same issue.out-of-scope - the request is unrelated to the PR's intent.Do not claim a fix is complete unless the code or diff proves it. If the evidence is ambiguous, classify as question-for-reviewer or needs-code-change.
If any item is classified as needs-code-change and IMPLEMENT resolved to implement (via --implement or an explicit request to address the feedback), resolve the code changes before drafting replies. Under the plan-only default, skip this entire step.
Print a short implementation queue:
Implementing <N> review-requested code changes before drafting replies.
Use kramme:pr:resolve-review --implement-only as the implementation engine, passing a structured review payload that contains only the items classified as needs-code-change. Do not pass the PR URL as the source argument and do not use --source online for this handoff, because that would allow resolve-review to fetch and process comments outside this skill's filtered item set. Include the PR number/title as metadata, plus each selected item's source_id, item kind (inline-thread, review-summary, or general-comment), thread ID when present, root comment ID when present, reviewer, file/line when present, diff hunk when present, and comment body. --implement-only requires that caller-scoped findings payload, makes no GitHub writes, writes no REVIEW_OVERVIEW.md, and drafts no replies — this skill owns the reply and resolution phase. resolve-review still runs its own scope-creep and validity checks as a safety net, so it may decline or defer some of the set.
Proceed without another prompt; this step is only reached when implementation was already requested (Step 5 opening). Do not re-confirm before editing files.
After implementation returns, read .context/resolve-review/implement-only-summary.json and reconcile each item against the relevant files and diffs:
implemented → reclassify as already-addressed; record Implementation status: implemented and Action executed: <specific change>.already-addressed → keep or reclassify as already-addressed; record Implementation status: not needed and carry the action/evidence into the draft reply.skipped-out-of-scope → reclassify as out-of-scope, carrying resolve-review's rationale into the draft reply.skipped-invalid or disagreed → reclassify as disagree, carrying resolve-review's rationale into the draft reply.blocked-implementation or blocked-validation → keep the item as needs-code-change, mark Implementation status: blocked, and stop before posting replies.Always verify each claim against the actual diff; never trust the summary's status alone.
If implementation fails or validation fails, stop before posting replies. Keep or write the plan with Implementation status: blocked, include the failure, and do not draft a completion claim.
If a change is out of scope or needs product/reviewer clarification, keep the original classification and do not force an implementation.
If implementation is skipped (the plan-only default or --no-implement), mark code-change items as Implementation status: not attempted. Do not post acknowledgement-only replies for these items unless the user explicitly asks for that.
Draft one reply per item unless the item should be skipped.
Reply rules:
needs-code-change item. If implementation was skipped or blocked, mark the item as not ready to post unless the user explicitly asks for an acknowledgement reply.After the first draft pass, humanize the draft reply bodies before writing the plan or posting anything. Humanization is best-effort: if kramme:text:humanize is unavailable, skip it, mark Humanized: no on each affected item, and continue.
When humanize is available, send all draft reply bodies in a single batched call, separated by a stable delimiter that carries each reply's index. Send only the reply bodies — not reviewer quotes, code snippets, file paths, IDs, command examples, or plan metadata. Map the humanized results back to items by index; for any reply whose mapping is ambiguous, or if the returned count does not match the input, keep the original body for that item rather than risk posting mis-mapped text.
Apply the humanized output back into each Draft reply: field, preserving:
If the humanizer changes meaning, adds unsupported warmth, removes necessary technical detail, or weakens a disagreement, keep the original wording for that part and make the smallest manual edit needed to remove AI-sounding phrasing.
Resolve rules:
already-addressed, and the reply explains the completed fix or existing behavior.disagree, question-for-reviewer, or out-of-scope items. Let the reviewer decide.Unless --inline is set, create or update GITHUB_REVIEW_REPLY_PLAN.md in the project root with this structure:
# GitHub Review Reply Plan
**PR:** [<title> (#<number>)](<url>)
## Summary
| Metric | Count |
| --- | ---: |
| Review feedback items found | <count> |
| Inline threads | <count> |
| Review-summary comments | <count> |
| General PR comments | <count> |
| Ready to reply | <count> |
| Needs code changes | <count> |
| Code changes implemented | <count> |
| Safe to resolve after reply | <count> |
**Skipped:** <count and reason summary, or "0">
## Feedback
### 1. @<reviewer> - `<path>:<line or review-summary|general-comment>` - `<classification>`
| Field | Value |
| --- | --- |
| Kind | one of `inline-thread`, `review-summary`, `general-comment` |
| Thread ID | `<graphql-thread-id, unavailable, or n/a>` |
| Root comment ID | `<rest-root-comment-id or n/a>` |
| Comment ID | `<review id or issue comment id, when applicable>` |
| Source comment links | one or more Markdown links to the source GitHub review/general comments, or `unavailable` with a reason |
| Original author | `@<login>` |
| Original author type | one of `human`, `bot`, `app`, `unknown` |
| Human confirmation required | `yes` or `no` |
| Implementation status | one of `not needed`, `implemented`, `not attempted`, `blocked` |
| Action executed | <specific change, or "none"> |
| Reply target | one of `inline-reply`, `top-level-comment`, `none` |
| Resolve after posting | `yes` or `no` |
| Humanized | `yes` or `no` |
| Post status | one of `not posted`, `posted`, `posted and resolved`, `posted, resolve failed` |
**Reviewer comment**
<short quote or paraphrase>
**Assessment**
<why this classification is correct>
**Evidence checked**
- <file, diff, test, or "not verified">
**Draft reply**
> <reply>
Use this readable layout exactly: keep status in the item heading, metadata in the table, and prose fields in their own short sections. Do not collapse item metadata into one paragraph. Use bullets for Evidence checked when there is more than one evidence source.
If --inline is set, return the same structure in chat and do not create the file.
Treat GITHUB_REVIEW_REPLY_PLAN.md and the reply payload files under .context/github-review-replies/ (Step 9) as working artifacts that should not be committed and can be cleaned up by /kramme:workflow-artifacts:cleanup.
If POST=false and RESOLVE=false, stop after writing or returning the plan.
Before any GitHub write, show:
Posting <N> replies/comments and resolving <M> inline review threads on <PR URL>.
If any reply/comment has Human confirmation required: yes, always ask for explicit confirmation before posting that reply/comment. This applies to inline-thread replies, review-summary responses, and general PR comment responses, including mixed-origin inline threads where a bot/app opened the thread and a human added feedback later. The user's current message, --post, and --auto do not waive this confirmation. Show the exact reply body or bodies that would be posted for those items, wait for the user's approval, and only post the approved subset.
For remaining bot/app-origin replies or comments, ask for explicit confirmation unless the user's current message clearly requested posting now and the flags include --post or --auto. For REST-only fallback, always ask for explicit confirmation before posting because resolution state is unknown; --post and --auto do not waive this confirmation.
Do not post replies for items classified as needs-code-change or with Implementation status: blocked|not attempted unless the user explicitly asks to post acknowledgement replies.
For each approved inline-thread reply, JSON-encode the body to a temporary file under .context/github-review-replies/ and post it with the root REST review comment ID:
jq -n --arg body "$DRAFT_REPLY" '{body: $body}' > .context/github-review-replies/reply-THREAD.json
gh api -X POST "repos/$OWNER/$REPO/pulls/$PR_NUMBER/comments/$ROOT_COMMENT_ID/replies" --input .context/github-review-replies/reply-THREAD.json
If a reply post fails, stop posting further replies, preserve the plan file, and report the failed item and GitHub error.
For each approved review-summary or general-comment response, JSON-encode the body to a temporary file under .context/github-review-replies/ and post it as a top-level PR comment:
jq -n --arg body "$DRAFT_REPLY" '{body: $body}' > .context/github-review-replies/reply-ITEM.json
gh api -X POST "repos/$OWNER/$REPO/issues/$PR_NUMBER/comments" --input .context/github-review-replies/reply-ITEM.json
If posting a top-level comment fails, stop posting further replies/comments, preserve the plan file, and report the failed item and GitHub error.
Only resolve inline threads approved by Step 6 and successfully posted in Step 9, unless the user explicitly requested resolving already-replied addressed inline threads. Review-summary and general-comment items are not resolvable.
Resolve with GraphQL:
gh api graphql -f threadId="$THREAD_ID" -f query='
mutation($threadId: ID!) {
resolveReviewThread(input: {threadId: $threadId}) {
thread { id isResolved }
}
}'
After each successful resolve, update the plan's Post status field to posted and resolved. If a resolve fails after the reply posted, leave the reply in place, mark the Post status field as posted, resolve failed, and report the GitHub error.
End with:
GITHUB_REVIEW_REPLY_PLAN.md, unless --inline was usedIf any items remain needs-code-change, include this next step:
/kramme:pr:github-review-reply --implement <PR URL>
tools
Requires Linear MCP. Implements one Linear issue end to end, selects applicable code-review, convention, and PR-refactor gates, runs them to bounded convergence, verifies, and optionally opens the PR and iterates on CI and review feedback until green. Use when the user wants a single Linear issue taken from implementation through a clean Pull Request. Not for implementation-only work, SIW-tracked issues, stacked PRs, existing PR updates, or post-merge rollout.
development
Reviews PR and local changes for convention drift and overcaution against documented rules and mined peer-file practice. Use for new patterns, dependencies, abstractions, or defensive complexity that departs from established practice; every finding cites evidence. Supports --inline. Not for general code quality (use kramme:pr:code-review) or spec review (use kramme:siw:spec-audit --team).
testing
Charts huge or foggy initiatives into a local `.context` decision map and resolves one typed frontier ticket per session until the work is ready for SIW or another execution workflow. Use when the route to a destination cannot fit in one agent session or parallel workspaces need coordinated planning state. Not for clear specs, ordinary issue decomposition, implementation, or Linear-native tracking.
development
Investigates a question against primary sources and saves one cited Markdown artifact. Use for reading legwork: official docs/API facts, source-code or spec checks, standards, and first-party service behavior before planning or implementation. Not for making product or architecture decisions, implementing code, broad web search, secondary blog summaries, or uncited answers.