Claude Code on a laptop helps one developer. Claude Code in GitHub Actions helps the whole team at once: anyone with write access can mention @claude in an issue or a pull request, and Claude Code works on the repository inside a workflow run, then answers in the thread.
That reach is also why it needs a little more care than a local setup. This post covers how to set it up, who can trigger it, the two ways it runs, and the settings that keep cost and scope under control.
Setup in one command
The quickest path is to open claude in the repository and run:
/install-github-app
Claude Code installs the Claude GitHub App, adds the authentication secret to the repository, pushes a branch with the workflow files you choose and opens GitHub with a pull request ready to create. Merge that pull request and @claude works in the repository.
Two details from the docs worth knowing before you start:
- The command works only with github.com repositories. GitLab has its own CI/CD integration.
- If you would rather do it by hand, install the app, add an
ANTHROPIC_API_KEYsecret, and copyexamples/claude.ymlfrom theanthropics/claude-code-actionrepository into.github/workflows/. The docs note that this file is a working workflow, not just an example.
A trimmed version of that workflow looks like this:
name: Claude Code
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
jobs:
claude:
if: contains(github.event.comment.body, '@claude')
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
actions: read
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
The if line keeps runners from starting on comments that don't mention @claude.
Two modes: mentions and prompts
The action decides how to run from your workflow file:
-
Interactive mode. With no
promptinput, Claude waits for the trigger phrase,@claudeby default, in a comment, a review or a new issue, and replies in that issue or pull request. Requests look like "@claude fix the TypeError in the user dashboard component." -
Automation mode. With a
promptinput, Claude runs on any GitHub event without waiting for a mention, including a schedule. Results go to the workflow run log unless the prompt tells Claude to post and it has a tool that can.
Start with interactive mode. A human asks, Claude answers in the thread, and a human reviews the result. Automated prompts are useful later for recurring jobs, such as a daily summary of commits and open issues, but they run without anyone asking, so add them once the team trusts the setup.
One detail matters for automated runs: with a plain-text prompt, Claude has no shell or GitHub API access until you grant the tools it needs, through --allowedTools in claude_args or a permissions.allow rule in the settings input. That is a good default. Grant what the job needs and nothing more.
Who can trigger a run
The action checks the triggering actor before Claude starts:
-
Write access. On issue and pull request events, the person who triggered the run must have write access to the repository. A drive-by commenter on a public repository cannot start a run. You can allow specific users without write access with
allowed_non_write_users. -
Human actor. Bots are rejected unless you list them in
allowed_bots, which keeps bots from triggering Claude in a loop.
For most teams the defaults are right. Change them only for a specific, named reason.
The team rules come from CLAUDE.md
In CI there is no developer sitting next to Claude to explain the project's habits. The docs' first best practice is a CLAUDE.md file in the repository root: a Markdown file Claude Code reads at the start of every session, with the code style, review criteria, project rules and preferred patterns. Claude follows it when it opens pull requests and answers requests.
This is where the local setup and the CI setup meet. The same committed file guides a developer's session on their laptop and the @claude run on GitHub, so the answers are consistent wherever the work happens. The docs add one more reason to keep it short: Claude reads it on every run, so a long file costs tokens every time.
Keep cost and scope under control
Each run uses GitHub Actions minutes and API tokens. The docs list the levers:
- Write specific
@clauderequests, so Claude needs fewer turns. - Use issue templates so the context is there up front.
- Keep
CLAUDE.mdconcise. - Set
--max-turnsinclaude_argsto cap how long a run can go on. - Set workflow-level timeouts so a stuck job ends.
- Use GitHub's concurrency controls to limit parallel runs.
A sensible starting point for a team is a turn cap and a timeout on every Claude workflow, so no single request can run far past what the team expects.
Three things that trip teams up
The API key in the wrong place. Never commit an API key or OAuth token. Store it as a GitHub secret and reference it, as in anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}. Grant the workflow only the permissions it needs, and review Claude's changes before merging.
CI not running on Claude's commits. GitHub doesn't start workflows on commits made with the default GITHUB_TOKEN. If your workflow passes github_token: ${{ secrets.GITHUB_TOKEN }} to the action, remove it so the action authenticates as the Claude GitHub App, or pass a custom app token.
Claude not answering. Check that the app is installed, workflows are enabled, the secret is set, the commenter has write access, and the comment says @claude as a whole word, not /claude or @claude-bot.
Where to start
Install it with /install-github-app, keep interactive mode only for the first weeks, add --max-turns and a timeout, and try it on a few small issues: a failing test, a missing validation, a docs fix. Review every pull request it opens like any other.
The quality of those pull requests depends on the CLAUDE.md it reads. AI Workspace Builder generates one from the docs your team already has, along with a profile for each role and an install script, using your own Anthropic API key. No docs yet? Answer a short questionnaire and download a starter CLAUDE.md, no signup needed.
Top comments (1)
"Use GitHub's concurrency controls" is the one lever on that list whose default can drop requests. A concurrency group allows one running and one pending run, and by default a newly queued run cancels the pending one. So if someone posts two follow-up
@claudecomments while the first run is still working, the middle request is cancelled and never gets a reply. What we'd add to the trimmed workflow, on theclaudejob next to itsifso comments without a mention never enter the group:group: claude-${{ github.event.issue.number || github.event.pull_request.number }}so runs only serialize per thread, andqueue: maxso pending runs wait in line instead of replacing each other (cancel-in-progresscan stay at its default of false, andqueue: maxrejectstrueanyway).