Skip to content

Commit d3112b3

Browse files
committed
ci: add Claude Code multi-agent PR review workflow
Automated code review on PR open using 5 parallel Opus agents (code quality, security, testing, language patterns, architecture). Uses pull_request_target for fork PR support, checks out cloud/ and claude/ for cross-repo context, and supports /review comment for re-review.
1 parent dd85eb3 commit d3112b3

1 file changed

Lines changed: 171 additions & 0 deletions

File tree

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
name: Claude Code Review
2+
3+
on:
4+
# Automatic review only on PR opened (no synchronize — author drives re-review)
5+
# Using pull_request_target because shellhub is public (fork PRs need secrets)
6+
pull_request_target:
7+
types: [opened]
8+
branches: [master]
9+
10+
# Manual review via /review command in comments
11+
issue_comment:
12+
types: [created]
13+
pull_request_review_comment:
14+
types: [created]
15+
pull_request_review:
16+
types: [submitted]
17+
18+
concurrency:
19+
group: claude-review-${{ github.event.pull_request.number || github.event.issue.number }}
20+
cancel-in-progress: true
21+
22+
jobs:
23+
review:
24+
name: Claude Code Review
25+
if: |
26+
(github.event_name == 'pull_request_target' && !github.event.pull_request.draft) ||
27+
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '/review')) ||
28+
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/review')) ||
29+
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '/review'))
30+
31+
runs-on: ubuntu-latest
32+
permissions:
33+
contents: read
34+
pull-requests: write
35+
issues: write
36+
37+
steps:
38+
# Checkout shellhub at workspace root (claude-code-action needs .git here)
39+
- name: Checkout shellhub (PR branch)
40+
uses: actions/checkout@v6
41+
with:
42+
ref: ${{ github.event.pull_request.head.sha }}
43+
44+
- name: Generate cross-repo token
45+
id: app-token
46+
uses: actions/create-github-app-token@v1
47+
with:
48+
app-id: ${{ secrets.CLOUD_DISPATCH_APP_ID }}
49+
private-key: ${{ secrets.CLOUD_DISPATCH_APP_PRIVATE_KEY }}
50+
owner: shellhub-io
51+
repositories: cloud,claude
52+
53+
- name: Determine cloud branch
54+
id: cloud-branch
55+
run: |
56+
BRANCH="${{ github.head_ref || github.ref_name }}"
57+
if git ls-remote --exit-code --heads \
58+
https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/shellhub-io/cloud.git \
59+
"$BRANCH" > /dev/null 2>&1; then
60+
echo "ref=$BRANCH" >> "$GITHUB_OUTPUT"
61+
else
62+
echo "ref=master" >> "$GITHUB_OUTPUT"
63+
fi
64+
65+
- name: Checkout cloud (context)
66+
uses: actions/checkout@v6
67+
with:
68+
repository: shellhub-io/cloud
69+
token: ${{ steps.app-token.outputs.token }}
70+
ref: ${{ steps.cloud-branch.outputs.ref }}
71+
fetch-depth: 1
72+
path: cloud
73+
74+
- name: Checkout claude config
75+
uses: actions/checkout@v6
76+
with:
77+
repository: shellhub-io/claude
78+
token: ${{ steps.app-token.outputs.token }}
79+
fetch-depth: 1
80+
path: claude
81+
82+
- name: Setup workspace context
83+
run: |
84+
# Link CLAUDE.md and .claude/ from claude repo into shellhub checkout
85+
ln -sf "$GITHUB_WORKSPACE/claude/.claude" "$GITHUB_WORKSPACE/.claude"
86+
ln -sf "$GITHUB_WORKSPACE/claude/shellhub/CLAUDE.md" "$GITHUB_WORKSPACE/CLAUDE.md"
87+
88+
- name: Run Claude Code Review
89+
uses: anthropics/claude-code-action@v1
90+
with:
91+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
92+
github_token: ${{ secrets.GITHUB_TOKEN }}
93+
94+
settings: |
95+
{
96+
"env": {
97+
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
98+
}
99+
}
100+
prompt: |
101+
You are the lead reviewer for PR #${{ github.event.pull_request.number || github.event.issue.number }}
102+
in shellhub-io/shellhub (Community Edition).
103+
104+
The cloud/ (enterprise) repo is checked out at $GITHUB_WORKSPACE/cloud/ for context.
105+
Focus the review on the shellhub diff. Use cloud/ only to understand cross-repo impact.
106+
107+
## Step 1: Gather context
108+
109+
1. Get the PR diff:
110+
gh pr diff ${{ github.event.pull_request.number || github.event.issue.number }}
111+
2. Get the list of changed files:
112+
gh pr view ${{ github.event.pull_request.number || github.event.issue.number }} --json files
113+
3. Fetch ALL existing review comments to avoid duplicating feedback:
114+
gh api repos/shellhub-io/shellhub/pulls/${{ github.event.pull_request.number || github.event.issue.number }}/comments
115+
gh api repos/shellhub-io/shellhub/pulls/${{ github.event.pull_request.number || github.event.issue.number }}/reviews
116+
117+
## Step 2: Spawn 5 reviewer agents IN PARALLEL
118+
119+
Launch exactly 5 Task agents in a SINGLE message (so they run in parallel).
120+
Each agent MUST use model: "opus". Each agent gets:
121+
- The PR diff (pass it in the prompt)
122+
- The list of changed files
123+
- Read access to the full codebase (current directory for shellhub, $GITHUB_WORKSPACE/cloud/ for cloud)
124+
125+
Agent assignments:
126+
1. **Code Quality**: Project conventions (CLAUDE.md), dead code, single responsibility, error handling, commit hygiene
127+
2. **Security**: OWASP Top 10 (injection, XSS, CSRF, SSRF), hardcoded secrets, crypto/rand usage, access control, input validation
128+
3. **Testing**: Missing tests for new/changed behavior, edge cases, test determinism, untested error paths
129+
4. **Go/TypeScript Patterns**: Error wrapping (%w), goroutine leaks, context propagation, minimal interfaces, React patterns (no `any`, no unnecessary re-renders, Zustand)
130+
5. **Architecture & Cross-repo**: If PR changes pkg/, check $GITHUB_WORKSPACE/cloud/ for impact. API contract changes, interface compatibility, breaking changes.
131+
132+
Each agent must return findings as a structured list:
133+
- file_path: exact path relative to repo root
134+
- line_start and line_end: exact line numbers in the NEW file
135+
- severity: critical | high | medium | low
136+
- description: what's wrong and why
137+
- suggestion: corrected code (if applicable), or empty string
138+
139+
Agents must NOT post any GitHub comments. They only return findings.
140+
141+
## Step 3: Aggregate and deduplicate
142+
143+
After all 5 agents complete, collect their findings. Then:
144+
1. Remove duplicate findings (same file + same line range + same issue)
145+
2. If the same pattern repeats across multiple locations, keep only the first occurrence and note "Same issue also at: file:line, file:line, ..."
146+
3. Compare against the existing review comments fetched in Step 1. Skip any finding already reported in a previous review thread on the same file and line.
147+
148+
## Step 4: Post inline comments
149+
150+
For each remaining finding, post an inline comment using
151+
mcp__github_inline_comment__create_inline_comment on the specific file and line.
152+
153+
When a fix is available, include a GitHub suggestion block:
154+
```suggestion
155+
corrected code here
156+
```
157+
158+
Do NOT re-report issues that already exist in previous review threads.
159+
160+
## Step 5: Post closing comment
161+
162+
After all inline comments are posted, post ONE comment on the PR using `gh pr comment`:
163+
- Briefly summarize what was reviewed and how many findings were posted
164+
- State: "I've provided feedback and suggestions as inline comments on the code.
165+
When you've addressed the feedback and believe the PR is ready for a new review,
166+
comment `/review` to request a new review iteration."
167+
168+
claude_args: |
169+
--max-turns 30
170+
--model claude-opus-4-6
171+
--allowedTools "mcp__github_inline_comment__create_inline_comment"

0 commit comments

Comments
 (0)