Review a GitHub PR against standards
/plugin marketplace add jeffweiss/elixir-production/plugin install jeffweiss-elixir-production@jeffweiss/elixir-production<pr-number>sonnetAutomated GitHub Pull Request review using gh CLI and pr-reviewer agent. Checks code against project standards, identifies issues, and triggers cognitive complexity analysis for large changes.
Reviews GitHub PRs comprehensively:
gh CLI to get PR data, diff, changed filesRequired:
gh CLI installed and authenticatedSetup:
# Install gh CLI
brew install gh # macOS
# or apt install gh # Linux
# Authenticate
gh auth login
# Verify access
gh pr list
# Review specific PR
/pr-review 123
# Review current branch's PR
/pr-review
# Review with PR URL
/pr-review https://github.com/owner/repo/pull/456
Fetching PR #123 using gh CLI...
PR: Add user profile feature
Author: @developer
Files changed: 8
Lines: +452 / -23
Using gh CLI:
# Get PR metadata
gh pr view 123 --json number,title,body,author,files,additions,deletions
# Get PR diff
gh pr diff 123
# List changed files
gh pr view 123 --json files --jq '.files[].path'
Thresholds for cognitive review:
Analyzing PR scale...
Files changed: 8
Lines changed: +452 / -23
Complexity: Medium
This is a moderately large change. Will launch cognitive-scientist agent for complexity analysis.
For all PRs - Launch pr-reviewer agent:
Launching pr-reviewer agent for code review...
The reviewer will:
1. Load project standards (AGENTS.md, CLAUDE.md, project-learnings.md)
2. Review changed files against standards
3. Check for missing typespecs, tests, error handling
4. Identify SPIKE code
5. Verify project convention compliance
For large PRs - Also launch cognitive-scientist:
Launching cognitive-scientist agent for cognitive complexity analysis...
This PR modifies 8 files with 452 lines. Analyzing:
- Deep vs shallow modules
- Working memory load
- Onboarding difficulty
- Complexity indicators
The pr-reviewer agent executes:
# Fetch changed files
gh pr diff 123 > /tmp/pr_123.diff
# Read changed files
for file in $(gh pr view 123 --json files --jq '.files[].path'); do
Read $file
done
# Load project standards
Read AGENTS.md
Read CLAUDE.md
Read .claude/project-learnings.md
# Analyze each file
- Check typespecs on public functions
- Verify test coverage
- Check error handling (tagged tuples)
- Identify SPIKE markers
- Verify project patterns
# Rate confidence for each issue
# Report only issues with ≥80% confidence
Generate review comment:
gh pr comment 123 --body "$(cat review.md)"
Review format:
## Code Review Summary
### 📊 Change Statistics
- Files changed: 8
- Lines added: +452
- Lines deleted: -23
- Complexity: Medium
### ✅ Strengths
- Excellent test coverage (95%)
- Clear separation of concerns
- Follows project authentication patterns
- Good error handling with tagged tuples
### ⚠️ Issues Found
#### [Critical] Missing typespec on public API (Confidence: 95%)
**File**: `lib/my_app/accounts.ex:45`
**Function**: `update_profile/2` needs typespec
**Recommendation**:
```elixir
@spec update_profile(User.t(), map()) ::
{:ok, User.t()} | {:error, Ecto.Changeset.t()}
def update_profile(user, params) do
# ...
end
File: lib/my_app_web/profile_live.ex:23
Issue: Loading user posts in loop
Recommendation: Add preload in query:
user = Accounts.get_user!(id) |> Repo.preload(:posts)
PR adds 452 lines across 8 files. Cognitive assessment:
Strengths:
Accounts.ProfileConcerns:
ProfileLive.handle_event/3 has mixed abstraction levelsAccounts.ProfileValidatorOverall: Well-structured with opportunities for improved clarity.
None detected. All code appears production-ready.
update_profile/2/precommit before merging🤖 Generated with Claude Code - Elixir Production Plugin
### Step 6: Handle Edge Cases
**PR not found**:
```markdown
❌ PR Not Found
Error: PR #999 does not exist in this repository
Check:
- PR number is correct
- You have access to the repository
- PR hasn't been closed/deleted
Not in git repository:
❌ Not in Git Repository
Current directory is not a git repository.
Navigate to your project root and try again.
gh CLI not authenticated:
❌ GitHub CLI Not Authenticated
Run: gh auth login
Then try the pr-review command again.
The pr-reviewer agent checks:
Elixir Standards:
with for railway programmingTesting:
Phoenix/LiveView (if applicable):
to_form/2on_mount hooks for authassign_async for async operationsSecurity:
Against project-learnings.md:
Against AGENTS.md/CLAUDE.md:
Detection markers:
# SPIKE: <reason>
# TODO: Add typespecs
# TODO: Add tests
# Needs refactoring
Migration readiness:
Input:
/pr-review 123
Output:
## Code Review: Fix email validation bug
### 📊 Change Statistics
- Files changed: 2
- Lines added: +15
- Lines deleted: -8
- Complexity: Low
### ✅ Strengths
- Focused change (single bug fix)
- Test added for regression
- Follows existing validation patterns
- Clear commit message
### ⚠️ Issues Found
No issues found! Code meets all production standards.
### 📝 Recommendation
✅ Approved - Ready to merge after `/precommit` passes
---
🤖 Generated with Claude Code - Elixir Production Plugin
Input:
/pr-review 456
Output:
## Code Review: Add payment processing feature
### 📊 Change Statistics
- Files changed: 12
- Lines added: +847
- Lines deleted: -45
- Complexity: High
### ✅ Strengths
- Comprehensive test coverage (92%)
- Good separation of concerns
- Clear error handling throughout
- Follows project payment patterns
### ⚠️ Issues Found
#### [Critical] Security: Missing input validation (Confidence: 100%)
**File**: `lib/my_app/payments/stripe_client.ex:34`
**Issue**: Amount parameter not validated before Stripe API call
**Risk**: Could pass invalid amounts to Stripe (negative, zero, non-integer)
**Fix**:
```elixir
def charge(amount, currency, metadata) when is_integer(amount) and amount > 0 do
# Validate amount before API call
with :ok <- validate_amount(amount),
{:ok, charge} <- Stripe.Charge.create(%{
amount: amount,
currency: currency,
metadata: metadata
}) do
{:ok, charge}
end
end
defp validate_amount(amount) when is_integer(amount) and amount > 0, do: :ok
defp validate_amount(_), do: {:error, :invalid_amount}
File: lib/my_app/payments.ex:56
Function: process_payment/3 lacks typespec
Add:
@spec process_payment(User.t(), integer(), map()) ::
{:ok, Payment.t()} | {:error, :insufficient_funds | Ecto.Changeset.t()}
File: lib/my_app/payments/balance.ex:23
Issue: Balance check and debit not atomic
Current:
def debit(user_id, amount) do
balance = get_balance(user_id)
if balance >= amount do
update_balance(user_id, balance - amount)
end
end
Problem: Another process could debit between check and update
Fix: Use database transaction with pessimistic locking:
def debit(user_id, amount) do
Repo.transaction(fn ->
user = Repo.get!(User, user_id, lock: "FOR UPDATE")
if user.balance >= amount do
Ecto.Changeset.change(user, balance: user.balance - amount)
|> Repo.update!()
else
Repo.rollback(:insufficient_funds)
end
end)
end
Large change: 847 lines across 12 files
Findings:
Shallow modules detected:
PaymentProcessor (depth ratio: 0.9)
High working memory load:
process_complex_payment/7: 7 parameters, 4-level nesting
Temporal coupling:
initialize_payment/1 functionOverall assessment: Good architecture with some complexity hot spots. Addressing recommendations would improve maintainability.
None detected.
Critical (Must fix before merge):
process_payment/3Important (Should address): 4. Refactor PaymentProcessor to deep module pattern 5. Add context struct to reduce parameter count 6. Consolidate payment initialization
Optional (Nice to have): 7. Add property-based tests for amount validation 8. Consider extracting PaymentValidator module
/precommit to verify all checks pass🤖 Generated with Claude Code - Elixir Production Plugin
### Example 3: SPIKE Code Detected
**Output**:
```markdown
## Code Review: Add dashboard feature
### 🚀 SPIKE Code Detected
**File**: `lib/my_app_web/live/dashboard_live.ex`
**Status**: Ready for migration
**SPIKE markers found**:
- `# SPIKE: Rapid prototyping for user validation`
- Missing typespecs (12 functions)
- Minimal error handling
- 2 smoke tests only
**Assessment**:
- Stable for 3 weeks
- Patterns clear and validated with users
- Performance acceptable for 100 users
**Migration readiness**: 🟡 Medium
**Estimated migration effort**: ~4 hours
- Add typespecs: 1 hour
- Add error handling: 1.5 hours
- Comprehensive tests: 1.5 hours
**Next step**: `/spike-migrate lib/my_app_web/live/dashboard_live.ex`
### ⚠️ Other Issues
[Continue with other findings...]
Automatic trigger for large PRs:
Detected large PR: 8 files, 452 lines changed
Launching cognitive-scientist agent in parallel with code review...
Both analyses will be integrated into the final review.
Cognitive analysis includes:
Based on .claude/elixir-production.local.md:
Review strictness:
Cognitive threshold:
--skip-cognitive flag90-100% (Critical):
80-89% (Important):
< 80% (Not reported):
# View PR
gh pr view <number>
gh pr view <number> --json title,body,author,files,additions,deletions
# Get diff
gh pr diff <number>
# List changed files
gh pr view <number> --json files --jq '.files[].path'
# Post comment
gh pr comment <number> --body "review text"
# Post review (approve/request changes)
gh pr review <number> --comment --body "review text"
gh pr review <number> --approve --body "LGTM!"
gh pr review <number> --request-changes --body "Please address..."
# Check CI status
gh pr checks <number>
# List PRs
gh pr list --state open --limit 10
Standard workflow:
/pr-review <number>/pr-review <number> if neededTeam integration:
# In CI/CD pipeline
- name: Claude Code Review
run: claude pr-review ${{ github.event.pull_request.number }}
# Or as GitHub Action
- uses: anthropic/claude-code-review@v1
with:
pr-number: ${{ github.event.pull_request.number }}
/review - Local code review (before PR)/precommit - Run quality checks/cognitive-audit - Deep complexity analysis/spike-migrate - Upgrade SPIKE code found in PRReview succeeds when:
Error: gh command not found:
# Install gh CLI
brew install gh # macOS
apt install gh # Linux
Error: gh authentication required:
gh auth login
Error: PR not found:
Error: Cannot post comment: