$ backgroundclaude
blog · 2026-04-10 · 8 min read

Claude Code in GitHub Actions: the v1 recipe, with guardrails

Running Claude Code in a GitHub workflow used to be an exercise in gluing claude -p to a setup-node step and hoping for the best. The official anthropics/claude-code-action is now GA as @v1, and it makes three things easy that were annoying before: mentioning @claudein a PR comment, running Claude automatically on every PR, and kicking off scheduled automation. Here's the practical recipe, the three use cases worth the CI minutes, and the beta→v1 migration that broke every existing workflow.

The three-step setup

  1. Install the Claude GitHub app on your repo. Easiest path: open Claude Code in your terminal and run /install-github-app. It walks you through it. If that fails or you want manual control, install from github.com/apps/claude. The app needs Contents read/write, Issues read/write, and Pull requests read/write.
  2. Add ANTHROPIC_API_KEY to repo secrets. Settings → Secrets and variables → Actions. Never commit the key.
  3. Drop in a workflow file. Anthropic ships examples in the repo. The minimal one is ~15 lines. More below.

You must be a repo admin to install the GitHub app and add secrets. If you're on AWS Bedrock or Google Vertex AI, the quickstart doesn't apply — you'll need OIDC federation, a custom GitHub App, and the bedrock/vertex flags. The docs have a full walkthrough for both; the rest of this post assumes direct Anthropic API, which is what most teams use.

The minimal viable workflow

This is the smallest useful workflow. It listens for @claude mentions in PR and issue comments and lets Claude respond.

# .github/workflows/claude.yml
name: Claude Code
on:
  issue_comment:
    types: [created]
  pull_request_review_comment:
    types: [created]

jobs:
  claude:
    runs-on: ubuntu-latest
    steps:
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}

That's the whole thing. Commit it, open a PR, type @claude fix this in a comment, and Claude will respond inline. The action auto-detects that this is interactive mode (no prompt input) and waits for mentions.

What the docs don't say loudly enough

You almost certainly want to add workflow-level permissions and a concurrency control:

name: Claude Code
on:
  issue_comment:
    types: [created]
  pull_request_review_comment:
    types: [created]

permissions:
  contents: write
  pull-requests: write
  issues: write
  id-token: write   # only if using OIDC cloud auth

concurrency:
  group: claude-${{ github.event.issue.number || github.event.pull_request.number }}
  cancel-in-progress: true

jobs:
  claude:
    runs-on: ubuntu-latest
    steps:
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          claude_args: |
            --max-turns 10
            --max-budget-usd 3

The concurrencykey stops two@claude mentions on the same PR from running simultaneously and racing each other's commits. The --max-turns and --max-budget-usd flags cap any one run before it spends your weekend.

The three workflows worth the CI minutes

1. @claude mention (interactive mode)

The workflow above. You mention, Claude responds. Great for “fix this bug in the comment thread” and “implement the feature described in this issue.”

In comments you write things like:

@claude implement this feature based on the issue description
@claude how should I handle user authentication for this endpoint?
@claude fix the TypeError in the user dashboard component

The trigger phrase defaults to @claude. You can change it with trigger_phrase: "@bot" if you need to avoid name collisions.

2. Auto PR review on every pull_request event

This is the automation-mode variant — no mention required, the action runs as soon as the PR is opened or updated.

name: Code Review
on:
  pull_request:
    types: [opened, synchronize]

permissions:
  contents: read
  pull-requests: write

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          prompt: >
            Review this pull request for code quality, correctness,
            and security. Analyze the diff, then post your findings
            as review comments.
          claude_args: "--max-turns 5"

The presence of the prompt input tells the action this is automation mode — Claude runs immediately with the provided instructions. Notice the narrower --max-turns 5: a review shouldn't need many turns, and capping early saves cost and latency.

3. Scheduled automation

Same automation mode, different trigger — schedule + cron instead of pull_request.

name: Daily Report
on:
  schedule:
    - cron: "0 9 * * *"   # 9am UTC

permissions:
  contents: read
  issues: write

jobs:
  report:
    runs-on: ubuntu-latest
    steps:
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          prompt: >
            Generate a summary of yesterday's commits and open issues.
            Post the summary as a comment on issue #42.
          claude_args: "--max-turns 8 --max-budget-usd 1 --model opus"

This is where you graduate from GitHub Actions into actual scheduled work — recurring sweeps, nightly refactors, status updates posted back to an issue. GH Actions schedule is fine for one or two of these. Beyond that, you start hitting rate limits and cron drift, and the background agent loop is the cleaner pattern.

The beta→v1 migration (read this if your workflow used to work)

claude-code-action@beta and claude-code-action@v1have different input shapes. If your old workflow stopped working, it's probably because of these changes. From the docs, the mapping:

Old beta inputv1 equivalent
moderemoved — auto-detected from presence of prompt
direct_promptprompt
custom_instructionsclaude_args: --append-system-prompt
max_turnsclaude_args: --max-turns
modelclaude_args: --model
allowed_toolsclaude_args: --allowedTools
disallowed_toolsclaude_args: --disallowedTools
claude_envsettings JSON format

The big idea in v1: every CLI flag now goes through one claude_args input, so you learn the CLI flags once and use them everywhere — CLI, SDK, and Actions.

Cost and concurrency, the boring part

GitHub Actions GH-hosted runners consume your repo's Actions minutes. Every Claude interaction also consumes API tokens based on prompt/response length. Three rules:

jobs:
  claude:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          claude_args: |
            --max-turns 10
            --max-budget-usd 2

Security defaults worth caring about

Where GitHub Actions stops being the right tool

For two use cases — PR review and @claude comment response — the action is excellent and you should probably just use it.

It gets harder when you want:

That list is the shape of a background agent, and it's what Cyrus does on top of the same Claude Code underneath. GitHub Actions is the right tool for GitHub-centric, stateless, one-shot work. Cyrus is the right tool once the loop matters more than the individual run.

Takeaways

beyond github

Linear, GitLab, Slack — same loop, same Claude.

Cyrus runs Claude Code (or Codex, Cursor, Gemini) in isolated git worktrees per issue, across Linear, GitHub, GitLab, and Slack, with rich mid-run approvals and streamed events back to the triggering issue. Community self-hosted is free forever, BYOK across all models.

Try Cyrus free →