Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
297 changes: 297 additions & 0 deletions .claude/commands/ai-review-local.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,297 @@
---
description: Run AI code review locally using OpenAI API before opening a PR
argument-hint: "[--full-registry] [--model <model>] [--dry-run]"
---

# Local AI Code Review

Run a structured code review using the OpenAI Chat Completions API. Reviews changes
against the same methodology criteria used by the CI reviewer, but adapted for local
pre-PR use. Designed for iterative review/revision cycles before submitting a PR.

## Arguments

`$ARGUMENTS` may contain optional flags:
- `--full-registry`: Include the entire REGISTRY.md instead of selective sections
- `--model <name>`: Override the OpenAI model (default: `gpt-5.4`)
- `--dry-run`: Print the compiled prompt without calling the API

## Constraints

This skill does not modify source code files. It may:
- Create a commit if there are uncommitted changes (Step 3)
- Create/update review artifacts in `.claude/reviews/` (gitignored)
- Write temporary files to `/tmp/` (cleaned up in Step 8)

Step 5 makes a single external API call to OpenAI. Step 3b runs a secret scan
before any data is sent externally.

## Instructions

### Step 1: Parse Arguments

Parse `$ARGUMENTS` for the optional flags listed above. All flags are optional —
the default behavior (selective registry, gpt-5.4, live API call) requires no arguments.

### Step 2: Validate Prerequisites

Run these checks in parallel:

```bash
# Check API key is set (never echo/log the actual value)
test -n "$OPENAI_API_KEY" && echo "API key: set" || echo "API key: MISSING"

# Check script exists
test -f .claude/scripts/openai_review.py && echo "Script: found" || echo "Script: MISSING"
```

If the API key is missing (and not `--dry-run`):
```
Error: OPENAI_API_KEY is not set.

To set it up:
1. Get a key from https://platform.openai.com/api-keys
2. Add to your shell: echo 'export OPENAI_API_KEY=sk-...' >> ~/.zshrc
3. Reload: source ~/.zshrc
```

If the script is missing:
```
Error: .claude/scripts/openai_review.py not found.
This file should be checked into the repository.
```

Ensure the reviews directory exists:
```bash
mkdir -p .claude/reviews
```

### Step 3: Commit Changes and Generate Diff

Determine and validate the comparison ref (matching the pattern from `/push-pr-update`):

```bash
# Get the repo's default branch name
default_branch=$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name' 2>/dev/null || echo "main")

# Resolve to a validated local ref (fallback chain for shallow/single-branch clones)
if git rev-parse --verify "$default_branch" >/dev/null 2>&1; then
comparison_ref="$default_branch"
elif git rev-parse --verify "origin/$default_branch" >/dev/null 2>&1; then
comparison_ref="origin/$default_branch"
else
git fetch origin "$default_branch" --depth=1 2>/dev/null || true
comparison_ref="origin/$default_branch"
fi
```

If the comparison ref still doesn't resolve, abort:
```
Error: Cannot resolve comparison ref for '$default_branch'. Ensure you have
fetched the default branch: git fetch origin $default_branch
```

Check for uncommitted changes (modified, staged, or untracked):
```bash
git status --porcelain
```

If there are uncommitted changes, commit them before proceeding:

1. Show the user what will be committed (the `git status --porcelain` output above)
2. Stage all changes: `git add -A`
3. Create a commit with a descriptive message summarizing the changes. Follow the
repository's commit message conventions (see recent `git log --oneline`).
4. Report: "Committed changes: <commit message> (<short sha>)"

If the commit fails (e.g., pre-commit hook), display the error and stop.

Generate diff and metadata:
```bash
git diff --unified=5 "${comparison_ref}...HEAD" > /tmp/ai-review-diff.patch
git diff --name-status "${comparison_ref}...HEAD" > /tmp/ai-review-files.txt
branch_name=$(git branch --show-current)
```

If the diff is empty, report:
```
No committed changes vs ${comparison_ref} to review.
```
Clean up temp files and stop.

### Step 3b: Secret Scan Before API Upload

Before sending any diff content to OpenAI, run the canonical secret scan patterns
(from `/pre-merge-check` Section 2.6) against the same diff range:

```bash
# Content pattern — search diff content, output filenames only (never echo secret values)
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)

# Sensitive filename pattern
sensitive_files=$(git diff --name-only "${comparison_ref}...HEAD" | grep -iE "(\.env|credentials|secret|\.pem|\.key|\.p12|\.pfx|id_rsa|id_ed25519)$" || true)
```

If either `secret_files` or `sensitive_files` is non-empty, use AskUserQuestion:
```
Warning: Potential secrets detected in files that would be sent to OpenAI:
- <list filenames>

The diff containing these files is about to be transmitted to the OpenAI API.

Options:
1. Abort — review and remove secrets before retrying
2. Continue — I confirm these are not real secrets
```

If user selects abort, clean up temp files and stop. If continue, proceed.

### Step 4: Handle Re-Review State

If `.claude/reviews/local-review-latest.md` exists, preserve it for re-review context:
```bash
if [ -f .claude/reviews/local-review-latest.md ]; then
cp .claude/reviews/local-review-latest.md .claude/reviews/local-review-previous.md
echo "Previous review preserved for re-review context."
fi
```

### Step 5: Run the Review Script

Build and run the command. Include `--previous-review` only if the previous review file
exists from Step 4.

```bash
python3 .claude/scripts/openai_review.py \
--review-criteria .github/codex/prompts/pr_review.md \
--registry docs/methodology/REGISTRY.md \
--diff /tmp/ai-review-diff.patch \
--changed-files /tmp/ai-review-files.txt \
--output .claude/reviews/local-review-latest.md \
--branch-info "$branch_name" \
[--previous-review .claude/reviews/local-review-previous.md] \
[--full-registry] \
[--model <model>] \
[--dry-run]
```

If `--dry-run`: display the prompt output and stop. Report the estimated token count
and model that would be used.

If the script exits non-zero, display the error output and stop.

### Step 6: Display the Review

Read and display the full contents of `.claude/reviews/local-review-latest.md`.

### Step 7: Summarize Findings and Offer Next Steps

Parse the review output to extract ALL findings. For each finding, capture:
- Severity (P0/P1/P2/P3)
- Section (Methodology, Code Quality, etc.)
- One-line summary of the issue

Present a **findings summary** showing every finding, grouped by severity:

```
## Review Summary: <assessment emoji and label>

### P0 — Blockers
1. [Methodology] <one-line summary> — <file:line>
2. [Security] <one-line summary> — <file:line>

### P1 — Needs Changes
1. [Code Quality] <one-line summary> — <file:line>

### P2 — Should Fix
1. [Documentation] <one-line summary> — <file:line>

### P3 — Informational (no action required)
1. [Maintainability] <one-line summary> — <file:line>
2. [Tech Debt] <one-line summary> — <file:line>
```

Omit severity groups that have zero findings. The full review with details is already
displayed in Step 6 — this summary helps the user quickly assess what needs attention.

Then use AskUserQuestion, tailored to the severity:

**If no findings at all** (clean review):
```
Review passed with no findings. Suggested next steps:
- /submit-pr — commit and open a pull request
```

**For ⛔ or ⚠️ (P0/P1 findings)**:
```
Options:
1. Enter plan mode to address findings (Recommended)
2. Re-run with --full-registry for deeper methodology context
3. Skip — I'll address these manually
```

**For ✅ with P2/P3 findings only**:
```
Options:
1. Address findings before submitting
2. Skip — proceed to /submit-pr
```

**If user chooses to address findings**: Parse the findings from the review output.
The review context is already in the conversation. Start addressing the findings
directly — for P0/P1 issues use `EnterPlanMode` for a structured approach; for P2/P3
issues, fix them directly since they are minor.

After fixes are committed, the user re-runs `/ai-review-local` for a follow-up review.

### Step 8: Cleanup

```bash
rm -f /tmp/ai-review-diff.patch /tmp/ai-review-files.txt
```

## Error Handling

| Scenario | Response |
|---|---|
| `OPENAI_API_KEY` not set (non-dry-run) | Error with setup instructions (see Step 2) |
| Script file missing | Error suggesting it should be checked in |
| No committed changes | Clean exit with message |
| Script exits non-zero | Display stderr output from script |
| Previous review file missing on re-run | Script warns and continues as fresh review |
| User aborts due to uncommitted changes | Clean exit |

## Examples

```bash
# Standard review of current branch vs main
/ai-review-local

# Review with full methodology registry
/ai-review-local --full-registry

# Preview the compiled prompt without calling the API
/ai-review-local --dry-run

# Use a different model
/ai-review-local --model gpt-4.1
```

## Notes

- This skill does NOT modify source files — it only generates temp files and
review artifacts in `.claude/reviews/` (which is gitignored). It may also
create a commit if there are uncommitted changes (Step 3).
- Re-review mode activates automatically when a previous review exists in
`.claude/reviews/local-review-latest.md`
- The review criteria are adapted from `.github/codex/prompts/pr_review.md` (same
methodology axes, severity levels, and anti-patterns) but framed for local
code-change review rather than PR review
- The CI review (Codex action with full repo access) remains the authoritative final
check — local review is a fast first pass to catch most issues early
- **Data transmission**: In non-dry-run mode, this skill transmits the unified diff,
changed-file metadata, selected methodology registry text, and prior review context
(if present) to OpenAI via the Chat Completions API. Use `--dry-run` to preview
exactly what would be sent.
- This skill pairs naturally with the iterative workflow:
`/ai-review-local` -> address findings -> `/ai-review-local` -> `/submit-pr`
Loading
Loading