- Claude Code
Claude
GitHub Actions
GitHub
Claude Code in GitHub Actions: review automatica delle PR con claude-code-action
Quando lavoro con Claude Code in GitHub Actions il momento che preferisco è aprire una pull request e trovare, poco dopo, una review già scritta: rischi individuati, righe puntate, severità assegnata. Il runner installa Claude Code e usa lo stesso agent loop disponibile in locale, attraverso l'Agent SDK della action. In questo tutorial monto il flusso da zero: parto da `claude -p` nel terminale, installo la GitHub App con `/install-github-app`, scrivo due workflow separati (review automatica e `@claude` interattivo) e chiudo con guardrail su tool, turni, budget e permessi.
🔍 Modalità non interattiva: claude -p
Tutto quello che Claude Code fa in una sessione interattiva — leggere file, lanciare comandi, ragionare sul codice — lo sa fare anche senza interfaccia. Il flag `-p` (o `--print`) esegue un prompt, stampa il risultato ed esce: è la modalità non interattiva, in passato chiamata headless, su cui si costruiscono script e automazioni. Il contesto arriva dalla directory di lavoro e l'output va su stdout come per qualsiasi tool Unix.
Per la CI servono guardrail distinti. `--output-format` sceglie tra `text`, `json` e `stream-json`; il JSON include risultato, session ID e una stima del costo. `--allowedTools` pre-approva i tool, ma non è da solo una deny-list: per un run ristretto aggiungo `--permission-mode dontAsk` e nego esplicitamente i tool di scrittura. `--max-turns` limita i round trip dell'agente, mentre `--max-budget-usd` imposta il vero tetto economico basato sulla stima client-side.
# 1. Base: prompt, risultato su stdout, exit
claude -p "Elenca i file toccati piu' spesso negli ultimi 20 commit"
# 2. Output JSON: risultato + costo + session id
claude -p "Riassumi l'architettura del progetto" \
--output-format json
# 3. Con guardrail: permessi, turni e budget
claude -p "Cerca TODO e FIXME e raggruppali per area" \
--allowedTools "Read,Grep,Glob" \
--disallowedTools "Edit,Write" \
--permission-mode dontAsk \
--max-turns 5 \
--max-budget-usd 0.50Headless mode · docs ufficiali ↗
🧪 La review in locale, prima della CI
Prima di portare un prompt di review in un workflow, lo collaudo nel terminale. Il ciclo è corto: lancio lo script, leggo la review, correggo il prompt e rilancio. Il JSON mostra anche la stima `total_cost_usd`, utile per scegliere `--max-turns` e `--max-budget-usd`; per la spesa ufficiale controllo comunque la Usage page della Claude Console.
Lo script recupera il branch base, calcola il diff in modo deterministico e lo passa su stdin. Claude non ha quindi bisogno di eseguire `git diff`. `dontAsk` nega i tool non pre-approvati e `--disallowedTools` blocca la scrittura: la review produce solo il report. In CI applico lo stesso principio separando il workflow che commenta da quello che può modificare il codice.
#!/usr/bin/env bash
# Review headless del diff rispetto al branch di base.
set -euo pipefail
base="${1:-main}"
git fetch origin "${base}"
git diff "origin/${base}...HEAD" | claude --bare -p "Fai la code review
del diff ricevuto su stdin.
Per ogni rilievo indica: file, riga, severita' (alta/media/bassa),
problema e correzione proposta. Concentrati su bug, sicurezza,
performance. Ignora lo stile." \
--allowedTools "Read,Grep,Glob" \
--disallowedTools "Edit,Write" \
--permission-mode dontAsk \
--max-turns 10 \
--max-budget-usd 1.00 \
--output-format json⚙️ Setup: /install-github-app e i secret
Il ponte tra il repository e l'API di Anthropic si configura con un comando: apro `claude` nel repository e lancio /install-github-app. Il wizard guida l'installazione della GitHub App ufficiale, la registrazione del secret `ANTHROPIC_API_KEY` e la creazione del workflow; occorre essere amministratori del repository. In alternativa installo l'app da `github.com/apps/claude`, aggiungo il segreto nelle impostazioni Actions e creo il YAML a mano.
L'unico punto in cui vale la pena rallentare sono i permessi del workflow. Il template di review nasce prudente, con `pull-requests: read`: Claude legge la PR ma non può pubblicare il commento con la review. Per avere i rilievi direttamente sulla pull request serve alzare a write — ed è una scelta che faccio consapevolmente workflow per workflow, non un default globale del repo.
Il runner esegue lo stesso agent loop che uso in locale: checkout del repository, guardrail espliciti e commento finale via GitHub API.
🤖 Il workflow di review automatica
Il primo workflow parte automaticamente quando una pull request non draft viene aperta, aggiornata, riaperta o resa pronta per la review. Con un `prompt` esplicito, anthropics/claude-code-action@v1 entra in automation mode; `track_progress: true` garantisce un commento di avanzamento che conterrà anche il riepilogo finale, mentre i tool `gh pr` e l'MCP per i commenti inline permettono di pubblicare i rilievi sulla PR.
`contents: read` limita il codice a sola lettura, `pull-requests: write` consente i commenti e `id-token: write` serve alla GitHub App ufficiale. Un checkout shallow è sufficiente perché la action riceve il contesto della PR e usa `gh pr diff`; non serve scaricare tutta la cronologia. Il job esclude intenzionalmente i fork: i workflow `pull_request` avviati da fork non ricevono `ANTHROPIC_API_KEY` e il loro `GITHUB_TOKEN` resta in sola lettura.
name: Claude PR Review
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
concurrency:
group: claude-pr-review-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
review:
if: >
github.event.pull_request.draft == false &&
github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
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 }}
track_progress: true
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}
Fai la code review di questa pull request.
Per ogni rilievo: file, riga, severita' (alta/media/bassa),
problema, correzione proposta. Concentrati su bug,
sicurezza e performance. Ignora lo stile.
Usa gh pr comment per il riepilogo e il tool MCP
per i commenti inline, con confirmed: true.
claude_args: |
--max-turns 15
--max-budget-usd 1.00
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*)"
--disallowedTools "Edit,Write"anthropics/claude-code-action · GitHub ↗
💬 @claude nei commenti: la modalità interattiva
Il secondo workflow richiede una menzione esplicita. Scrivo `@claude come gestiresti la paginazione qui?` in un commento e l'agente risponde; con `@claude sistema la validazione di questo endpoint` può implementare la modifica e creare un commit sul branch della PR. Senza `prompt`, la action entra in modalità interattiva e applica il proprio controllo di accesso: per impostazione predefinita può attivarla solo un utente con permessi di scrittura sul repository.
Qui `contents: write` è necessario perché l'agente può creare commit. Tengo quindi i workflow separati: la review automatica ha codice in sola lettura, mentre quello interattivo ha poteri maggiori ma parte solo da una menzione autorizzata. Aggiungo anche `pull_request_review` per coprire le menzioni nel testo di una review, oltre ai commenti generali e inline.
name: Claude
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
pull_request_review:
types: [submitted]
jobs:
claude:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude'))
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
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 }}
claude_args: --max-turns 25 --max-budget-usd 2.00🎛️ claude_args: modello, permessi e turni
`claude_args` passa i flag della CLI alla action. Uso `--model` per scegliere il modello, `--max-turns` per limitare i round trip e `--max-budget-usd` per fermare il run quando la stima client-side raggiunge la soglia. `--allowedTools` pre-approva capacità specifiche; il confine effettivo nasce dalla combinazione con `--disallowedTools`, dalla modalità dei permessi e dal blocco `permissions` di GitHub.
Nella sintassi dei permessi, `Bash(git diff:)` autorizza i comandi che iniziano con `git diff`; la forma equivalente moderna è `Bash(git diff *)`. Senza il confine prima dell'asterisco, `Bash(git diff)` includerebbe anche `git diff-index`. Mantengo quindi pattern specifici e aggiungo soltanto i tool necessari al risultato atteso.
Ogni run produce un commento strutturato: severità, file:riga, problema e proposta. Il formato lo decide il prompt, non la action.
⚠️ Errori da evitare
Il primo errore è saltare il collaudo locale. Un prompt di review scritto direttamente nel YAML si itera a colpi di push e attese del runner; lo stesso prompt maturato con `claude -p` arriva in CI già stabile. Il secondo è trattare la review dell'agente come un verdetto: è un primo passaggio che pulisce i problemi meccanici — null check mancanti, edge case, query sospette — e libera la review umana per architettura e scelte di design. Chi approva la PR resta una persona.
Il terzo errore è economico: `--max-turns` limita la durata agentica, mentre `--max-budget-usd` imposta la soglia di costo stimata. Parto basso, osservo `total_cost_usd` e verifico la spesa ufficiale nella Claude Console. L'ultimo errore è di sicurezza: i secret non vengono passati ai workflow `pull_request` dei fork; non sostituisco questo limite con `pull_request_target` facendo checkout del codice non attendibile nel workspace principale.
- Collauda il prompt in locale con claude -p: iterare in CI costa minuti a tentativo, sul terminale secondi.
- Due workflow, due perimetri: review automatica in sola lettura; scrittura solo nel workflow @claude chiamato da un umano.
- Limita turni e budget: --max-turns controlla i round trip, --max-budget-usd la spesa stimata per run.
- Permessi minimi che funzionano: pull-requests: write serve per il commento; contents: write solo dove l'agente committa davvero.
- La review AI non approva: pulisce i problemi meccanici, ma il merge resta una decisione umana.
🧪 Verifica su una PR di prova
Prima di attivare il workflow su tutto il repository, apro una PR di prova nello stesso repository con un difetto deliberato e innocuo. Verifico che il run parta, che il commento venga pubblicato, che i rilievi inline abbiano file e riga corretti e che il job precedente venga cancellato dopo un nuovo push. Solo allora porto il workflow su `main`.
git switch -c test/claude-pr-review
# Introduci un difetto innocuo e committalo
git add .
git commit -m "test: exercise Claude PR review"
git push -u origin test/claude-pr-review
gh pr create --fill --base main
gh pr checks --watch✅ Checklist finale
Prima di dichiarare "attiva" la review automatica su un repo, ripasso sempre gli stessi sette punti. Sono la differenza tra un workflow che produce review utili e uno che genera rumore costoso — e ognuno di questi punti l'ho imparato sbagliandolo almeno una volta.
Se una voce non è verde, il workflow non va su `main`. Vale per i side project e vale doppio per i repo di lavoro, dove un run fuori controllo su venti PR aperte è una bolletta, non un esperimento.
[ ] Prompt di review collaudato in locale con claude -p
[ ] ANTHROPIC_API_KEY registrata come secret del repo
[ ] Workflow review: pull-requests: write, contents: read
[ ] Workflow @claude separato per le modifiche al codice
[ ] Tool gh/MCP necessari per pubblicare i commenti
[ ] --max-turns e --max-budget-usd calibrati
[ ] Policy same-repo/fork definita esplicitamenteDomande frequenti su Claude Code GitHub Actions
Cos'è la modalità headless di Claude Code?
È l'esecuzione non interattiva della CLI: con il flag -p (--print) Claude Code esegue lo stesso agent loop della sessione normale — legge file, lancia comandi, ragiona sul codice — ma stampa il risultato e esce, senza UI. È la base di ogni automazione: script locali, cron, CI/CD. L'output può essere testo semplice, JSON strutturato o stream di eventi JSON riga per riga.
Cosa fa claude-code-action rispetto a un normale bot di review?
La action ufficiale di Anthropic esegue nel runner GitHub Actions un agente basato sul Claude Agent SDK: può usare una shell vera, leggere i file del checkout e — nei workflow dove lo permetti — modificare codice e committare. Supporta gli argomenti della CLI di Claude Code e aggiunge contesto dell'evento GitHub, autenticazione e tool per i commenti.
Quanto costa la review automatica di una PR?
Dipende da modello, dimensione del diff e turni consumati. --max-turns limita i round trip, --max-budget-usd ferma il run quando raggiunge la soglia stimata e --model permette di scegliere un modello più economico. Il campo total_cost_usd del JSON è una stima client-side; per il dato ufficiale controllo la Usage page della Claude Console.
Perché separare il workflow di review da quello @claude?
Per il principio dei permessi minimi. La review automatica gira senza intervento umano sulle PR same-repository ammesse: le do contents: read e soltanto i tool necessari per ispezionare e commentare, così non può modificare il codice del repository. Il workflow @claude può scrivere codice e committare (contents: write), ma parte solo quando una persona autorizzata lo menziona esplicitamente. Automazione ampia con poteri piccoli, poteri grandi solo su richiesta umana.
La review di Claude sostituisce quella umana?
No, la anticipa. L'agente è bravo sui problemi meccanici — null check mancanti, edge case non gestiti, query N+1 e incoerenze col resto del codebase — e li segnala prima che un collega inizi la review manuale. La review umana resta necessaria per architettura, scelte di prodotto e contesto che non sta nel repo. Il merge lo approva sempre una persona.
Posso usare la action senza API key Anthropic diretta?
Sì. Con la Workload Identity Federation di Anthropic sostituisci la chiave statica con gli identificatori di federazione e id-token: write. Bedrock, Vertex AI e Microsoft Foundry richiedono invece input use_bedrock/use_vertex/use_foundry, autenticazione OIDC del provider, variabili e identificatori di modello specifici. Prompt e logica di review restano riutilizzabili, ma il workflow di autenticazione cambia.
Parliamone
Se questo tema ti riguarda, scrivimi: confrontarsi su codice e AI è sempre tempo speso bene.