Skip to content

Commit 521b2b4

Browse files
committed
[ci] feat: add @claude PR review workflow via claude-code-action
Add a comment-triggered workflow that runs Claude Code as a PR review agent, using the upstream anthropics/claude-code-action@v1. How it works: - Trigger: comments matching '@claude' on issues, PRs, PR reviews, and PR review comments. Default phrase per upstream action. - Authorization gate: only OWNER / MEMBER / COLLABORATOR commenters can fire the action, with a self-author bypass for the original PR/issue author. Without this gate, drive-by commenters on a public repo could trigger paid agent runs and execute tools on the self-hosted runner. - Permissions: contents: read (agent reads files only), pull-requests: write + issues: write (agent posts review comments), id-token: write (action's OIDC token request), actions: read. - Routing: env.ANTHROPIC_BASE_URL routes Claude API traffic through the internal gateway. Verified end to end via the Claude Code CLI; the gateway supports tool use + streaming. - Model: 'Claude Sonnet 4.6' — the gateway exposes Claude models with display-name IDs (verified via GET /v1/models). The canonical hyphenated form is rejected as 'no available channel'. - Tools: --allowedTools enables the inline review-comment MCP tool plus the gh / Read / Grep / Glob tools the agent needs to inspect the diff and modified files. - Behavior: prompt is intentionally empty so the action runs in its default agent mode (PR context + GitHub MCP tools auto-injected). Project-wide review guidance lives in CLAUDE.md and skills/code-review/SKILL.md, which the agent loads automatically. - Progress: track_progress: true shows live checkbox progress in the bot's initial PR comment. End-to-end verified on a fork PR: the agent posts severity-tagged inline comments on file:line plus a top-level verdict / summary / checklist, matching the SKILL.md contract.
1 parent 9324ffa commit 521b2b4

1 file changed

Lines changed: 96 additions & 0 deletions

File tree

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
name: Claude Code
2+
3+
on:
4+
issue_comment:
5+
types: [created]
6+
pull_request_review_comment:
7+
types: [created]
8+
pull_request_review:
9+
types: [submitted]
10+
issues:
11+
types: [opened, assigned]
12+
13+
permissions:
14+
contents: read
15+
pull-requests: write
16+
issues: write
17+
actions: read
18+
id-token: write
19+
20+
jobs:
21+
claude:
22+
# Run only when @claude is mentioned AND the commenter is a trusted
23+
# actor on the repo (or the PR/issue author themselves). Without this
24+
# gate, anyone on the public internet who can comment on the repo
25+
# (e.g. a fork-PR contributor) could trigger paid agent runs and
26+
# execute tools on the self-hosted runner.
27+
if: >-
28+
(
29+
github.event_name == 'issue_comment' &&
30+
contains(github.event.comment.body, '@claude') &&
31+
(
32+
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association) ||
33+
github.event.comment.user.login == github.event.issue.user.login
34+
)
35+
) ||
36+
(
37+
github.event_name == 'pull_request_review_comment' &&
38+
contains(github.event.comment.body, '@claude') &&
39+
(
40+
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association) ||
41+
github.event.comment.user.login == github.event.pull_request.user.login
42+
)
43+
) ||
44+
(
45+
github.event_name == 'pull_request_review' &&
46+
contains(github.event.review.body, '@claude') &&
47+
(
48+
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.review.author_association) ||
49+
github.event.review.user.login == github.event.pull_request.user.login
50+
)
51+
) ||
52+
(
53+
github.event_name == 'issues' &&
54+
(contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')) &&
55+
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.issue.author_association)
56+
)
57+
runs-on: [self-hosted, macOS, ARM64]
58+
timeout-minutes: 30
59+
steps:
60+
- name: Checkout
61+
uses: actions/checkout@v4
62+
with:
63+
fetch-depth: 0
64+
65+
- name: Claude Code Action Official
66+
uses: anthropics/claude-code-action@v1
67+
env:
68+
# Route Claude API traffic through the internal proxy.
69+
ANTHROPIC_BASE_URL: ${{ secrets.ANTHROPIC_BASE_URL }}
70+
with:
71+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
72+
# track_progress shows a live checkbox list in the bot's
73+
# initial PR comment as the agent works.
74+
track_progress: true
75+
# Default trigger phrase is @claude.
76+
# claude_args:
77+
# - Model ID matches what the internal gateway exposes via
78+
# /v1/models (display-name form with spaces, not the
79+
# canonical Anthropic ID).
80+
# - --allowedTools explicitly enables the inline review-comment
81+
# MCP tool (not in the default allow-list) plus the gh
82+
# subcommands and read-only filesystem tools the agent needs
83+
# to actually inspect the diff and modified files.
84+
claude_args: |
85+
--model "Claude Sonnet 4.6"
86+
--max-turns 20
87+
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Read,Grep,Glob"
88+
# NOTE: do NOT set `prompt:` here. Setting it puts the action in
89+
# custom-automation mode, which overrides the user's @claude
90+
# comment and skips the GitHub MCP tool injection — meaning the
91+
# agent has no way to post a review back. With `prompt:` empty,
92+
# the action's default agent mode injects PR context + GitHub
93+
# tools, and the user's @claude comment becomes the agent input.
94+
# Project-wide instructions (e.g. "use skills/code-review/SKILL.md
95+
# when reviewing") belong in CLAUDE.md, which the agent loads
96+
# automatically.

0 commit comments

Comments
 (0)