name: Claude Code Review on: pull_request: types: [opened, synchronize] # Optional: Only run on specific file changes # paths: # - "src/**/*.ts" # - "src/**/*.tsx" # - "src/**/*.js" # - "src/**/*.jsx" jobs: claude-review: # Optional: Filter by PR author # if: | # github.event.pull_request.user.login == 'external-contributor' || # github.event.pull_request.user.login == 'new-developer' || # github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' runs-on: blacksmith-8vcpu-ubuntu-2204 permissions: contents: write pull-requests: write issues: write id-token: write steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 # Full history for better context - name: Check if already reviewed id: check-review uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | // Check if Claude has already reviewed this commit const currentSha = context.payload.pull_request.head.sha; // Get all comments on the PR const comments = await github.rest.issues.listComments({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, per_page: 100 }); // Check if Claude has already reviewed this specific commit const alreadyReviewed = comments.data.some(comment => comment.user.login === 'claude[bot]' && comment.body.includes(currentSha) ); if (alreadyReviewed) { core.info(`Claude has already reviewed commit ${currentSha}`); core.setOutput('skip', 'true'); } else { core.info(`No Claude review found for commit ${currentSha}`); core.setOutput('skip', 'false'); } - name: Run Claude Code Review if: steps.check-review.outputs.skip != 'true' id: claude-review uses: anthropics/claude-code-action@beta with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} # Use Claude Opus 4 for more thorough reviews model: "claude-opus-4-20250514" # Direct prompt for automated review with detailed instructions direct_prompt: | Please provide a comprehensive code review for this pull request. Structure your review as follows: ## 📋 Summary Brief overview of the changes and their purpose. ## ✅ Positive Aspects What's done well in this PR. ## 🔍 Areas for Improvement ### Code Quality - Naming conventions, code organization, readability - Adherence to project patterns and best practices - DRY principle violations or code duplication ### Potential Issues - Bugs or logic errors - Edge cases not handled - Error handling gaps ### Performance - Inefficient algorithms or data structures - Unnecessary re-renders (for UI components) - Resource leaks or memory issues ### Security - Input validation issues - Authentication/authorization concerns - Potential vulnerabilities ### Testing - Missing test coverage - Test quality and completeness - Edge cases that should be tested ## 💡 Suggestions Specific, actionable improvements with code examples where helpful. ## 🎯 Priority Items List the most important items that should be addressed before merging. --- *Reviewed commit: ${{ github.event.pull_request.head.sha }}* *Files changed: ${{ github.event.pull_request.changed_files }}* # Enhanced tool access for better analysis allowed_tools: | Bash(pnpm install) Bash(pnpm run build) Bash(pnpm run test) Bash(pnpm run test:*) Bash(pnpm run lint) Bash(pnpm run lint:*) Bash(pnpm run typecheck) Bash(pnpm run format) Bash(pnpm run format:check) Glob Grep Read # Environment variables for Claude's context claude_env: | PR_NUMBER: ${{ github.event.pull_request.number }} PR_TITLE: ${{ github.event.pull_request.title }} PR_AUTHOR: ${{ github.event.pull_request.user.login }} BASE_BRANCH: ${{ github.event.pull_request.base.ref }} HEAD_BRANCH: ${{ github.event.pull_request.head.ref }} CHANGED_FILES: ${{ github.event.pull_request.changed_files }} ADDITIONS: ${{ github.event.pull_request.additions }} DELETIONS: ${{ github.event.pull_request.deletions }} # Optional: Post a summary comment if Claude's review is very long - name: Create summary if needed if: steps.check-review.outputs.skip != 'true' && always() uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | // Wait a bit for Claude's comment to appear await new Promise(resolve => setTimeout(resolve, 5000)); // Find Claude's latest comment const comments = await github.rest.issues.listComments({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, per_page: 10, sort: 'created', direction: 'desc' }); const claudeComment = comments.data.find(c => c.user.login === 'claude[bot]'); if (claudeComment && claudeComment.body.length > 10000) { // If the review is very long, add a summary at the top const summary = `## 📊 Review Summary\n\n**Review length**: ${claudeComment.body.length} characters\n**Commit**: ${context.payload.pull_request.head.sha.substring(0, 7)}\n\n> 💡 Tip: Use the table of contents below to navigate this review.\n\n---\n\n`; await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: claudeComment.id, body: summary + claudeComment.body }); }