| name | pr-review |
| description | Review a pull request against GodTools Android project conventions. Use when asked to review a PR, check code quality, or audit changes. |
| argument-hint | ["pr-number"] |
| allowed-tools | Bash, Read, Grep, Glob, Write, Edit |
Review pull request $ARGUMENTS against the GodTools Android project conventions.
Steps
-
Check for dismissed issues by reading .claude/skills/pr-review/dismissed-issues.md if it exists.
Load all dismissed entries — each has a Pattern and Reason. You will use these to suppress matching findings later.
-
Fetch the PR diff and metadata. If $ARGUMENTS is provided, use it as the PR number:
gh pr diff $ARGUMENTS
gh pr view $ARGUMENTS
If no PR number is given (or the above fails because no upstream PR exists), fall back to reviewing the current branch against develop:
git diff develop...HEAD
git log develop...HEAD --oneline
Use the branch name and commit log as the "title" in the review header.
-
Identify all changed files and categorize them (Kotlin, build scripts, resources, manifests, tests).
-
Pre-flight check — run ktlint. This is a hard blocker:
./gradlew :build-logic:ktlintCheck ktlintCheck
If it fails, report as Must Fix before reviewing anything else.
-
Review each category using the checklist below.
-
Before outputting, cross-reference every finding against dismissed patterns. A finding matches a dismissed pattern when it describes the same class of issue (not necessarily the exact file/line — match by concept). Move matched findings to a separate suppressed list.
-
Output a structured review (format below).
-
Post inline comments to the PR for every ⚠️ and ❌ finding that references a specific file and line number. Before posting, deduplicate against all existing comments (resolved or not) to avoid re-posting anything already raised:
HEAD_SHA=$(gh pr view $ARGUMENTS --json headRefOid -q .headRefOid)
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
EXISTING=$(gh api repos/$REPO/pulls/$ARGUMENTS/comments --jq '[.[] | select(.in_reply_to_id == null) | {path:.path, line:.line, body:.body}]')
For each finding, check whether any existing comment (resolved or not) already covers the same file + line (or contains substantially the same text). Skip any finding that is already covered. Then bundle the remaining new comments into a single review submission:
gh api repos/$REPO/pulls/$ARGUMENTS/reviews \
--method POST \
--field commit_id="$HEAD_SHA" \
--field event="COMMENT" \
--field "comments[][path]=<file path>" \
--field "comments[][line]=<line number>" \
--field "comments[][side]=RIGHT" \
--field "comments[][body]=<finding text>
🤖 Posted by [Claude Code](https://claude.ai/code)" \
Use the exact file path from the diff and the line number in the current version of the file (RIGHT side). Each comment body should contain the full finding description. Always append the attribution footer \n\n🤖 Posted by [Claude Code](https://claude.ai/code) to each comment. If no new actionable findings exist (only ✅ items or all already commented), skip this step.
-
If the review has no ❌ or ⚠️ findings (only ✅ and/or ⏭️ items), ask the user whether to post the full review. If they say yes:
- Check whether the PR author matches the current git user (
gh pr view $ARGUMENTS --json author -q .author.login vs gh api user -q .login)
- If it is a self-review, post with
--comment (GitHub does not allow self-approval)
- If it is someone else's PR, ask whether to approve or just comment, then post with
--approve or --comment accordingly
- Always append
\n\n🤖 Posted by [Claude Code](https://claude.ai/code) to the body
-
After the review output, print:
---
To dismiss a finding so it won't appear in future reviews, say:
dismiss: <short title> — <reason>
Review Checklist
Build Scripts (build.gradle.kts)
gradle/libs.versions.toml
Android Resources & Manifests
settings.gradle.kts
Jetpack Compose
Circuit Presenter/UI Patterns
Presenter
UI Composable
Screen
Cross-Module Activity / Intent Creation
Repository & DAO Patterns
WorkManager
Kotlin Code Quality
Testing
PR Hygiene
For detailed examples of each pattern, see references/patterns.md.
When reviewing any Compose UI code, also load .claude/rules/design_system_rules.md — it defines the authoritative conventions for color tokens, typography, spacing, icons, components, and accessibility.
Output Format
## PR Review: <title> (#<number>)
### Summary
<1–2 sentence summary of what the PR does>
### Checklist Findings
#### ✅ Looks Good
- <item>
#### ⚠️ Minor Issues
- <file:line> — <issue> — <suggested fix>
#### ❌ Must Fix
- <file:line> — <issue> — <suggested fix>
#### ⏭️ Suppressed
- <short title> — dismissed: <reason>
(omit this section entirely if nothing was suppressed)
### Overall Verdict
APPROVE / REQUEST CHANGES / COMMENT
<brief rationale>
Be specific. Reference file paths and line numbers. Cite the relevant convention when flagging an issue.
Handling Dismissals
When the user says dismiss: <title> — <reason> (in any form — "dismiss the X issue because Y", etc.):
- Read
.claude/skills/pr-review/dismissed-issues.md if it exists (create it if not).
- Run
git config user.name to get the current user's name.
- Append a new entry in this format:
## <title>
**Pattern**: <describe the class of issue broadly enough to match future occurrences>
**Reason**: <reason the user gave>
**Dismissed**: <today's date as YYYY-MM-DD>
**Dismissed by**: <git user.name>
- If the current session reviewed a PR, find any open (unresolved) comment thread on that PR matching the dismissed issue. Use the GraphQL API to locate threads and resolve the matching one, replying with the dismissal reason first:
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
OWNER=${REPO%%/*}
REPONAME=${REPO##*/}
gh api graphql -f query="
{
repository(owner: \"$OWNER\", name: \"$REPONAME\") {
pullRequest(number: $PR_NUMBER) {
reviewThreads(first: 100) {
nodes {
id
isResolved
comments(first: 1) {
nodes { id body path line }
}
}
}
}
}
}"
Match the thread by file path, line number, or substantial text overlap with the dismissed finding. Then reply to the thread and resolve it:
gh api repos/$REPO/pulls/$PR_NUMBER/comments \
--method POST \
--field in_reply_to=<comment_id> \
--field body="Dismissed: <reason given by user>
🤖 [Claude Code](https://claude.ai/code)"
gh api graphql -f query="
mutation {
resolveReviewThread(input: { threadId: \"<thread_node_id>\" }) {
thread { id isResolved }
}
}"
- Confirm to the user what was added and that it will be suppressed in future reviews.