Claude Code · Advanced/Lesson 05 of 07~5 min

Claude Code in GitHub Actions

The same claude -p discipline, lifted into CI: a workflow file, a secret instead of a login, and every limit written down where no one has to remember it. Practised in a copy you throw away.

The Third Way engineering team||Verified against Claude Code v2.1.285 (stable), October 2026

01The goal

Run Claude Code unattended in a GitHub Actions workflow that reads its credential from a repository secret and stops within limits written in the file — then remove every trace of it.

02The idea

The Claude Code GitHub Action — anthropics/claude-code-action, from Anthropic — runs Claude Code as a step in a workflow. With no prompt input it waits for @claude in an issue or pull request and answers in a comment (interactive mode). With a prompt it runs on any event without waiting for a mention (automation mode), and its display_report input puts Claude’s report on the run’s summary page.

The workflow names a repository secret — ANTHROPIC_API_KEY for a Console key, CLAUDE_CODE_OAUTH_TOKEN for a subscription token — and the credential never appears in the file. No one is at the keyboard, so the limits go in the file: claude_args carries Claude Code’s CLI flags such as --max-turns and --allowedTools, the job’s permissions scope its GitHub token down to read, and timeout-minutes bounds the run.

This lesson practises in a throwaway private copy of the practice template, because it ends by deleting the workflow, the secret and the key. Make one: gh repo create claude-actions-practice --template wesammustafa/claude-code-practice --private --clone.

03The walkthrough

  1. 01In the copy, start claude and run /install-github-app. Follow the prompts: when GitHub asks which repositories the Claude GitHub App may access, choose Only select repositories and pick this copy only.
  2. 02Continue into the GitHub Actions setup and select just the @claude workflow, claude.yml. For the credential, paste an API key made for this lesson — quick setup saves it as the ANTHROPIC_API_KEY secret (or CLAUDE_CODE_OAUTH_TOKEN for a subscription token), pushes a branch carrying the workflow, and opens your browser with a pull request ready to create.
  3. 03Create and merge that pull request, git pull in your clone, and gh secret list — the secret is there, and @claude now works in the repository.
  4. 04Open an issue that mentions it: gh issue create --title "What does links.js do?" --body "@claude In one paragraph, what does src/links.js do? Don’t change any files." — then gh run list --limit 3 to see the run it started, and gh issue view <url> --comments for Claude’s answer.

04Your turn

Add .github/workflows/linkcheck-report.yml — a workflow you start by hand, in which Claude runs the template’s link checker on samples/ and explains each broken link on the run’s summary page, changing no files. Then run it, read the report, and tear down.

↳The skeleton, with the limits in place
on:
workflow_dispatch: {} # starts only by hand
permissions:
contents: read # a read-only job token
jobs:
linkcheck:
runs-on: ubuntu-latest
timeout-minutes: 20 # bounded run time
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: anthropics/claude-code-action@v1.0.237 # pinned, not @v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ github.token }}
prompt: Run npm run check:links on samples/ and explain each broken link.
claude_args: "--max-turns 8 --allowedTools Bash(npm run check:links *)"
display_report: true
Credential from the secret, never the file. The action pinned to a release tag or full SHA. Read-only token, turn cap, one narrow allow rule, a timeout. display_report: true puts the answer on the run’s summary page.
  1. 01Commit the workflow and push it to main — a workflow_dispatch run starts only when the file is on the default branch. Then: gh workflow run linkcheck-report.yml, find the run with gh run list --workflow linkcheck-report.yml --limit 1, and gh run watch <run-id> --exit-status.
  2. 02Read Claude’s report on the run’s summary page (gh run view <run-id> --web). With plain-text prompts Claude has no shell until you allow the commands it needs — which is why claude_args allows exactly one.
  3. 03Tear down, in order: delete the workflow file(s), commit and push. Delete the secret — gh secret delete ANTHROPIC_API_KEY. With an API key, delete the key itself on the Console’s API keys page. If nothing else uses it, remove the App’s access to the copy.

The security shape is the lesson inside the lesson. Anyone with write access to the repository can start a run with @claude, and the issue or comment text is input to Claude — it can carry hidden instructions, so keep practising copies private and think hard before enabling mentions where you do not control the writers. Pin the action because the @v1 tag moves with each release, and each release pins its own Claude Code version — a workflow on @v1 can run a newer Claude Code than the one you tested. And remember the teardown’s fine print: deleting a secret leaves the credential it held valid — retire the key itself.

↳Check yourself
Q1

What turns interactive mode into automation mode?

  1. AA prompt input on the action
  2. BSetting workflow_dispatch
  3. CNaming the secret CLAUDE_CODE_OAUTH_TOKEN
→Check your answer
Answer: A

With no prompt the action waits for @claude; with one, it runs on the trigger without waiting for a mention.

Q2

Why pin anthropics/claude-code-action to a release tag or SHA?

  1. AThe action refuses to run otherwise
  2. BThe @v1 tag moves with each release — and each release pins its own Claude Code version
  3. CPinned runs are cheaper
→Check your answer
Answer: B

A moving tag means the Claude Code version under your tested workflow can change without your consent. GitHub calls a full commit SHA the only immutable pin; a release tag is the lighter version.

Q3

The teardown deleted the ANTHROPIC_API_KEY secret. What is still true?

  1. AThe key it held is retired
  2. BNothing — deletion revokes it
  3. CThe key itself is still valid until you delete it on the Console
→Check your answer
Answer: C

Deleting a secret removes the pointer, not the credential. Retire the key itself — that is why the lesson recommends a key made for the lesson.

The Third Way engineering team
Delivery engineering
Work with us