Skip to content

Commit 2f3e2a9

Browse files
authored
Merge pull request #227 from igerber/pr-improvement
Add local AI review skill (/ai-review-local)
2 parents 759616b + 90d477c commit 2f3e2a9

5 files changed

Lines changed: 1158 additions & 1 deletion

File tree

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
---
2+
description: Run AI code review locally using OpenAI API before opening a PR
3+
argument-hint: "[--full-registry] [--model <model>] [--dry-run]"
4+
---
5+
6+
# Local AI Code Review
7+
8+
Run a structured code review using the OpenAI Chat Completions API. Reviews changes
9+
against the same methodology criteria used by the CI reviewer, but adapted for local
10+
pre-PR use. Designed for iterative review/revision cycles before submitting a PR.
11+
12+
## Arguments
13+
14+
`$ARGUMENTS` may contain optional flags:
15+
- `--full-registry`: Include the entire REGISTRY.md instead of selective sections
16+
- `--model <name>`: Override the OpenAI model (default: `gpt-5.4`)
17+
- `--dry-run`: Print the compiled prompt without calling the API
18+
19+
## Constraints
20+
21+
This skill does not modify source code files. It may:
22+
- Create a commit if there are uncommitted changes (Step 3)
23+
- Create/update review artifacts in `.claude/reviews/` (gitignored)
24+
- Write temporary files to `/tmp/` (cleaned up in Step 8)
25+
26+
Step 5 makes a single external API call to OpenAI. Step 3b runs a secret scan
27+
before any data is sent externally.
28+
29+
## Instructions
30+
31+
### Step 1: Parse Arguments
32+
33+
Parse `$ARGUMENTS` for the optional flags listed above. All flags are optional —
34+
the default behavior (selective registry, gpt-5.4, live API call) requires no arguments.
35+
36+
### Step 2: Validate Prerequisites
37+
38+
Run these checks in parallel:
39+
40+
```bash
41+
# Check API key is set (never echo/log the actual value)
42+
test -n "$OPENAI_API_KEY" && echo "API key: set" || echo "API key: MISSING"
43+
44+
# Check script exists
45+
test -f .claude/scripts/openai_review.py && echo "Script: found" || echo "Script: MISSING"
46+
```
47+
48+
If the API key is missing (and not `--dry-run`):
49+
```
50+
Error: OPENAI_API_KEY is not set.
51+
52+
To set it up:
53+
1. Get a key from https://platform.openai.com/api-keys
54+
2. Add to your shell: echo 'export OPENAI_API_KEY=sk-...' >> ~/.zshrc
55+
3. Reload: source ~/.zshrc
56+
```
57+
58+
If the script is missing:
59+
```
60+
Error: .claude/scripts/openai_review.py not found.
61+
This file should be checked into the repository.
62+
```
63+
64+
Ensure the reviews directory exists:
65+
```bash
66+
mkdir -p .claude/reviews
67+
```
68+
69+
### Step 3: Commit Changes and Generate Diff
70+
71+
Determine and validate the comparison ref (matching the pattern from `/push-pr-update`):
72+
73+
```bash
74+
# Get the repo's default branch name
75+
default_branch=$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name' 2>/dev/null || echo "main")
76+
77+
# Resolve to a validated local ref (fallback chain for shallow/single-branch clones)
78+
if git rev-parse --verify "$default_branch" >/dev/null 2>&1; then
79+
comparison_ref="$default_branch"
80+
elif git rev-parse --verify "origin/$default_branch" >/dev/null 2>&1; then
81+
comparison_ref="origin/$default_branch"
82+
else
83+
git fetch origin "$default_branch" --depth=1 2>/dev/null || true
84+
comparison_ref="origin/$default_branch"
85+
fi
86+
```
87+
88+
If the comparison ref still doesn't resolve, abort:
89+
```
90+
Error: Cannot resolve comparison ref for '$default_branch'. Ensure you have
91+
fetched the default branch: git fetch origin $default_branch
92+
```
93+
94+
Check for uncommitted changes (modified, staged, or untracked):
95+
```bash
96+
git status --porcelain
97+
```
98+
99+
If there are uncommitted changes, commit them before proceeding:
100+
101+
1. Show the user what will be committed (the `git status --porcelain` output above)
102+
2. Stage all changes: `git add -A`
103+
3. Create a commit with a descriptive message summarizing the changes. Follow the
104+
repository's commit message conventions (see recent `git log --oneline`).
105+
4. Report: "Committed changes: <commit message> (<short sha>)"
106+
107+
If the commit fails (e.g., pre-commit hook), display the error and stop.
108+
109+
Generate diff and metadata:
110+
```bash
111+
git diff --unified=5 "${comparison_ref}...HEAD" > /tmp/ai-review-diff.patch
112+
git diff --name-status "${comparison_ref}...HEAD" > /tmp/ai-review-files.txt
113+
branch_name=$(git branch --show-current)
114+
```
115+
116+
If the diff is empty, report:
117+
```
118+
No committed changes vs ${comparison_ref} to review.
119+
```
120+
Clean up temp files and stop.
121+
122+
### Step 3b: Secret Scan Before API Upload
123+
124+
Before sending any diff content to OpenAI, run the canonical secret scan patterns
125+
(from `/pre-merge-check` Section 2.6) against the same diff range:
126+
127+
```bash
128+
# Content pattern — search diff content, output filenames only (never echo secret values)
129+
secret_files=$(git diff -G "(AKIA[A-Z0-9]{16}|ghp_[a-zA-Z0-9]{36}|sk-[a-zA-Z0-9]{48}|gho_[a-zA-Z0-9]{36}|[Aa][Pp][Ii][_-]?[Kk][Ee][Yy][[:space:]]*[=:]|[Ss][Ee][Cc][Rr][Ee][Tt][_-]?[Kk][Ee][Yy][[:space:]]*[=:]|[Pp][Aa][Ss][Ss][Ww][Oo][Rr][Dd][[:space:]]*[=:]|[Pp][Rr][Ii][Vv][Aa][Tt][Ee][_-]?[Kk][Ee][Yy]|[Bb][Ee][Aa][Rr][Ee][Rr][[:space:]]+[a-zA-Z0-9_-]+|[Tt][Oo][Kk][Ee][Nn][[:space:]]*[=:])" --name-only "${comparison_ref}...HEAD" 2>/dev/null || true)
130+
131+
# Sensitive filename pattern
132+
sensitive_files=$(git diff --name-only "${comparison_ref}...HEAD" | grep -iE "(\.env|credentials|secret|\.pem|\.key|\.p12|\.pfx|id_rsa|id_ed25519)$" || true)
133+
```
134+
135+
If either `secret_files` or `sensitive_files` is non-empty, use AskUserQuestion:
136+
```
137+
Warning: Potential secrets detected in files that would be sent to OpenAI:
138+
- <list filenames>
139+
140+
The diff containing these files is about to be transmitted to the OpenAI API.
141+
142+
Options:
143+
1. Abort — review and remove secrets before retrying
144+
2. Continue — I confirm these are not real secrets
145+
```
146+
147+
If user selects abort, clean up temp files and stop. If continue, proceed.
148+
149+
### Step 4: Handle Re-Review State
150+
151+
If `.claude/reviews/local-review-latest.md` exists, preserve it for re-review context:
152+
```bash
153+
if [ -f .claude/reviews/local-review-latest.md ]; then
154+
cp .claude/reviews/local-review-latest.md .claude/reviews/local-review-previous.md
155+
echo "Previous review preserved for re-review context."
156+
fi
157+
```
158+
159+
### Step 5: Run the Review Script
160+
161+
Build and run the command. Include `--previous-review` only if the previous review file
162+
exists from Step 4.
163+
164+
```bash
165+
python3 .claude/scripts/openai_review.py \
166+
--review-criteria .github/codex/prompts/pr_review.md \
167+
--registry docs/methodology/REGISTRY.md \
168+
--diff /tmp/ai-review-diff.patch \
169+
--changed-files /tmp/ai-review-files.txt \
170+
--output .claude/reviews/local-review-latest.md \
171+
--branch-info "$branch_name" \
172+
[--previous-review .claude/reviews/local-review-previous.md] \
173+
[--full-registry] \
174+
[--model <model>] \
175+
[--dry-run]
176+
```
177+
178+
If `--dry-run`: display the prompt output and stop. Report the estimated token count
179+
and model that would be used.
180+
181+
If the script exits non-zero, display the error output and stop.
182+
183+
### Step 6: Display the Review
184+
185+
Read and display the full contents of `.claude/reviews/local-review-latest.md`.
186+
187+
### Step 7: Summarize Findings and Offer Next Steps
188+
189+
Parse the review output to extract ALL findings. For each finding, capture:
190+
- Severity (P0/P1/P2/P3)
191+
- Section (Methodology, Code Quality, etc.)
192+
- One-line summary of the issue
193+
194+
Present a **findings summary** showing every finding, grouped by severity:
195+
196+
```
197+
## Review Summary: <assessment emoji and label>
198+
199+
### P0 — Blockers
200+
1. [Methodology] <one-line summary> — <file:line>
201+
2. [Security] <one-line summary> — <file:line>
202+
203+
### P1 — Needs Changes
204+
1. [Code Quality] <one-line summary> — <file:line>
205+
206+
### P2 — Should Fix
207+
1. [Documentation] <one-line summary> — <file:line>
208+
209+
### P3 — Informational (no action required)
210+
1. [Maintainability] <one-line summary> — <file:line>
211+
2. [Tech Debt] <one-line summary> — <file:line>
212+
```
213+
214+
Omit severity groups that have zero findings. The full review with details is already
215+
displayed in Step 6 — this summary helps the user quickly assess what needs attention.
216+
217+
Then use AskUserQuestion, tailored to the severity:
218+
219+
**If no findings at all** (clean review):
220+
```
221+
Review passed with no findings. Suggested next steps:
222+
- /submit-pr — commit and open a pull request
223+
```
224+
225+
**For ⛔ or ⚠️ (P0/P1 findings)**:
226+
```
227+
Options:
228+
1. Enter plan mode to address findings (Recommended)
229+
2. Re-run with --full-registry for deeper methodology context
230+
3. Skip — I'll address these manually
231+
```
232+
233+
**For ✅ with P2/P3 findings only**:
234+
```
235+
Options:
236+
1. Address findings before submitting
237+
2. Skip — proceed to /submit-pr
238+
```
239+
240+
**If user chooses to address findings**: Parse the findings from the review output.
241+
The review context is already in the conversation. Start addressing the findings
242+
directly — for P0/P1 issues use `EnterPlanMode` for a structured approach; for P2/P3
243+
issues, fix them directly since they are minor.
244+
245+
After fixes are committed, the user re-runs `/ai-review-local` for a follow-up review.
246+
247+
### Step 8: Cleanup
248+
249+
```bash
250+
rm -f /tmp/ai-review-diff.patch /tmp/ai-review-files.txt
251+
```
252+
253+
## Error Handling
254+
255+
| Scenario | Response |
256+
|---|---|
257+
| `OPENAI_API_KEY` not set (non-dry-run) | Error with setup instructions (see Step 2) |
258+
| Script file missing | Error suggesting it should be checked in |
259+
| No committed changes | Clean exit with message |
260+
| Script exits non-zero | Display stderr output from script |
261+
| Previous review file missing on re-run | Script warns and continues as fresh review |
262+
| User aborts due to uncommitted changes | Clean exit |
263+
264+
## Examples
265+
266+
```bash
267+
# Standard review of current branch vs main
268+
/ai-review-local
269+
270+
# Review with full methodology registry
271+
/ai-review-local --full-registry
272+
273+
# Preview the compiled prompt without calling the API
274+
/ai-review-local --dry-run
275+
276+
# Use a different model
277+
/ai-review-local --model gpt-4.1
278+
```
279+
280+
## Notes
281+
282+
- This skill does NOT modify source files — it only generates temp files and
283+
review artifacts in `.claude/reviews/` (which is gitignored). It may also
284+
create a commit if there are uncommitted changes (Step 3).
285+
- Re-review mode activates automatically when a previous review exists in
286+
`.claude/reviews/local-review-latest.md`
287+
- The review criteria are adapted from `.github/codex/prompts/pr_review.md` (same
288+
methodology axes, severity levels, and anti-patterns) but framed for local
289+
code-change review rather than PR review
290+
- The CI review (Codex action with full repo access) remains the authoritative final
291+
check — local review is a fast first pass to catch most issues early
292+
- **Data transmission**: In non-dry-run mode, this skill transmits the unified diff,
293+
changed-file metadata, selected methodology registry text, and prior review context
294+
(if present) to OpenAI via the Chat Completions API. Use `--dry-run` to preview
295+
exactly what would be sent.
296+
- This skill pairs naturally with the iterative workflow:
297+
`/ai-review-local` -> address findings -> `/ai-review-local` -> `/submit-pr`

0 commit comments

Comments
 (0)