# Claude Code GitHub Actions: set up @claude, workflows, secrets and limits

> The Claude Code GitHub Action runs Claude Code inside your repository's workflows. Run `/install-github-app` in Claude Code to install the GitHub App, save the secret and open a pull request with the workflow. After you merge it, mention `@claude` in an issue or pull request comment. Give the workflow a `prompt` instead and it runs on any GitHub event, so scope its permissions, tools and turns.

Mindket editors · Published 2026-11-04 · Updated 2026-11-05 · https://mindket.com/learn/claude-code-advanced/claude-code-github-actions

## In short

- `/install-github-app` installs the app, saves `ANTHROPIC_API_KEY` or `CLAUDE_CODE_OAUTH_TOKEN` as a secret and opens a pull request with the workflow. It needs admin access and a github.com repository.
- No `prompt` input means interactive mode: Claude waits for `@claude`. A `prompt` input means automation mode, which runs on any event you choose.
- Only users with write access can start a run, and bots are rejected unless you list them in `allowed_bots`. Never check out an untrusted pull request head into the workspace root.
- Cost has two parts, Actions minutes and API tokens. Cap them with `--max-turns` in `claude_args`, workflow timeouts and concurrency controls.

## Before you start

You need a github.com repository where you have admin access, Claude Code on your machine and the [GitHub CLI](https://cli.github.com) signed in with `gh auth login`. A GitLab or Bitbucket remote does not work with the quick setup. Several Anthropic products share the Claude Code name, and this lesson covers only the `claude-code-action` workflow integration from [Anthropic's GitHub Actions page](https://code.claude.com/docs/en/github-actions).

The action is built on the Agent SDK, and `claude_args` accepts the same flags as `claude -p` in the [headless lesson](https://mindket.com/learn/claude-code-advanced/claude-code-headless). Security details come from the [repository's own docs](https://github.com/anthropics/claude-code-action/blob/main/docs/security.md). Everything was read on 4 November 2026, and the GitHub Actions page again on 5 November.

The action ships often, so pin `@v1` and let it move. These figures show how widely it is used and how fresh it was when this lesson was checked.

**The claude-code-action repository on GitHub**

- **9.8k** stars on anthropics/claude-code-action (Source: [anthropics/claude-code-action on GitHub](https://github.com/anthropics/claude-code-action), read 2026-11-05)
- **2.2k** forks of the repository (Source: [anthropics/claude-code-action on GitHub](https://github.com/anthropics/claude-code-action), read 2026-11-05)
- **v1.0.268** the newest release, published on 4 November 2026 (Source: [claude-code-action release v1.0.268 on GitHub](https://github.com/anthropics/claude-code-action/releases/tag/v1.0.268), read 2026-11-05)

## Install it and send your first @claude

Quick setup installs the Claude GitHub App and stores your credential as a repository secret. It then proposes the workflow in a pull request. That workflow is the one below, which the manual path copies from the repository's examples folder.

````yaml
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 }}
````

1. Open `claude` in the repository and run `/install-github-app`. Claude Code installs the app first. If it already has an API key it reuses it, otherwise you choose between a long-lived token from your Claude subscription and a pasted API key.
2. Claude Code saves the credential as `ANTHROPIC_API_KEY` for a key or `CLAUDE_CODE_OAUTH_TOKEN` for a subscription token. It then pushes a branch with the workflow files you select, already pointed at that secret, and opens GitHub with a pull request ready to create.
3. Create and merge the pull request. Then comment on an issue with a request, such as `@claude how should I implement user authentication for this endpoint?`. Claude answers in a comment on the same issue and updates it as it works.
4. Without Claude Code locally, or when the command fails, set it up by hand. Install the [Claude GitHub App](https://github.com/apps/claude), add the secret, and copy the workflow into `.github/workflows/`. For a subscription token run `claude setup-token` locally and change the `anthropic_api_key` line to `claude_code_oauth_token`.

## What each part of the workflow is for

Anthropic's page names the lines that are not boilerplate. Most trouble comes from one of them going missing.

- `id-token: write` is required for the default GitHub App authentication. Without it you get OIDC errors, and the permission stays even when you pass your own token for workload identity federation.
- `actions: read` lets Claude read CI results on pull requests. The FAQ adds `additional_permissions: actions: read` on the action step as well.
- `actions/checkout` gives Claude a local copy of the repository. Claude clones shallowly, 20 commits for a pull request and 1 for a new branch, so set the checkout depth yourself when you need full history.
- The `if` keeps runners from starting on comments with no `@claude`. The action also checks the trigger phrase itself before it responds.
- Contents, issues and pull requests get write access because they are the three app permissions the action relies on: Claude edits files, responds to issues and pushes changes.

## Two modes and who can start a run

The action detects its mode from the workflow, and there is no `mode` input. With no `prompt` it runs interactively and waits for the trigger phrase, `@claude` by default, in a comment, a review or the title or body of a new issue. With a `prompt` it runs in automation mode on whatever event your `on:` block names, and the result goes to the run log unless the prompt tells Claude to post it.

A plain-text prompt gets no shell or GitHub API access until you grant tools with `--allowedTools` in `claude_args`, or with a `permissions.allow` rule in the `settings` input. A skill brings the tools its `allowed-tools` frontmatter names. This code review workflow from the page grants one inline comment tool and keeps the token read-only.

````yaml
name: Code Review
on:
  pull_request:
    types: [opened, synchronize, ready_for_review, reopened]
jobs:
  review:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: read
      issues: read
      id-token: write
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 1
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          plugin_marketplaces: "https://github.com/anthropics/claude-plugins-official.git"
          plugins: "code-review@claude-plugins-official"
          prompt: "/code-review:code-review --comment ${{ github.repository }}/pull/${{ github.event.pull_request.number }}"
          claude_args: '--allowedTools "mcp__github_inline_comment__create_inline_comment"'
````

| Actor | Result |
| --- | --- |
| A user with write access | The run starts |
| A user without write access | Rejected. `allowed_non_write_users` lifts the check, and it works only with your own `github_token` |
| A bot or GitHub App | Rejected unless listed in `allowed_bots`. Listed bots skip the permission check |
| A scheduled run | No write check. GitHub credits the user who last changed the cron line, and a bot there must be listed in `allowed_bots` |
| A `workflow_run` started by a fork pull request | The action checks the actor who started the upstream run as well, and stops if that person lacks write access. `allowed_non_write_users` with your own `github_token` is the way around it |

## What Claude can touch, and the checkout trap

The action runs on your runner with a short-lived token from the Claude GitHub App. The token is scoped to the one repository the run works in. Installing the app grants its whole permission set, and GitHub does not let you accept a subset. If your organization wants only contents, issues and pull requests, the docs describe a custom GitHub App with just those three. The repository's security page lists fewer app permissions than the docs table does, so read the install screen.

By default Claude does not open the pull request. Per the security page it pushes its commits to a new branch and leaves a link to the pull request page, so a person decides and branch protection stays in the path. The FAQ says Claude never merges, rebases or force pushes, and that this lives in its system prompt, so it holds even when you allow the git tools.

On a pull request the action first restores a fixed list of Claude files from the base branch: `.claude/`, `.mcp.json`, `.claude.json`, `.gitmodules`, `.ripgreprc`, `CLAUDE.md`, `CLAUDE.local.md` and `.husky/`. The pull request's own copies are kept under `.claude-pr/` for reference. Everything else stays at the head, so a hook that runs `npm run format` still resolves through the PR's `package.json`. Keep hook commands self-contained.

`pull_request_target` and `workflow_run` run with the base repository's secrets. That makes the checkout the dangerous step, and this is the pattern the security page gives when you need the PR files.

> Do not check out an untrusted ref into the workspace root before this action.
>
> Anthropic, claude-code-action repository documentation, [claude-code-action docs: Security](https://github.com/anthropics/claude-code-action/blob/main/docs/security.md) (read 2026-11-04)

````yaml
# If you need the PR's files locally, check out the base ref at the workspace
# root (this action expects a git repo there), then check out the head ref into
# a subdirectory and pass it via --add-dir.
- uses: actions/checkout@v6 # no ref input: base branch at workspace root
- uses: actions/checkout@v6
  with:
    # For workflow_run use: ${{ github.event.workflow_run.head_sha }}
    ref: ${{ github.event.pull_request.head.sha }}
    path: pr-head
- uses: anthropics/claude-code-action@v1
  with:
    claude_args: "--add-dir pr-head"
````

## Untrusted input and the settings that widen it

- Hidden instructions can ride in HTML comments, invisible characters and hidden attributes. The action strips HTML comments, invisible characters, image alt text, hidden attributes and entities, and the docs say new bypasses may appear. Read the raw text before you tag Claude on an outsider's issue. On public repositories `include_comments_by_actor` limits whose comments reach Claude, and exclusion wins when an actor is in both lists.
- `allowed_bots: '*'` on a public repository lets any GitHub App invoke the action with a prompt it controls. Prefer a named list.
- `allowed_non_write_users` is marked risky. It works only with `github_token`, which should be `secrets.GITHUB_TOKEN` and never a personal access token, and the docs suggest limiting tools to the minimum. Claude scrubs secrets from subprocess environments on a best-effort basis, and `CLAUDE_CODE_SCRIPT_CAPS` limits calls to named scripts.
- `show_full_output` is off by default because it prints every tool result, including `env` and file reads, and public repositories show those logs to everyone. It switches on by itself when Actions debug mode is on.
- The Bash tool is off by default in the action. List commands in `--allowedTools`, such as `Bash(npm:*)`. Two MCP servers, GitHub and file operations, start automatically, and their tools still need `--allowedTools`.
- To keep a static key out of the repository, use workload identity federation. The action trades the workflow's OIDC token for Claude API access through a Console service account, using `anthropic_federation_rule_id` and `anthropic_organization_id`.

## Cost, and how to stop a runaway job

Every run uses GitHub Actions minutes on your runner and API tokens for each interaction. With an OAuth token the tokens come out of your Claude subscription, not API billing. Rates change, so the docs point you to [GitHub's billing page](https://github.com/settings/billing/summary) and [Claude's pricing page](https://claude.com/pricing) and print no figures.

`claude_args` takes any CLI flag, which is how the v1 action carries `--max-turns` and a system prompt addition.

````yaml
- uses: anthropics/claude-code-action@v1
  with:
    anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
    claude_args: |
      --max-turns 10
      --append-system-prompt "Focus on security"
````

- Write specific `@claude` requests and use issue templates, so Claude needs fewer turns.
- Keep CLAUDE.md short, because Claude reads it on every run. The [CLAUDE.md guide](https://mindket.com/blog/claude-md-file) covers what to put in it.
- Set `--max-turns` in `claude_args`, a workflow-level timeout and GitHub's concurrency controls to limit parallel runs.

## Boris Cherny's review habit: tag @claude to update CLAUDE.md

Boris Cherny, who created Claude Code, described a review habit [on X](https://x.com/bcherny/status/2007179842928947333) in tip 5 of a thread. During code review he often tags Claude on a coworker's pull request and asks it to add something to CLAUDE.md as part of that pull request. His team runs this through the GitHub Action, and he calls it their version of Dan Shipper's Compounding Engineering.

His post names the command `/install-github-action`. The command in Anthropic's docs is `/install-github-app`, the one this lesson uses.

To copy the habit, keep the mention workflow above with `contents: write` and `pull-requests: write`, so Claude can commit its CLAUDE.md edit to that same pull request. In review, comment `@claude add a line to CLAUDE.md about` the thing you just caught. The rule lands with the change that taught it. Keep each line short, since Claude reads the file on every run.

> We use the Claude Code Github action (/install-github-action) for this.
>
> Boris Cherny, Creator of Claude Code, at Anthropic, [X](https://x.com/bcherny/status/2007179842928947333) (read 2026-11-05)

[![Boris Cherny (@bcherny) on X, 2 January 2026, tip 5 of his thread. During code review he often tags @.claude on coworkers' PRs to add something to CLAUDE.md as part of the PR, using the Claude Code GitHub action.](https://mindket.com/blog/shots/x-bcherny-tag-claude-on-prs.webp?v=9fe081cc1404)](https://x.com/bcherny/status/2007179842928947333)

Boris Cherny on X, 2 January 2026

> A screenshot of X's own embed of the post, taken on 5 November 2026, with the time in UTC. Select it to open the post on X.

## Common mistakes

- Tagging `@claude` from another workflow. The `github-actions` user cannot trigger further workflows, which prevents loops, so the comment needs a token from a user or an app of your own.
- Passing `github_token: secrets.GITHUB_TOKEN` and wondering why CI skips Claude's commits. GitHub does not run workflows for commits made with that token. Remove the input so the action authenticates as the Claude GitHub App, and note that `allowed_non_write_users` needs your own token.
- A comment that is not the trigger phrase as a whole word. `/claude` and `@claude-bot` do nothing unless you change `trigger_phrase`.
- Leaving a workflow on `@beta`. Change it to `@v1`, drop the `mode` input, rename `direct_prompt` to `prompt` and move `max_turns` and `model` into `claude_args`.
- Debugging the workflow before the credential. Test the API key or OAuth token locally with `claude` first.

## Try it yourself

- In a scratch repository, run `/install-github-app`, merge the pull request and comment `@claude` with a question about one file. Watch the single comment update as the run progresses.
- Comment `/claude` and then `@claude-bot` and confirm that no run starts. Change `trigger_phrase` and try again.
- Copy the review workflow, remove `id-token: write` and read the error in the run log. Put it back.
- Add `claude_args: "--max-turns 3"` to the workflow and give Claude a task that needs more turns. Compare the run with and without the cap.

## Next: build your own agent with the Agent SDK

Anthropic points to the Claude Agent SDK for automation outside GitHub Actions, and the action runs on it too. The last lesson, [build an agent with the Claude Agent SDK](https://mindket.com/learn/claude-code-advanced/claude-agent-sdk), shows the same loop as a library.

The review workflow above already installs a plugin through the `plugins` and `plugin_marketplaces` inputs. The [plugins post](https://mindket.com/blog/claude-code-plugins) covers what a plugin can hold.

## Check yourself

1. A workflow step uses anthropics/claude-code-action@v1 with no prompt input. What does the action do?

   A. Runs on every event with a default review prompt
   B. Waits for the trigger phrase, @claude by default, in a comment or a new issue
   C. Fails, because the prompt input is required

   Answer: B. With no prompt the action runs in interactive mode and responds only when someone uses the trigger phrase.

2. Which job permission does the default GitHub App authentication require?

   A. id-token: write
   B. packages: write
   C. security-events: write

   Answer: A. The default authentication fetches a GitHub OIDC token, so the job must grant id-token: write or the run fails with OIDC errors.

3. Claude pushes commits, but your CI workflow does not start on them. What is the likeliest cause?

   A. GitHub blocks branches that start with claude/
   B. The id-token permission is missing
   C. The step passes the default GITHUB_TOKEN as github_token, and GitHub does not run workflows for commits made with it

   Answer: C. GitHub does not trigger workflows on commits made with the default token, so remove the input and let the action authenticate as the Claude GitHub App.

4. A pull_request_target workflow must give Claude the PR files. What does the security page advise?

   A. Check out the PR head at the workspace root so Claude sees it first
   B. Paste the PR files into the prompt
   C. Turn off the base branch restore
   D. Check out the base ref at the root and the head into a subdirectory passed with --add-dir

   Answer: D. These events run with the base repository's secrets, so an untrusted ref must not land in the workspace root before the action runs.

## Frequently asked questions

### Can I start a run by assigning an issue or adding a label?

Yes. Add `assigned` and `labeled` to the `issues` event in the `on:` block, then set `assignee_trigger` to the assignee's username or `label_trigger` to the label name on the action step. Both sit beside `trigger_phrase`, whose default is `@claude`.

### Does the action need an API key?

It needs one credential. Use `ANTHROPIC_API_KEY` from the [Claude Console](https://platform.claude.com/settings/keys), or `CLAUDE_CODE_OAUTH_TOKEN` from `claude setup-token` on a subscription plan. For a secret shared across an organization, use an API key, since the OAuth token is tied to the person who ran the command. Workload identity federation avoids a static secret.

### Why is @claude not responding?

Check that the app is installed, workflows are enabled, the secret exists, the comment holds `@claude` as a whole word and the commenter has write access. A missing `id-token: write` permission also fails the run.

### Can Claude create and merge pull requests?

Not by default. It creates a branch and posts a pre-filled link, and a person opens the pull request. It does not merge, rebase or force push, and it pushes only to its own branch or the pull request branch it was invoked on.

### Is it safe to run on a public repository?

It can be, with care. A commenter needs write access, bots are blocked by default and the docs tell you to scope the workflow's permissions to the minimum. What remains is prompt injection through untrusted text, which sanitizing cannot fully stop, since the docs warn that new bypass techniques may emerge.

### How much does a run cost?

Each run uses GitHub Actions minutes and, with an API key, tokens that depend on prompt length, task and codebase size. With an OAuth token it uses your subscription instead. Cap turns with `--max-turns` and set timeouts and concurrency limits.

### Does it work with GitLab, Bedrock or Vertex?

`/install-github-app` works only with github.com repositories, and GitLab has its own page, Claude Code GitLab CI/CD. For Amazon Bedrock, Google Cloud's Agent Platform or Microsoft Foundry, set `use_bedrock`, `use_vertex` or `use_foundry` to `"true"` and authenticate through OIDC.

## Sources

- [Claude Code docs: Claude Code GitHub Actions](https://code.claude.com/docs/en/github-actions) (read 2026-11-05)
- [claude-code-action docs: Security](https://github.com/anthropics/claude-code-action/blob/main/docs/security.md) (read 2026-11-04)
- [claude-code-action docs: Usage](https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md) (read 2026-11-04)
- [claude-code-action docs: FAQ](https://github.com/anthropics/claude-code-action/blob/main/docs/faq.md) (read 2026-11-04)
- [claude-code-action docs: Setup guide](https://github.com/anthropics/claude-code-action/blob/main/docs/setup.md) (read 2026-11-04)
- [anthropics/claude-code-action on GitHub](https://github.com/anthropics/claude-code-action) (read 2026-11-05)
- [claude-code-action release v1.0.268 on GitHub](https://github.com/anthropics/claude-code-action/releases/tag/v1.0.268) (read 2026-11-05)
- [Boris Cherny on X: tag @claude on PRs to update CLAUDE.md](https://x.com/bcherny/status/2007179842928947333) (read 2026-11-05)

[Browse kits](https://mindket.com/kits)
