Skip to content

Commit b0e6e9a

Browse files
committed
meta: add PR review skill and ignore .prs/ output directory
1 parent b63d2c1 commit b0e6e9a

3 files changed

Lines changed: 149 additions & 0 deletions

File tree

.claude/skills/review-prs/SKILL.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
---
2+
name: review-prs
3+
tools: Read, Grep, Glob, Bash
4+
---
5+
6+
Review all open PRs on pyinfra-dev/pyinfra and maintain review files in `.prs/`:
7+
8+
## Steps
9+
10+
1. **Run sync script**: Execute `bash .claude/skills/review-prs/sync.sh` to clean up stale reviews and get the list of PRs to update/create.
11+
12+
2. **For each PR** in the sync output (Update + New only, NOT Unchanged), launch agents in parallel (batches of 3-5) to review:
13+
- Each agent gets: repo name, PR number, whether it's an update or new review.
14+
- Agent fetches the PR diff via `gh pr diff --repo pyinfra-dev/pyinfra {number}`.
15+
- Agent also fetches `updatedAt` via `gh pr view --repo pyinfra-dev/pyinfra {number} --json updatedAt --jq .updatedAt` and includes it in the review header as `**PR Updated:** {timestamp}`.
16+
- Agent reads relevant source code files being modified (use Read/Grep, never assume).
17+
- Agent writes the review file to `.prs/{number}.md`.
18+
19+
3. **Review format** for each PR file (`.prs/{number}.md`):
20+
21+
```markdown
22+
# PR #{number} - {title}
23+
24+
**Author:** {author}
25+
**URL:** https://github.com/pyinfra-dev/pyinfra/pull/{number}
26+
**Review Date:** {YYYY-MM-DD}
27+
**PR Updated:** {updatedAt ISO timestamp from GH API}
28+
29+
## Verdict: {GO | NO-GO | NEEDS-DISCUSSION}
30+
31+
{1-2 sentence summary of what the PR does}
32+
33+
## Issues
34+
35+
{Only if there are problems. Each issue should be a concise bullet with a code snippet if relevant. Skip this section entirely if no issues.}
36+
37+
## Notes
38+
39+
{Optional minor observations, nits, or suggestions. Keep brief.}
40+
```
41+
42+
## Review guidelines
43+
44+
- **Be minimal**: Only highlight actual problems or risks. Don't pad reviews with praise or restatements.
45+
- **Code snippets**: When referencing problematic code, include the relevant snippet (keep short).
46+
- **Deep inspection**: Always read the actual source code being modified. Never assume behavior - trace code paths, check callers, verify types. Use Grep/Read extensively.
47+
- **Verdict options**:
48+
* **GO** = safe to merge as-is or with trivial nits only
49+
* **NO-GO** = has bugs, security issues, breaking changes, or significant design problems
50+
* **NEEDS-DISCUSSION** = requires maintainer input on approach/design
51+
52+
## Parallelism
53+
54+
- Process multiple PRs in parallel using Agent tool where possible (batch into groups of 3-5).
55+
- Each agent should be given the full context: repo name, PR number, review format, and instruction to deeply inspect code.
56+
57+
## Final Summary
58+
59+
Once all review updates are complete, output a summary table of PRs grouped by verdict. Re-read the PR files to collect updated verdicts for each.

.claude/skills/review-prs/sync.sh

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#!/usr/bin/env bash
2+
# Syncs .prs/ review files against open GitHub PRs.
3+
# Deletes reviews for merged/closed PRs, outputs a plan for what to update/create.
4+
# Skips re-review when PR hasn't been updated since the last review.
5+
set -euo pipefail
6+
7+
REPO="pyinfra-dev/pyinfra"
8+
PRS_DIR="$(git rev-parse --show-toplevel)/.prs"
9+
10+
mkdir -p "$PRS_DIR"
11+
12+
# Fetch all open PR numbers (updated in last year)
13+
SINCE=$(date -v-1y +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -d '1 year ago' +%Y-%m-%dT%H:%M:%SZ)
14+
OPEN_PRS=$(gh pr list --repo "$REPO" --state open --limit 200 --json number,title,author,updatedAt \
15+
--jq "[.[] | select(.updatedAt >= \"$SINCE\")] | sort_by(.number)")
16+
17+
OPEN_NUMBERS=$(echo "$OPEN_PRS" | jq -r '.[].number')
18+
19+
# Find existing review files
20+
EXISTING=()
21+
for f in "$PRS_DIR"/*.md; do
22+
[ -f "$f" ] || continue
23+
num=$(basename "$f" .md)
24+
[[ "$num" =~ ^[0-9]+$ ]] && EXISTING+=("$num")
25+
done
26+
27+
# Delete stale reviews (merged/closed)
28+
DELETED=()
29+
for num in "${EXISTING[@]}"; do
30+
if ! echo "$OPEN_NUMBERS" | grep -qx "$num"; then
31+
rm "$PRS_DIR/$num.md"
32+
DELETED+=("$num")
33+
fi
34+
done
35+
36+
# Categorize: update (changed), unchanged (skip), or new
37+
UPDATE=()
38+
UNCHANGED=()
39+
NEW=()
40+
while IFS= read -r num; do
41+
if [ -f "$PRS_DIR/$num.md" ]; then
42+
# Compare stored updatedAt with current PR updatedAt
43+
stored_ts=$(sed -n 's/^\*\*PR Updated:\*\* //p' "$PRS_DIR/$num.md" 2>/dev/null || echo "")
44+
current_ts=$(echo "$OPEN_PRS" | jq -r ".[] | select(.number == $num) | .updatedAt")
45+
if [ -n "$stored_ts" ] && [ "$stored_ts" = "$current_ts" ]; then
46+
UNCHANGED+=("$num")
47+
else
48+
UPDATE+=("$num")
49+
fi
50+
else
51+
NEW+=("$num")
52+
fi
53+
done <<< "$OPEN_NUMBERS"
54+
55+
# Output markdown summary
56+
echo "# PR Review Sync"
57+
echo ""
58+
echo "**Repo:** $REPO"
59+
echo "**Date:** $(date +%Y-%m-%d)"
60+
echo ""
61+
62+
if [ ${#DELETED[@]} -gt 0 ]; then
63+
echo "## Deleted (merged/closed)"
64+
for num in "${DELETED[@]}"; do
65+
echo "- #$num"
66+
done
67+
echo ""
68+
fi
69+
70+
if [ ${#UNCHANGED[@]} -gt 0 ]; then
71+
echo "## Unchanged since last review (${#UNCHANGED[@]})"
72+
echo "$OPEN_PRS" | jq -r --argjson nums "$(printf '%s\n' "${UNCHANGED[@]}" | jq -R 'tonumber' | jq -s '.')" \
73+
'.[] | select(.number as $n | $nums | index($n)) | "- #\(.number) \(.title) (@\(.author.login))"'
74+
echo ""
75+
fi
76+
77+
echo "## Update existing reviews (${#UPDATE[@]})"
78+
if [ ${#UPDATE[@]} -gt 0 ]; then
79+
echo "$OPEN_PRS" | jq -r --argjson nums "$(printf '%s\n' "${UPDATE[@]}" | jq -R 'tonumber' | jq -s '.')" \
80+
'.[] | select(.number as $n | $nums | index($n)) | "- #\(.number) \(.title) (@\(.author.login))"'
81+
fi
82+
echo ""
83+
84+
echo "## New reviews needed (${#NEW[@]})"
85+
if [ ${#NEW[@]} -gt 0 ]; then
86+
echo "$OPEN_PRS" | jq -r --argjson nums "$(printf '%s\n' "${NEW[@]}" | jq -R 'tonumber' | jq -s '.')" \
87+
'.[] | select(.number as $n | $nums | index($n)) | "- #\(.number) \(.title) (@\(.author.login))"'
88+
fi

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,5 @@ docs/_deploy_globals.rst
3535

3636
pyinfra-debug.log
3737
Makefile
38+
39+
.prs/

0 commit comments

Comments
 (0)