Przejdź do głównej zawartości

Claude Code w CI/CD z GitHub Actions i trybem headless

Claude Code działa w CI/CD przez akcję GitHuba anthropics/claude-code-action@v1, a w każdym innym pipelinie przez tryb headless (claude -p). Akcja odpowiada na wzmianki @claude albo wykonuje stały prompt przy dowolnym zdarzeniu GitHuba, na przykład etykiecie lub nieudanym buildzie. Każdy przebieg ograniczają allowlista narzędzi, limit tur i te same wymagane testy, które przechodzi kod ludzi.

Twój zespół otwiera 30 pull requestów tygodniowo, każdy czeka pół dnia na pierwsze spojrzenie człowieka, a build pada dwa razy w tygodniu na zapomnianej regule lintera. Chcesz agenta w pipelinie, który nie „naprawi” builda usuniętym testem ani nie odda sekretu w cudzym pull requeście. Ta strona jest dla programisty, który konfiguruje workflowy, i dla tech leada, który decyduje, co wolno im robić.

  • Workflow @claude, który odpowiada na prośby w komentarzach do zgłoszeń i pull requestów
  • Automatyczne code review każdego pull requesta z komentarzami przy liniach, plus własny prompt nastawiony na bezpieczeństwo
  • Zadanie zamieniające oznaczone etykietą zgłoszenie w pull request, z bramką specyfikacji przed startem
  • Workflow auto-fix dla CI, który nie może usunąć ani pominąć testu i nigdy nie uruchamia kodu gałęzi obok twojego klucza API, bo osobny job bez sekretów ponownie uruchamia bramkę, zanim cokolwiek zostanie wypchnięte
  • Przepis na headless claude -p dla GitLaba, Jenkinsa lub dowolnego runnera, ze strukturalnym JSON-em, na którym skrypt może oprzeć decyzję
  • Konfiguracje dla Bedrocka, Google Cloud i Foundry, limity kosztów oraz awarie, których możesz się spodziewać w pierwszym tygodniu
ChceszUżyjWynik trafia do
Doraźnych próśb od ludzi w zgłoszeniach i PR-achAkcji bez wejścia prompt (tryb interaktywny)Komentarza, który Claude aktualizuje w trakcie
Stałego zadania na zdarzenie (nowy PR, etykieta, cron)Akcji z wejściem prompt (tryb automatyzacji)Logu przebiegu albo komentarza, jeśli prompt o to prosi
Code review każdego PR-a bez utrzymywania workflowuZarządzanego Code Review (Team i Enterprise, research preview)Komentarzy przy liniach PR-a
Claude’a w GitLabie, Jenkinsie, Buildkite lub na maszynie z cronemHeadless claude -p w skrypciestdout, JSON-a, którego parsujesz
Cyklicznego zadania bez zdarzenia w repozytoriumRutyn (Routines)Sesji w chmurze

Akcja sama wybiera tryb na podstawie konfiguracji: bez prompt czeka na frazę wyzwalającą (domyślnie @claude), z prompt startuje od razu. Sam YAML pipeline’u (cache, macierze, filtry ścieżek) opisuje konfiguracja pipeline za pomocą Claude Code. Ta strona dotyczy agenta działającego wewnątrz tego pipeline’u.

Zainstaluj aplikację Claude GitHub App i workflow @claude

Dział zatytułowany „Zainstaluj aplikację Claude GitHub App i workflow @claude”
  1. Uruchom instalator z lokalnej sesji. Zainstaluj GitHub CLI i wykonaj gh auth login. Otwórz claude w repozytorium i wpisz /install-github-app. Potrzebujesz uprawnień administratora repozytorium, a komenda działa tylko dla remote’ów na github.com. Instaluje aplikację Claude GitHub App i zapisuje sekret repozytorium: ANTHROPIC_API_KEY dla klucza API albo CLAUDE_CODE_OAUTH_TOKEN dla tokenu subskrypcji (wygenerujesz go przez claude setup-token).

  2. Scal pull request z workflowem, który otworzy instalator. Instalator wypycha gałąź z claude.yml (i z claude-code-review.yml, jeśli wybierzesz workflow code review) i otwiera GitHuba na gotowym pull requeście. Scalenie go włącza @claude.

  3. Albo dodaj workflow ręcznie. Ręczna konfiguracja jest potrzebna dla Bedrocka, Google Cloud i Foundry albo gdy chcesz panować nad plikiem. Zainstaluj Claude GitHub App, dodaj sekret i zacommituj ten plik:

    .github/workflows/claude.yml
    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
    timeout-minutes: 30
    permissions:
    contents: write
    pull-requests: write
    issues: write
    id-token: write # the action's GitHub App authentication
    actions: read # lets Claude read CI results on the PR
    steps:
    - uses: actions/checkout@v7
    with:
    fetch-depth: 1
    persist-credentials: false
    - uses: anthropics/claude-code-action@v1
    with:
    anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
    claude_args: '--max-turns 30'
  4. Przetestuj. Skomentuj zgłoszenie: @claude fix the TypeError in the dashboard component. Claude odpowiada komentarzem, aktualizuje go w trakcie pracy i commituje na nową gałąź. Nie otwiera pull requesta sam: jego komentarz linkuje do strony tworzenia PR-a na GitHubie, więc to człowiek decyduje, co zostanie zaproponowane.

Przy pull requeście akcja, zanim Claude ruszy, przywraca z gałęzi bazowej ścieżki konfiguracji samego Claude’a: .claude/, .mcp.json, .claude.json, CLAUDE.md, CLAUDE.local.md, .husky/ i kilka innych. Pull request nie wniesie więc własnych hooków ani serwerów MCP. Cała reszta zostaje w wersji z pull requesta, łącznie z package.json, więc hook z gałęzi bazowej, który wywołuje npm run format, uruchamia skrypt napisany w pull requeście. Wywołuj narzędzia bezpośrednio, z przypiętą wersją (docs/security.md akcji, odczyt 2026-09-26).

Które wejścia akcji istnieją, a które są po cichu ignorowane?

Dział zatytułowany „Które wejścia akcji istnieją, a które są po cichu ignorowane?”

Najczęstsze wejścia to prompt, claude_args, anthropic_api_key lub claude_code_oauth_token, github_token, settings, plugins, plugin_marketplaces, trigger_phrase, track_progress, allowed_bots oraz use_bedrock, use_vertex lub use_foundry (pełna lista w action.yml). Wejść z czasów bety, czyli model, max_turns, timeout_minutes, direct_prompt i custom_instructions, w v1 nie ma (action.yml na gałęzi main, 2026-09-26): GitHub wypisuje ostrzeżenie „Unexpected input”, a przebieg idzie dalej na ustawieniach domyślnych. Opcje CLI przenieś do claude_args:

  • --model claude-sonnet-5 przypina model. Bez tego akcja używa domyślnego modelu Claude Code, więc koszt przebiegu zmienia się razem ze zmianą domyślnego modelu. Zanim wybierzesz, zajrzyj do przeglądu modeli.
  • --max-turns 10 kończy przebieg błędem, gdy Claude dojdzie do limitu.
  • --allowedTools "..." przyznaje narzędzia. W trybie automatyzacji Claude nie ma powłoki ani dostępu do API GitHuba poza tym, co mu przyznasz.
  • --append-system-prompt "..." zastępuje dawne custom_instructions.

Zegar zadania to GitHubowe timeout-minutes: na poziomie joba, a nie wejście akcji.

Jeśli nie chcesz przechowywać żadnego długowiecznego poświadczenia Claude’a, akcja może wymienić token OIDC workflowu GitHuba na dostęp do API przez konto serwisowe w Claude Console. Ustaw anthropic_federation_rule_id i anthropic_organization_id (plus anthropic_service_account_id albo anthropic_workspace_id, gdy reguła ich wymaga) i zostaw id-token: write. Jeśli jeden sekret ma obsługiwać całą organizację, niech to będzie klucz API z Console: CLAUDE_CODE_OAUTH_TOKEN jest związany z subskrypcją osoby, która uruchomiła claude setup-token.

Workflow code review z szybkiej instalacji uruchamia plugin code-review z marketplace’u claude-code Anthropic. Oto ten sam workflow rozpisany, żebyś panował nad wyzwalaczami, modelem i uprawnieniami:

.github/workflows/claude-review.yml
name: Code Review
on:
pull_request:
types: [opened, synchronize, ready_for_review, reopened]
jobs:
review:
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
timeout-minutes: 20
concurrency:
group: claude-review-${{ github.event.pull_request.number }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: read
issues: read
id-token: write
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 1
persist-credentials: false
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
plugins: 'code-review@claude-code-plugins'
prompt: '/code-review:code-review --comment ${{ github.repository }}/pull/${{ github.event.pull_request.number }}'
claude_args: '--allowedTools "mcp__github_inline_comment__create_inline_comment"'

Dwie linie decydują, czy ktokolwiek zobaczy code review. --comment sprawia, że Claude publikuje komentarze przy liniach albo jeden komentarz podsumowujący, gdy nic nie znajdzie; bez tej flagi wyniki zostają w logu przebiegu. Akcja uruchamia serwer MCP do komentarzy przy liniach tylko wtedy, gdy przyznaje go --allowedTools. W publicznych repozytoriach GitHub nie udostępnia sekretów pull requestom z forków, więc to zadanie obejmuje tylko gałęzie z tego samego repozytorium.

Żeby code review trzymało się reguł zespołu, zapisz je w CLAUDE.md albo w skillu w .claude/skills/ i wywołaj go jako prompt (/security-pass). Krok checkout musi wykonać się wcześniej, żeby pliki skilla były na runnerze. Własne komendy slash są teraz skillami; zobacz własne komendy.

Wstaw go jako prompt: w workflowie powyżej zamiast wywołania pluginu i dopisz do --allowedTools narzędzia Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr comment:*), żeby Claude mógł przeczytać diff i opublikować komentarz podsumowujący. Linia z confirmed: true w prompcie też ma znaczenie: narzędzie akcji do komentarzy przy liniach wstrzymuje niepotwierdzone komentarze i klasyfikuje je po zakończeniu sesji, więc bez niej komentarze mogą się opóźnić albo zostać odfiltrowane. Etykiety ważności mają znaczenie: code review, które zgłasza wszystko z tą samą głośnością, w drugim tygodniu przestaje być czytane, a „nic HIGH, sprawdziłem to i to” samo w sobie jest dowodem, z którego może skorzystać recenzent.

Traktuj to code review jako jeden z czujników, a nie jako zatwierdzenie. Co człowiek czyta zamiast całego diffu, opisuje code review PR-a agenta bez czytania każdej linii. Lokalne code review przed pushem opisuje automatyzacja code review.

Etykieta jest bramką specyfikacji: nic nie rusza, dopóki człowiek nie uzna, że zgłoszenie ma kryteria akceptacji, które agent może spełnić.

.github/workflows/issue-to-pr.yml
name: Issue to PR
on:
issues:
types: [labeled]
permissions: {}
jobs:
implement:
# Holds the API key and a read-only token. Claude edits and tests; it cannot push.
if: >-
github.event.label.name == 'claude-implement' &&
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.issue.author_association)
runs-on: ubuntu-latest
timeout-minutes: 45
permissions:
contents: read
issues: read
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ github.token }} # scoped to this job's read-only permissions
prompt: |
Implement issue #${{ github.event.issue.number }} in ${{ github.repository }}.
Read it with `gh issue view ${{ github.event.issue.number }}` and ignore its comments.
Follow the instructions in .github/claude/implement.md.
Write the pull request body to ${{ runner.temp }}/pr-body.md.
claude_args: >-
--max-turns 40
--add-dir ${{ runner.temp }}
--allowedTools "Read,Edit,Write,Glob,Grep,Bash(gh issue view:*),Bash(npm ci),Bash(npm test:*),Bash(npm run lint:*),Bash(npm run typecheck:*)"
- name: Export Claude's change as a patch
run: |
git add -A && git diff --cached --binary > "$RUNNER_TEMP/change.patch"
[ -s "$RUNNER_TEMP/pr-body.md" ] || echo "Claude wrote no PR body." > "$RUNNER_TEMP/pr-body.md"
- uses: actions/upload-artifact@v7
with:
name: claude-implement
path: |
${{ runner.temp }}/change.patch
${{ runner.temp }}/pr-body.md
open-pr:
# Holds the write token, never sees the API key, runs nothing Claude wrote.
needs: implement
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: write
pull-requests: write
issues: write
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: actions/download-artifact@v8
with:
name: claude-implement
path: ${{ runner.temp }}
- name: Push claude/issue-N and open a PR, or post Claude's questions
env:
GH_TOKEN: ${{ github.token }}
ISSUE: ${{ github.event.issue.number }}
run: |
if [ ! -s "$RUNNER_TEMP/change.patch" ]; then
gh issue comment "$ISSUE" --body-file "$RUNNER_TEMP/pr-body.md"; exit 0; fi
BR="claude/issue-$ISSUE"
git apply --index "$RUNNER_TEMP/change.patch"
if git diff --cached --name-only | grep '^\.github/'; then
echo "Refusing: the change touches .github/"; exit 1; fi
git config user.name "claude[bot]"
git config user.email "claude[bot]@users.noreply.github.com"
git switch -c "$BR"
git commit -m "Implement #$ISSUE"
git push "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "HEAD:refs/heads/$BR"
gh pr create --head "$BR" --title "Implement #$ISSUE" --body-file "$RUNNER_TEMP/pr-body.md"

Prompt przekazuje numer zgłoszenia, a nie ${{ github.event.issue.body }}. Wklejenie treści sprawia, że tekst autora zgłoszenia staje się częścią twoich instrukcji; przekazanie numeru zostawia instrukcje po twojej stronie, a zgłoszenie jako dane, które Claude czyta. To zmniejsza ryzyko prompt injection, ale go nie usuwa, dlatego workflow otacza je czterema kontrolami:

  • Kto napisał tekst i kto nadał etykietę. Etykietę może nadać także osoba z rolą Triage, ale claude-code-action odmawia startu każdemu aktorowi bez prawa zapisu lub administratora, chyba że ustawisz allowed_non_write_users, więc przebieg uruchomi tylko nadający etykietę z prawem zapisu. Tę bramkę daje sama akcja (checkWritePermissions, sprawdzone na main w commicie 97c5347, 2026-10-01): zamień akcję na zwykły krok claude -p, a ją stracisz. Warunek na author_association pomija zgłoszenia, których autorem nie jest właściciel, członek organizacji ani współpracownik, przy czym COLLABORATOR obejmuje też współpracowników z prawem odczytu i rolą Triage. Claude czyta zgłoszenie bez komentarzy, bo komentarz może dopisać każdy, także już po nadaniu etykiety.
  • Claude nie dostaje gita. Wpis w rodzaju Bash(git:*) to dowolna powłoka: git -c alias.x='!sh -c …' x uruchamia dowolną komendę, a sama akcja dostarcza własny wrapper scripts/git-push.sh właśnie dlatego, że git push --receive-pack=… robi to samo. Tutaj Claude nie ma gita, a jego token ma tylko contents: read.
  • Token z prawem zapisu żyje w osobnym jobie. open-pr nigdy nie widzi klucza API i nie uruchamia niczego, co napisał Claude: nakłada patch, odrzuca każdą zmianę w .github/, wypycha claude/issue-<numer> i otwiera pull request, a gdy zmiany nie ma, publikuje pytania Claude’a w zgłoszeniu.
  • Każdy checkout ma persist-credentials: false, więc żaden krok nie zostawia tokenu w .git/config dla kolejnego.

npm test to nadal wykonywanie kodu obok klucza API, bo testy, które Claude uruchamia, sam pisze. Tutaj jest to do przyjęcia tylko dlatego, że zaufany jest zarówno kod (gałąź domyślna), jak i instrukcje (zgłoszenie od zaufanego autora). Przy zgłoszeniach od zewnętrznych kontrybutorów użyj kształtu workflowu naprawy CI opisanego niżej: Claude dostaje tylko narzędzia plikowe, a bramkę uruchamia job bez sekretów. Pull request otwarty GITHUB_TOKEN-em workflowu nie uruchamia innych workflowów, więc jeśli CI ma na nim ruszyć, użyj w open-pr tokenu GitHub App.

To ryzyko nie jest teoretyczne. W łańcuchu, który badacz bezpieczeństwa Adnan Khan nazwał „Clinejection”, jak streścił go Simon Willison 2026-03-06 (relacja z drugiej ręki), prompt wstrzyknięty przez tytuł zgłoszenia do workflowu AI do triażu, zbudowanego na claude-code-action z narzędziami Bash, Write i Edit, doprowadził do zatrucia cache GitHub Actions i kradzieży tokenów publikacji.

Pull request otwarty w ten sposób niesie własne dowody: kryteria przypisane do testów, uruchomione komendy, otwarte pytania. Taki kształt definiuje pakiet dowodów i to on pozwala recenzentowi zatwierdzić zmianę na podstawie dowodów, a nie czytania linia po linii.

Niebezpieczna wersja tego zadania robi checkout padającej gałęzi, daje Claude’owi klucz API i powłokę, a potem wypycha to, co wyprodukuje. Prędzej czy później usuwa niestabilny test, który się sypał. Do tego skrypty z package.json, pliki testów i konfigurację builda z tej gałęzi uruchamia w tym samym jobie co twój sekret, więc każdy, kto może wypchnąć gałąź, może odczytać klucz.

Wersja poniżej dzieli pracę na trzy joby o różnych uprawnieniach:

JobMa dostęp doUruchamia kod gałęzi?Co robi
patchKlucz API, token tylko do odczytuNieClaude czyta logi i edytuje kopię commita
verifyNiczego: bez sekretów, token tylko do odczytuTakNakłada łatkę, odrzuca osłabione testy, ponownie uruchamia bramkę
open-prToken z prawem zapisuNieCommituje zweryfikowaną łatkę na nową gałąź i otwiera PR
.github/workflows/claude-fix-ci.yml
name: Claude fixes CI
on:
workflow_run:
workflows: ['CI']
types: [completed]
permissions: {}
jobs:
patch:
# Holds the API key. Reads and edits the failing commit, never executes it.
if: >-
github.event.workflow_run.conclusion == 'failure' &&
github.event.workflow_run.pull_requests[0] &&
!startsWith(github.event.workflow_run.head_branch, 'claude-fix/')
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
actions: read
id-token: write
steps:
- uses: actions/checkout@v7 # trusted default branch at the workspace root
with:
persist-credentials: false
- uses: actions/checkout@v7 # the failing commit, in a subdirectory
with:
ref: ${{ github.event.workflow_run.head_sha }}
path: pr-head
persist-credentials: false
- name: Save the failing jobs' logs
env:
GH_TOKEN: ${{ github.token }}
RUN_ID: ${{ github.event.workflow_run.id }}
run: gh run view "$RUN_ID" --repo "$GITHUB_REPOSITORY" --log-failed | tail -c 60000 > "$RUNNER_TEMP/ci-failure.log"
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: |
CI failed on the commit checked out in pr-head/. The failing jobs' logs are in
${{ runner.temp }}/ci-failure.log. Edit files under pr-head/ only.
Follow the CI-fix rules in .github/claude/fix-ci.md.
claude_args: >-
--max-turns 25
--add-dir pr-head ${{ runner.temp }}
--allowedTools "Read,Edit,Write,Glob,Grep"
- name: Export Claude's change as a patch
run: git -C pr-head add -A && git -C pr-head diff --cached --binary > fix.patch
- uses: actions/upload-artifact@v7
with:
name: claude-fix
path: fix.patch
verify:
# Executes the branch's code, so it gets no secrets and a read-only token.
needs: patch
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
steps:
- uses: actions/checkout@v7
with:
ref: ${{ github.event.workflow_run.head_sha }}
persist-credentials: false
- uses: actions/download-artifact@v8
with:
name: claude-fix
path: ${{ runner.temp }}
- name: Apply the patch and re-run the gate outside Claude
run: |
[ -s "$RUNNER_TEMP/fix.patch" ] || { echo "Claude changed nothing"; exit 1; }
git apply --index "$RUNNER_TEMP/fix.patch"
if git diff --cached --name-only --diff-filter=D | grep -E '\.(test|spec)\.'; then
echo "Refusing: a test file was deleted"; exit 1; fi
if git diff --cached -U0 | grep -E '^\+.*\.(skip|only)\(|^\+.*\bxit\('; then
echo "Refusing: a test was skipped or focused"; exit 1; fi
if git diff --cached --name-only | grep -E '^\.github/|(^|/)package(-lock)?\.json$|(jest|vitest|playwright|karma)\.config\.'; then
echo "Refusing: the patch edits CI, package scripts or test config"; exit 1; fi
npm ci && npm run lint && npm run typecheck && npm test
open-pr:
# Can write to the repository, but runs no code from the branch.
needs: verify
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v7
with:
ref: ${{ github.event.workflow_run.head_sha }}
persist-credentials: false
- uses: actions/download-artifact@v8
with:
name: claude-fix
path: ${{ runner.temp }}
- name: Push to a fix branch and open a PR
env:
GH_TOKEN: ${{ github.token }}
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
RUN_ID: ${{ github.run_id }}
run: |
SAFE=$(printf '%s' "$HEAD_BRANCH" | tr -cd 'a-zA-Z0-9/_.-')
BR="claude-fix/$SAFE-$RUN_ID"
git apply --index "$RUNNER_TEMP/fix.patch"
git config user.name "claude[bot]"
git config user.email "claude[bot]@users.noreply.github.com"
git switch -c "$BR"
git commit -m "fix: repair CI failure from run $RUN_ID"
git push "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "HEAD:refs/heads/$BR"
gh pr create --head "$BR" --base "$HEAD_BRANCH" --fill

Bezpieczeństwo opiera się na czterech decyzjach. Claude dostaje narzędzia plikowe i żadnej powłoki, więc kod gałęzi nigdy nie działa obok klucza. Ten kod działa tylko w verify, który nie ma żadnego sekretu i odrzuca patch dotykający .github/, package.json albo konfiguracji testów, więc Claude nie przepisze bramki, która go sprawdza. Sprawdzenie prefiksu claude-fix/ nie pozwala workflowowi wyzwalać samego siebie. A pull request celuje w gałąź programisty, więc to autor przyjmuje albo odrzuca poprawkę.

verify nie jest jednak piaskownicą. Job wyzwolony przez workflow_run działa w kontekście gałęzi domyślnej i dzieli z nią zakres cache GitHub Actions, więc niezaufany kod może tam zatruć cache bez żadnego sekretu, a to jest właśnie wektor Clinejection opisany wyżej. Nie używaj actions/cache ani cache w setup-node w verify i nigdy nie przywracaj cache w workflowach wydania i publikacji.

Ceną jest to, że Claude nie uruchomi testów, więc nieudany verify oznacza brak pull requesta, a nie ponowną próbę; artefakt claude-fix przechowuje łatkę i diagnozę. Pull request otwarty tokenem GITHUB_TOKEN workflowu nie wyzwala innych workflowów; verify już uruchomił bramkę, a token aplikacji GitHub (actions/create-github-app-token) w open-pr sprawi, że CI ruszy także na nim.

Plik z promptem leży na gałęzi domyślnej, więc pull request nie przepisze reguł, których Claude przestrzega. CLAUDE_FIX_NOTES.md trafia do commita dla recenzenta; przed scaleniem usuń go albo przenieś jego treść do opisu PR-a.

Uruchom Claude Code headless w GitLabie, Jenkinsie lub dowolnym runnerze

Dział zatytułowany „Uruchom Claude Code headless w GitLabie, Jenkinsie lub dowolnym runnerze”

Poza GitHub Actions wywołuj CLI bezpośrednio. W CI nie ładuj niczego z checkoutu. --bare pomija hooki, synchronizację pluginów, auto memory, LSP i automatyczne wyszukiwanie CLAUDE.md. --setting-sources "" pomija pliki ustawień użytkownika, projektu i lokalne. --strict-mcp-config ignoruje każdy serwer MCP, którego nie przekazałeś przez --mcp-config. Tryb bare uwierzytelnia się wyłącznie przez ANTHROPIC_API_KEY, apiKeyHelper przekazany przez --settings albo poświadczenia dostawcy chmury, nigdy logowaniem z subskrypcji ani przez pęk kluczy (wszystko sprawdzone w claude --help, 2.1.283).

Okno terminala
# In the CI job; ANTHROPIC_API_KEY comes from the CI secret store.
CI_TMP=$(mktemp -d)
git diff "origin/$TARGET_BRANCH...HEAD" > "$CI_TMP/change.diff"
claude --bare -p "Classify the risk of the change in $CI_TMP/change.diff for release. Read the files it touches. Answer in the schema." \
--setting-sources "" --strict-mcp-config \
--add-dir "$CI_TMP" \
--allowedTools "Read,Grep,Glob" \
--permission-mode dontAsk \
--max-turns 15 --max-budget-usd 3 \
--output-format json \
--json-schema '{"type":"object","properties":{"risk":{"enum":["low","medium","high"]},"reasons":{"type":"array","items":{"type":"string"}}},"required":["risk","reasons"]}' \
> risk.json
jq -e '.is_error == false and (.structured_output.risk == "low" or .structured_output.risk == "medium")' risk.json || { jq '.structured_output.reasons // .result' risk.json; exit 1; }

--permission-mode dontAsk odrzuca wszystko spoza allowlisty, zamiast czekać na pytanie, na które nikt nie odpowie. --max-budget-usd zatrzymuje przebieg na limicie w dolarach i działa tylko z -p. --json-schema umieszcza zwalidowany obiekt w polu structured_output, więc pipeline rozgałęzia się na wartości, a nie na wolnym tekście. Przebieg, który kończy się błędem, wyczerpuje budżet albo limit tur, nie ma structured_output, więc bramka musi traktować brak werdyktu jako porażkę; dlatego linia jq sprawdza is_error i przepuszcza tylko dwie znane bezpieczne wartości. --max-turns nie pojawia się w wyjściu claude --help, ale jest opisane w dokumentacji CLI i działa z -p (sprawdzone na 2.1.283). W zadaniu, które ma wyłącznie czytać, --restricted dodatkowo usuwa Bash i pozostałe narzędzia uruchamiające kod oraz ogranicza narzędzia plikowe do katalogów roboczych i --add-dir.

Dla GitLaba istnieje też utrzymywana przez GitLab integracja Claude Code z GitLab CI/CD, w wersji beta. Do sterowania programowego wykraczającego poza wywołanie z powłoki użyj Claude Agent SDK. Dłuższe, wieloetapowe skrypty opisuje automatyzacja z Claude Code.

Z dostawcą chmury akcja uwierzytelnia się przez federację OIDC, więc repozytorium nie przechowuje statycznych poświadczeń chmurowych. Ustaw jedno wejście (use_bedrock, use_vertex albo use_foundry), nadaj id-token: write i dodaj krok logowania do dostawcy przed akcją.

permissions:
contents: write
pull-requests: write
issues: write
id-token: write
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
aws-region: us-west-2 # exported as AWS_REGION for the rest of the job
- uses: anthropics/claude-code-action@v1
with:
use_bedrock: 'true'
claude_args: '--model us.anthropic.claude-opus-5-5 --max-turns 10'

Użyj ID profilu inferencji, które konsola Bedrocka pokazuje dla grupy regionów, w której nadałeś dostęp do modelu, na przykład us. plus ID modelu w Bedrocku anthropic.claude-opus-5-5. Rola IAM potrzebuje zawężonej polityki wywołań od Anthropic, która obejmuje bedrock:InvokeModel.

W publicznym repozytorium każdy komentarz z frazą wyzwalającą uruchamia te zadania, a logowanie do chmury wykonuje się, zanim akcja sprawdzi prawo zapisu komentującego. Dodaj pierwszy krok, który sprawdza uprawnienia komentującego przez gh api i kończy zadanie wcześniej. Pełną konfigurację dostawców, łącznie z własną aplikacją GitHub z uprawnieniami tylko do Contents, Issues i Pull requests, opisuje przewodnik Anthropic po dostawcach chmury oraz nasza strona o integracji korporacyjnej.

Każdy przebieg zużywa minuty GitHub Actions i tokeny modelu; CLAUDE_CODE_OAUTH_TOKEN obciąża subskrypcję zamiast API. Większość pracy wykonuje pięć mechanizmów:

  • Nie uruchamiaj wcale dla draftów, zmian wyłącznie w dokumentacji i PR-ów od botów: if: github.event.pull_request.draft == false plus filtr paths: w wyzwalaczu.
  • Przypnij model w claude_args, żeby zmiana domyślnego modelu nie zmieniała rachunku. Ceny są w przeglądzie modeli.
  • Ogranicz pracę: --max-turns w akcji, --max-turns i --max-budget-usd w przebiegach headless.
  • Ogranicz czas przez timeout-minutes: joba.
  • Anuluj nieaktualne przebiegi grupą concurrency: na pull request, jak w workflowie code review powyżej.

Zarządzane Code Review jest rozliczane osobno: dokumentacja Anthropic podaje, że każde review „averages $15-25” i rośnie z rozmiarem PR-a (dokumentacja Code Review, sprawdzone 2026-09-26). Wydatki CI śledź obok użycia interaktywnego według strony kontrola kosztów Claude Code.

Dowód pochodzi z bramek, których Claude nie może edytować:

  1. Wymagane status checki. Ochrona gałęzi wymaga na PR-ach Claude’a tych samych testów, sprawdzania typów i lintera co na PR-ach wszystkich innych. Workflow auto-fix uruchamia je ponownie w jobie, którego Claude nie dotyka.
  2. Chronione testy. Reguła CODEOWNERS na katalogach testów i konfiguracji CI sprawia, że zmiana wyroczni wymaga zatwierdzenia przez wskazaną osobę. Workflow auto-fix przed pushem odrzuca usunięte, pominięte i zawężone (.only) testy.
  3. Dowody w opisie PR-a. Kryteria akceptacji przypisane do testów, uruchomione komendy i otwarte pytania, zgodnie z pakietem dowodów.
  4. Strukturalne werdykty. Zadania headless zwracają wynik --json-schema, a pipeline pada na wartości, a nie na tym, że człowiek przeczyta prozę.
  5. Człowiek zatwierdzający dla każdej klasy ryzyka. Komentarze Claude’a to dane wejściowe. Decyzja o scaleniu zostaje przy osobie wskazanej w CODEOWNERS, a przy ścieżkach wysokiego ryzyka ta osoba czyta wybrane punkty zapalne opisane w code review PR-a agenta.

Kolejność wdrażania dla tech leada: najpierw workflow code review (tylko odczyt, niskie ryzyko), potem @claude, potem zgłoszenie w PR za etykietą, a auto-fix dopiero wtedy, gdy job verify i CODEOWNERS na testach są na miejscu.

Claude nie odpowiada na @claude. Sprawdź, czy aplikacja Claude GitHub App jest zainstalowana w tym repozytorium, czy Actions są włączone, czy nazwa sekretu zgadza się z workflowem, czy komentarz zawiera @claude jako całe słowo i czy komentujący ma prawo zapisu. Log przebiegu pokazuje, która kontrola odrzuciła zdarzenie.

CI nie rusza na commitach Claude’a. GitHub nie wyzwala workflowów na pushach wykonanych domyślnym GITHUB_TOKEN. Usuń github_token: ${{ secrets.GITHUB_TOKEN }} z akcji, żeby uwierzytelniała się jako Claude GitHub App, albo przekaż token własnej aplikacji GitHub.

Code review się wykonuje, ale nic nie publikuje. Prompt nie ma --comment albo claude_args nie dopuszcza mcp__github_inline_comment__create_inline_comment. Plugin code-review pomija też drafty, zamknięte pull requesty i te, które Claude już skomentował.

Workflow ignoruje twój model albo limit tur. Ustawiłeś model: lub max_turns: jako wejścia akcji. Poszukaj w przebiegu adnotacji z ostrzeżeniem „Unexpected input” i przenieś wartości do claude_args.

Zadanie z harmonogramu nie przechodzi kontroli aktora. GitHub przypisuje przebiegi z harmonogramu użytkownikowi, który ostatnio zmienił linię cron. Jeśli to bot, dodaj go do allowed_bots. W publicznych repozytoriach GitHub wyłącza też harmonogram po 60 dniach bez aktywności.

Zadanie kończy się błędem max-turns. Zadanie jest za duże na jeden przebieg. Podziel je (jedno zgłoszenie na przebieg, jeden padający job na naprawę), zanim podniesiesz limit.

Workflow auto-fix nigdy nie otwiera pull requesta. verify padł albo Claude zatrzymał się zgodnie z regułami i zapisał tylko diagnozę. Przeczytaj CLAUDE_FIX_NOTES.md z artefaktu claude-fix i dokończ ręcznie. Jeśli verify pada w większości przebiegów, zostaw te awarie człowiekowi, zamiast dawać powłokę jobowi, który ma klucz.

open-pr pada z komunikatem „GitHub Actions is not permitted to create or approve pull requests”. Gałąź z poprawką jest już wypchnięta, ale repozytorium lub organizacja nie pozwala tokenowi GITHUB_TOKEN workflowu otwierać pull requestów. Włącz „Allow GitHub Actions to create and approve pull requests” w Settings → Actions → General albo użyj tokenu aplikacji GitHub w open-pr.

Auto-fix otwiera pull request, który osłabia test. Wzorce w verify tego nie wyłapały, na przykład obniżonego progu pokrycia. Zamknij PR, dopisz ten wzorzec do verify i obejmij plik konfiguracji regułą CODEOWNERS.

Job wydania lub publikacji uruchamia kod, którego nikt nie scalił. Job wykonujący kod gałęzi, na przykład verify, zapisał coś do cache Actions gałęzi domyślnej, a późniejszy zaufany workflow ten cache przywrócił. Usuń cache ze wszystkich jobów uruchamiających niezaufany kod, przestań przywracać cache w workflowach wydania i publikacji i wyczyść cache repozytorium w Actions → Caches.

Bedrock lub Google Cloud zwraca 401 albo 403. Polityka zaufania OIDC nie pasuje do tego repozytorium lub gałęzi, rola nie ma uprawnienia do wywołania modelu albo brakuje dostępu do modelu w jednym z regionów profilu inferencji.