Skip to content

Instantly share code, notes, and snippets.

@wildcard
Last active July 17, 2025 05:34
Show Gist options
  • Save wildcard/545ab6f8677b519eaa1c9fd163456e40 to your computer and use it in GitHub Desktop.
Save wildcard/545ab6f8677b519eaa1c9fd163456e40 to your computer and use it in GitHub Desktop.
Oh My Zsh custom plugin: review_pr - GitHub PR review tool using Claude

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

This is a zsh plugin called review_pr that automates GitHub Pull Request reviews using Claude AI. The plugin creates an intelligent workflow for fetching, caching, and reviewing PRs with detailed analysis.

Core Architecture

Main Functions

  • review_pr() - Primary function that orchestrates the entire PR review process
  • review_pr_last() - Utility to view the most recent review for a specific PR

Key Components

URL Parsing & Validation (lines 6-20):

  • Validates GitHub PR URL format: https://github.com/owner/repo/pull/number
  • Extracts owner, repo, and PR number using bash parameter expansion

Repository Caching System (lines 23-41):

  • Smart caching at $HOME/.cache/review_pr/repos/owner/repo
  • Automatic daily updates using cross-platform stat commands
  • Fallback clone if cache doesn't exist

Git Worktree Management (lines 54-58):

  • Creates isolated worktrees for each PR: _pr-{number}-{sha}
  • Uses detached HEAD checkout for clean isolation
  • Automatic cleanup unless DEBUG_REVIEW_PR is set

Claude Integration (lines 68-75):

  • Calls Claude CLI with structured prompt for PR analysis
  • Uses --add-dir . to include full codebase context
  • Saves reviews with timestamped filenames

Output Management (lines 83-87):

  • Prefers bat for syntax highlighting, falls back to less
  • Always uses --paging=always and --style=plain for bat

Development Commands

Testing Plugin

# Test plugin loading
zsh -c "source ~/.oh-my-zsh/custom/plugins/review_pr/review_pr.plugin.zsh && review_pr"

Debug Mode

export DEBUG_REVIEW_PR=1
review_pr https://github.com/owner/repo/pull/123
# Worktree preserved at: ~/.cache/review_pr/repos/owner/repo/_pr-123-sha

Versioning with GitHub Gist

# Update gist with changes
gh gist edit 545ab6f8677b519eaa1c9fd163456e40 -f ~/.oh-my-zsh/custom/plugins/review_pr/review_pr.plugin.zsh

# View gist history
gh gist view 545ab6f8677b519eaa1c9fd163456e40 --web

File Structure

~/.cache/review_pr/
├── repos/owner/repo/           # Git repository cache
│   └── _pr-123-abc123/         # Temporary worktrees (debug mode only)
└── reviews/owner/repo/123/     # Review output files
    └── 123-abc123-20240101-120000.md

Dependencies

Required:

  • gh (GitHub CLI) - PR metadata and authentication
  • claude (Claude CLI) - AI review generation
  • Git with worktree support

Optional:

  • bat - Enhanced output formatting

Environment Variables

  • DEBUG_REVIEW_PR - Preserves worktrees for debugging
  • REVIEW_CACHE - Custom cache location (default: $HOME/.cache/review_pr)

Error Handling Patterns

The plugin uses consistent error handling:

  • Early validation with descriptive error messages
  • || { echo "❌ Error"; return 1; } pattern for critical failures
  • Cross-platform compatibility (macOS/Linux stat commands)

Claude Prompt Structure

The Claude review prompt (lines 69-74) requests:

  • PR title and description
  • File-by-file code analysis
  • Existing reviewer comments
  • Risk assessment and open questions
  • Explicit acknowledgment of missing context

Common Troubleshooting

Authentication Issues:

gh auth status
gh auth refresh

Cache Management:

# Clear repository cache
rm -rf ~/.cache/review_pr/repos

# Clear old worktrees
find ~/.cache/review_pr -type d -name "_pr-*" -exec rm -rf {} +

Empty Reviews:

  • Check Claude CLI authentication
  • Verify repository accessibility
  • Check for API rate limiting
review_pr() {
local pr_url="$1"
local DEBUG_REVIEW_PR="$DEBUG_REVIEW_PR"
local REVIEW_CACHE="$HOME/.cache/review_pr"
if [[ -z "$pr_url" || "$pr_url" != https://github.com/*/pull/* ]]; then
echo "❗ Usage: review_pr https://github.com/OWNER/REPO/pull/123"
return 1
fi
# Parse URL components
local url_base="${pr_url#https://github.com/}"
local owner_repo="${url_base%%/pull/*}"
local owner="${owner_repo%%/*}"
local repo="${owner_repo#*/}"
local pr_number="${url_base##*/}"
local repo_url="https://github.com/$owner/$repo.git"
local repo_cache="$REVIEW_CACHE/repos/$owner/$repo"
local review_dir="$REVIEW_CACHE/reviews/$owner/$repo/$pr_number"
mkdir -p "$repo_cache" "$review_dir"
# Use or update cached repo
if [[ -d "$repo_cache/.git" ]]; then
# Cross-platform stat
if stat -f %m "$repo_cache/.git" &>/dev/null; then
local mod_time=$(stat -f %m "$repo_cache/.git")
else
local mod_time=$(stat -c %Y "$repo_cache/.git")
fi
local age=$(( $(date +%s) - mod_time ))
if (( age > 86400 )); then
echo "🔄 Updating cached repo..."
(cd "$repo_cache" && git fetch --prune)
else
echo "♻️ Using cached repo."
fi
else
echo "📦 Cloning $repo_url into cache..."
gh repo clone "$owner/$repo" "$repo_cache" || { echo "❌ Clone failed"; return 1; }
fi
cd "$repo_cache" || return 1
# Get SHA from PR
echo "🔎 Fetching latest commit from PR #$pr_number"
local sha
sha=$(gh pr view "$pr_url" --json headRefOid -q '.headRefOid') \
|| { echo "❌ Failed to get PR SHA"; return 1; }
echo "✅ Latest commit: $sha"
# Checkout SHA into worktree
local worktree="$repo_cache/_pr-$pr_number-$sha"
if [[ ! -d "$worktree" ]]; then
git worktree add --detach "$worktree" "$sha" || {
echo "❌ Failed to create worktree"
return 1
}
fi
# Prepare output file
local timestamp=$(date +"%Y%m%d-%H%M%S")
local session_id="$pr_number-$sha-$timestamp"
local output_file="$review_dir/$session_id.md"
# Fetch PR details for context
echo "📋 Fetching PR details..."
local pr_details
pr_details=$(gh pr view "$pr_url" --json title,body,author,reviewRequests,reviews,labels,assignees,comments --template '
PR Title: {{.title}}
Author: {{.author.login}}
{{if .assignees}}Assignees: {{range .assignees}}{{.login}} {{end}}{{end}}
{{if .labels}}Labels: {{range .labels}}{{.name}} {{end}}{{end}}
{{if .reviewRequests}}Review Requests: {{range .reviewRequests}}{{.login}} {{end}}{{end}}
Description:
{{.body}}
{{if .reviews}}Recent Reviews:
{{range .reviews}}- {{.author.login}} ({{.state}}): {{.body}}
{{end}}{{end}}
{{if .comments}}Recent Comments:
{{range .comments}}- {{.author.login}}: {{.body}}
{{end}}{{end}}
') 2>/dev/null || echo "⚠️ Could not fetch PR details"
# Get diff information
echo "📊 Fetching PR diff..."
local pr_diff
pr_diff=$(gh pr diff "$pr_url" 2>/dev/null) || echo "⚠️ Could not fetch PR diff"
# Run Claude with comprehensive context
echo "🤖 Running Claude review..."
cd "$worktree" || return 1
# Create the prompt
local claude_prompt="Review this GitHub PR #$pr_number in $owner/$repo.
PR CONTEXT:
$pr_details
DIFF SUMMARY:
$pr_diff
Please provide a comprehensive review including:
- Analysis of the code changes (file by file)
- Assessment of code quality, security, and best practices
- Review of test coverage and documentation
- Identification of potential risks or issues
- Suggestions for improvements
- Summary of existing reviewer feedback
- Any questions or concerns for the author
Focus on being thorough and constructive."
# Run Claude (simplified first to test)
echo "$claude_prompt" | claude --add-dir . --output-format text \
--allowedTools "Read,Grep,Glob,LS,Task" > "$output_file"
# Validate output
if [[ ! -s "$output_file" ]]; then
echo "⚠️ Claude returned no content. Review file is empty."
else
echo "✅ Review saved to: $output_file"
echo -e "\n📘 Showing review:\n"
if command -v bat &>/dev/null; then
bat --paging=always --style=plain "$output_file"
else
less "$output_file"
fi
fi
# Cleanup
if [[ -z "$DEBUG_REVIEW_PR" ]]; then
cd "$repo_cache" && git worktree remove --force "$worktree"
else
echo "🛠️ Debug mode: keeping worktree at $worktree"
fi
}
review_pr_last() {
local owner="$1"
local repo="$2"
local pr="$3"
local dir="$HOME/.cache/review_pr/reviews/$owner/$repo/$pr"
local latest=$(ls -t "$dir"/*.md 2>/dev/null | head -n1)
if [[ -z "$latest" ]]; then
echo "❌ No review found for $owner/$repo PR #$pr"
return 1
fi
echo "📘 Latest review:"
if command -v bat &>/dev/null; then
bat --paging=always --style=plain "$latest"
else
less "$latest"
fi
}

review_pr Plugin

A zsh plugin for reviewing GitHub Pull Requests using Claude AI.

Features

  • Smart Caching: Efficiently caches repositories and avoids unnecessary re-clones
  • PR Review: Automatically fetches PR details and generates comprehensive reviews
  • Worktree Management: Uses Git worktrees for isolated PR checkouts
  • Review History: Saves all reviews with timestamps for future reference
  • Clean Output: Supports bat for syntax highlighting or falls back to less

Prerequisites

  • GitHub CLI (gh) - for PR API access
  • Claude CLI - for AI-powered reviews
  • Git with worktree support
  • Optional: bat for enhanced output formatting

Installation

From GIST (Recommended)

# Create plugin directory
mkdir -p ~/.oh-my-zsh/custom/plugins/review_pr

# Download from GIST
curl -o ~/.oh-my-zsh/custom/plugins/review_pr/review_pr.plugin.zsh \
  https://gist.githubusercontent.com/wildcard/545ab6f8677b519eaa1c9fd163456e40/raw/review_pr.plugin.zsh

# Add to .zshrc plugins array
plugins=(... review_pr)

# Reload shell
source ~/.zshrc

Manual Installation

  1. Copy review_pr.plugin.zsh to ~/.oh-my-zsh/custom/plugins/review_pr/
  2. Add review_pr to your plugins in ~/.zshrc
  3. Restart your shell

Usage

Basic PR Review

review_pr https://github.com/owner/repo/pull/123

View Previous Review

review_pr_last owner repo 123

Functions

review_pr <pr_url>

Main function that reviews a GitHub PR.

Parameters:

  • pr_url: Full GitHub PR URL (e.g., https://github.com/owner/repo/pull/123)

Process:

  1. Validates PR URL format
  2. Parses owner, repo, and PR number
  3. Manages repository cache (clones or updates as needed)
  4. Fetches latest commit SHA from PR
  5. Creates isolated worktree for the PR
  6. Runs Claude review with comprehensive prompt
  7. Saves review to timestamped file
  8. Displays review with syntax highlighting
  9. Cleans up worktree (unless debug mode)

Example:

review_pr https://github.com/microsoft/vscode/pull/12345

review_pr_last <owner> <repo> <pr_number>

Displays the most recent review for a specific PR.

Parameters:

  • owner: GitHub repository owner
  • repo: Repository name
  • pr_number: PR number

Example:

review_pr_last microsoft vscode 12345

Configuration

Environment Variables

  • DEBUG_REVIEW_PR: Set to any value to enable debug mode (keeps worktrees)
  • REVIEW_CACHE: Custom cache location (default: $HOME/.cache/review_pr)

Examples:

# Enable debug mode
export DEBUG_REVIEW_PR=1
review_pr https://github.com/owner/repo/pull/123

# Custom cache location
export REVIEW_CACHE="/tmp/pr_reviews"
review_pr https://github.com/owner/repo/pull/123

File Structure

The plugin creates the following directory structure:

$HOME/.cache/review_pr/
├── repos/                     # Cached repositories
│   └── owner/
│       └── repo/              # Git repository
├── reviews/                   # Review outputs
│   └── owner/
│       └── repo/
│           └── pr_number/
│               └── 123-abc123-20240101-120000.md

Review Output Format

Each review includes:

  • PR Metadata: Title, description, author
  • File-by-file Analysis: Changes, concerns, suggestions
  • Reviewer Comments: Existing feedback from other reviewers
  • Risk Assessment: Potential issues or concerns
  • Questions: Areas needing clarification

Advanced Usage

Batch Review Multiple PRs

# Review multiple PRs in sequence
for pr in 123 124 125; do
  review_pr "https://github.com/owner/repo/pull/$pr"
done

Custom Review Prompts

Modify the Claude prompt in the plugin file to customize review focus:

# Edit plugin file
nano ~/.oh-my-zsh/custom/plugins/review_pr/review_pr.plugin.zsh

# Find the claude command and modify the prompt
claude -p --add-dir . --output-format text \
  "/review this PR focusing on security vulnerabilities..." \
  > "$output_file"

Integration with Other Tools

# Combine with other review tools
review_pr https://github.com/owner/repo/pull/123
# Then run additional analysis
cd ~/.cache/review_pr/repos/owner/repo
semgrep --config=auto .

Troubleshooting

Common Issues

  1. "Clone failed" error

    • Check internet connection
    • Verify GitHub CLI authentication: gh auth status
    • Ensure repository access permissions
  2. "Failed to get PR SHA" error

    • Verify PR URL is correct and accessible
    • Check GitHub CLI permissions: gh auth refresh
  3. "Failed to create worktree" error

    • Usually indicates the commit SHA doesn't exist
    • Try fetching the PR directly: gh pr checkout <pr_number>
  4. Empty review files

    • Check Claude CLI installation and authentication
    • Verify the repository has readable content
    • Check for rate limiting or API errors

Debug Mode

Enable debug mode to troubleshoot issues:

export DEBUG_REVIEW_PR=1
review_pr https://github.com/owner/repo/pull/123
# Worktree will be preserved at: ~/.cache/review_pr/repos/owner/repo/_pr-123-sha

Cache Management

# Clear old caches
find ~/.cache/review_pr -type d -name "_pr-*" -exec rm -rf {} +

# Clear repository cache (forces fresh clones)
rm -rf ~/.cache/review_pr/repos

# Clear review history
rm -rf ~/.cache/review_pr/reviews

Performance Tips

  • Repository caches are automatically updated daily
  • Use debug mode sparingly to avoid disk space issues
  • Consider setting custom REVIEW_CACHE on SSDs for faster access
  • Reviews are cached permanently - periodically clean old reviews

Contributing

This plugin is versioned using GitHub Gists. To contribute:

  1. Fork the gist: https://gist.github.com/wildcard/545ab6f8677b519eaa1c9fd163456e40
  2. Make your changes
  3. Submit feedback via GitHub issues or discussions

License

This plugin is provided as-is under MIT license terms.

Zsh Custom Plugins GIST Versioning Guide

Overview

This guide explains how to maintain your custom zsh plugins using GitHub Gists for version control and distribution.

Current Gist: https://gist.github.com/wildcard/545ab6f8677b519eaa1c9fd163456e40

Quick Reference Commands

# View current gist
gh gist view 545ab6f8677b519eaa1c9fd163456e40

# Edit gist directly
gh gist edit 545ab6f8677b519eaa1c9fd163456e40

# Clone gist for local editing
gh gist clone 545ab6f8677b519eaa1c9fd163456e40

# Update gist from local file
gh gist edit 545ab6f8677b519eaa1c9fd163456e40 -f review_pr.plugin.zsh

Workflow for Plugin Updates

Method 1: Direct File Update (Recommended)

  1. Edit your plugin file locally:

    nano ~/.oh-my-zsh/custom/plugins/review_pr/review_pr.plugin.zsh
  2. Update the gist with your changes:

    gh gist edit 545ab6f8677b519eaa1c9fd163456e40 -f ~/.oh-my-zsh/custom/plugins/review_pr/review_pr.plugin.zsh
  3. Add a descriptive commit message when prompted

Method 2: Clone and Push Workflow

  1. Clone the gist to a dedicated directory:

    mkdir ~/gists && cd ~/gists
    gh gist clone 545ab6f8677b519eaa1c9fd163456e40 zsh-plugins
    cd zsh-plugins
  2. Make your changes to the files

  3. Commit and push:

    git add .
    git commit -m "feat: add new functionality to review_pr"
    git push

Version History Management

Viewing History

# See all revisions of the gist
gh gist view 545ab6f8677b519eaa1c9fd163456e40 --web

# View specific revision
gh gist view 545ab6f8677b519eaa1c9fd163456e40 --revision <revision-id>

Branching Strategy

Since gists don't support branches, use descriptive commit messages:

  • feat: for new features
  • fix: for bug fixes
  • docs: for documentation
  • refactor: for code restructuring
  • chore: for maintenance tasks

Adding New Plugins

Single Plugin

# Add a new plugin file to existing gist
gh gist edit 545ab6f8677b519eaa1c9fd163456e40 -a /path/to/new-plugin.plugin.zsh

Multiple Plugins

# Create new gist for multiple plugins
gh gist create ~/.oh-my-zsh/custom/plugins/*/*.plugin.zsh --public --desc "Oh My Zsh custom plugins collection"

Distribution and Installation

For Others to Install Your Plugin

  1. Direct Download:

    # Create plugin directory
    mkdir -p ~/.oh-my-zsh/custom/plugins/review_pr
    
    # Download plugin
    curl -o ~/.oh-my-zsh/custom/plugins/review_pr/review_pr.plugin.zsh \
      https://gist.githubusercontent.com/wildcard/545ab6f8677b519eaa1c9fd163456e40/raw/review_pr.plugin.zsh
  2. Add to .zshrc:

    plugins=(... review_pr)
  3. Reload shell:

    source ~/.zshrc

Auto-Update Script

Create an update script for easy maintenance:

#!/bin/bash
# save as ~/bin/update-zsh-plugins

GIST_ID="545ab6f8677b519eaa1c9fd163456e40"
PLUGIN_DIR="$HOME/.oh-my-zsh/custom/plugins/review_pr"

echo "Updating review_pr plugin..."
curl -s "https://gist.githubusercontent.com/wildcard/$GIST_ID/raw/review_pr.plugin.zsh" \
  -o "$PLUGIN_DIR/review_pr.plugin.zsh"

echo "Plugin updated! Restart your shell or run: source ~/.zshrc"

Best Practices

1. Documentation in Plugin

Always include usage comments at the top of your plugin:

# review_pr plugin
# Author: Your Name
# Version: 1.0.0
# Description: GitHub PR review tool using Claude
# Usage: review_pr https://github.com/owner/repo/pull/123

2. Version Tags

Use semantic versioning in commit messages:

git commit -m "v1.2.0: feat: add support for draft PRs"

3. Backup Strategy

  • Keep local copies of all plugins
  • Export gist URLs to a central document
  • Consider creating a master gist that lists all your plugin gists

4. Testing

Before pushing updates:

# Test plugin loading
zsh -c "source ~/.oh-my-zsh/custom/plugins/review_pr/review_pr.plugin.zsh && review_pr"

Troubleshooting

Gist Not Updating

# Force refresh
gh auth refresh
gh gist edit 545ab6f8677b519eaa1c9fd163456e40 -f ~/.oh-my-zsh/custom/plugins/review_pr/review_pr.plugin.zsh

Large Files

Gists have a 10MB limit per file. For larger plugins:

  1. Split into multiple files
  2. Use a GitHub repository instead
  3. Remove unnecessary comments/debugging code

Lost Gist ID

# List all your gists
gh gist list

# Search for specific gist
gh gist list | grep "review_pr"

Advanced Usage

Multiple Environments

For different environments (work/personal):

# Create environment-specific gists
gh gist create plugin.zsh --desc "Work plugins"
gh gist create plugin.zsh --desc "Personal plugins"

# Use different update scripts
~/bin/update-work-plugins
~/bin/update-personal-plugins

Collaboration

Share gists with team members:

# Make gist public and share URL
echo "Team plugin: https://gist.github.com/wildcard/545ab6f8677b519eaa1c9fd163456e40"

# Others can star/watch for updates
gh gist view 545ab6f8677b519eaa1c9fd163456e40 --web
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment