| name: Claude Code | |
| on: | |
| issue_comment: | |
| types: [created] | |
| pull_request_review_comment: | |
| types: [created] | |
| issues: | |
| # only "opened" — an issue's author_association gates the summon below; | |
| # "assigned" would gate on the issue author, not the assigner, so a | |
| # maintainer assigning an outsider's issue would be wrongly skipped. | |
| types: [opened] | |
| pull_request_review: | |
| types: [submitted] | |
| jobs: | |
| claude: | |
| # Only trusted actors (repo owner/member/collaborator) may summon @claude, so the | |
| # write-scoped token and OAuth secret are never issued for an outside contributor's | |
| # comment on this public repo. Defense-in-depth on top of the action's own check. | |
| if: | | |
| (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude') && | |
| contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)) || | |
| (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude') && | |
| contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)) || | |
| (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude') && | |
| contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.review.author_association)) || | |
| (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')) && | |
| contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.issue.author_association)) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write # allow Claude to push commits/branches when asked | |
| pull-requests: write # allow Claude to comment on / update PRs | |
| issues: write # allow Claude to comment on / update issues | |
| id-token: write | |
| actions: read # Required for Claude to read CI results on PRs | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 1 | |
| - name: Run Claude Code | |
| id: claude | |
| uses: anthropics/claude-code-action@v1 | |
| with: | |
| claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| # This is an optional setting that allows Claude to read CI results on PRs | |
| additional_permissions: | | |
| actions: read | |
| # Sign the bot's commits so they show as "Verified". The action commits | |
| # automatically — on a PR comment it pushes to that PR's branch; on an | |
| # issue comment it opens a new claude/* branch + PR with the fix. | |
| use_commit_signing: true | |
| # No custom prompt: Claude performs the instructions in the @claude comment. | |
| # Deliberately NO Bash in the tool allowlist. @claude can be summoned on a | |
| # fork PR, and this job holds the OAuth secret + a write token. Any build | |
| # or interpreter command (python -c, cmake/make custom targets, etc.) run | |
| # against attacker-controlled PR content is arbitrary code + network | |
| # execution, so no command allowlist can safely contain it. Claude edits | |
| # files and the action commits/opens the PR; the resulting commit is | |
| # verified by the repo's CircleCI matrix. --max-turns gives room to | |
| # investigate + fix. | |
| claude_args: '--max-turns 30 --model claude-opus-5' |