review-pr-comments — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited review-pr-comments (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
User-invoked only. $ARGUMENTS is an optional PR number; if empty, auto-detect from the current branch.
All GitHub interaction goes through gh CLI — never the GitHub MCP server. The MCP server is incomplete (missing endpoints for review-thread resolution, partial coverage of comment surfaces).
If $ARGUMENTS has a number, use it.
Otherwise:
BRANCH=$(git branch --show-current)
gh pr list --head "$BRANCH" --json number,title,url --jq '.[0]'If no open PR for the branch, stop and tell the user.
Capture OWNER, REPO, PR for the rest of the run:
gh repo view --json owner,name --jq '"\(.owner.login) \(.name)"'GitHub exposes PR feedback in three places. Missing any one means you'll miss real comments. Always check all three.
These are the most common — Gemini/Claude/Copilot bots, human reviewers' line-level comments.
gh api "repos/$OWNER/$REPO/pulls/$PR/comments" --paginate \
--jq '.[] | {id, path, line, body, user: .user.login, in_reply_to_id, html_url}'Fields you need: id (REST numeric, used for reply), path, line, body, user.login, in_reply_to_id (non-null = follow-up reply, ignore the duplicates).
To resolve a thread you need its GraphQL node ID. Fetch in one query and correlate by databaseId ↔ REST id:
gh api graphql -f query='
query($owner: String!, $repo: String!, $pr: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $pr) {
reviewThreads(first: 100) {
nodes {
id
isResolved
isOutdated
path
line
comments(first: 1) { nodes { databaseId author { login } body } }
}
}
}
}
}' -F owner="$OWNER" -F repo="$REPO" -F pr="$PR"Build a map databaseId → {threadId, isResolved} so step 6 can resolve by REST comment ID.
Skip threads where isResolved: true — already handled.
This is where Claude-bot summaries, Gemini-bot summary, Copilot summary, and human comments-without-line-context land. The REST endpoint is /issues/.../comments because GitHub stores PR-level conversation as issue comments.
gh api "repos/$OWNER/$REPO/issues/$PR/comments" --paginate \
--jq '.[] | {id, body, user: .user.login, created_at, html_url}'When a reviewer submits "Request changes" or "Approve" they often paste a body with overall feedback. Different endpoint:
gh api "repos/$OWNER/$REPO/pulls/$PR/reviews" --paginate \
--jq '.[] | {id, state, body, user: .user.login}'Filter out bot summary blobs — purely informational, never actionable:
gemini-code-assist[bot] summary comments (the long "Summary of Changes" general comment — keep the inline [medium]/[high] priority ones)copilot-pull-request-reviewer[bot] summarycoderabbitai[bot] walk-through commentKeep bot comments that raise specific findings (Gemini inline, Claude bot inline, Copilot inline). Read the body, not the author — if there's a concrete code suggestion, it's actionable.
For every real comment, assign one of three verdicts:
Read the file before deciding. Don't blindly trust the reviewer; also don't reflexively dismiss bot output — Gemini/Copilot often catch real issues.
Common patterns in this codebase to watch for:
noUncheckedIndexedAccess is on, T | undefined from arr[i] is real. A bot warning about a missing ! or ?? fallback is usually valid.packages/server/src/telemetry/: comments about identity propagation across async boundaries deserve careful reading.analytics-store.ts / queries.ts: IS vs = for nullable columns, json_each parameter bindings — bot suggestions about these are usually correct.mcp-handler.ts: handlers are monkey-patched via server.tool; bot comments about telemetry-wrap behavior need to be checked against the wrapper, not the raw handler.CLAUDE.md). Any comment suggesting randomUUID() or auto-increment is invalid.## PR review assessment — #<PR_NUMBER>
### packages/.../file.ts:42 — <one-line gist>
Verdict: Valid & fix | Valid & skip | Invalid
Reason: <1–2 sentences>
Thread: <resolved | open>
...Group by file, ordered by line. Show all comments — including the ones you'd skip — so the user can override your call.
Ask the user to confirm which ones to fix. Don't auto-proceed.
For each approved "Valid & fix":
CLAUDE.md for the codebase's "Key patterns" section.IS operator suggestion reveals the prepared statement has too many parameters), fix both — don't leave the file inconsistent.Run the relevant subset, in roughly increasing cost:
yarn prettier:check # fast
yarn lint # fast
yarn workspace @paparats/<affected-pkg> typecheck
yarn workspace @paparats/<affected-pkg> testBefore pushing — full sweep:
yarn check && yarn testIf any quality gate fails, fix it before moving on. Never commit through a broken gate.
Close the loop on GitHub. Always reply and resolve — never silent resolution, never resolve without replying.
REST endpoint, posts a reply in the same thread as the original comment:
gh api "repos/$OWNER/$REPO/pulls/$PR/comments/$COMMENT_ID/replies" \
-f body="Fixed in <commit-sha-short> — <one-sentence what changed>."$COMMENT_ID is the REST numeric id of the original comment (not your reply).
For Valid & skip / Invalid, reply with the reason: "Not applicable because…" / "Already handled by … in <file>:<line>."
Use the GraphQL threadId you correlated in step 2b:
gh api graphql -f query='
mutation($threadId: ID!) {
resolveReviewThread(input: {threadId: $threadId}) {
thread { isResolved }
}
}' -f threadId="$THREAD_ID"There's no native thread / reply for issue-level comments. Either:
> @<author> on <date>: … then your response.There's nothing to "resolve" — issue comments don't have a resolution state.
gh pr checks "$PR"For each failing check:
# Extract run ID from the URL field of `gh pr checks --json`:
gh pr checks "$PR" --json name,state,link --jq '.[] | select(.state != "SUCCESS")'
# Then for each failing run:
RUN_ID=$(echo "$LINK" | grep -oE '[0-9]+$')
gh run view "$RUN_ID" --log-failedTriage each failure:
yarn workspace @paparats/<pkg> test.yarn install locally and commit the lockfile.Summarise in this shape:
## PR #<N> review handled
Fixed (N):
- <file:line> — <what changed> (commit <sha>)
...
Replied & resolved (N + M):
- N fixes + M skip/invalid
Skipped (M):
- <file:line> — <reason>
CI:
- ✅ <check> (fixed by <commit>)
- ⚠️ <check> (pre-existing on main, not this PR)
Outstanding:
- <anything that needs the user's eyes>Never commit or push for the user. Stage the changes; let them review and commit.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.