Vai al contenuto
Parliamo del tuo progetto

31 Ottobre 2026

Hook, pre-commit e CI con gli agenti AI: dove mettere i controlli di qualità del codice

Lint, tipi e test sono il miglior alleato di un agente di coding, ma se li esegui nel momento sbagliato rallentano tutto. Ecco come distribuire i controlli di qualità tra hook, pre-commit, CI e post-merge.

Quando si inizia a lavorare con un agente di coding, la prima idea sui controlli di qualità del codice è quasi sempre la stessa: “facciamogli eseguire lint e test dopo ogni modifica, così si accorge subito degli errori”. In teoria è perfetto. In pratica l’agente rallenta, il contesto si riempie di output e spesso i controlli falliscono su stati intermedi che l’agente stava ancora sistemando.

Matt Pocock ha affrontato il tema nel video del 13 ottobre “STOP running your checks in harness hooks”, e la sua indicazione è controintuitiva solo in apparenza: non tutti i controlli vanno eseguiti a ogni modifica. Ogni controllo ha il suo momento giusto. I controlli di qualità del codice funzionano quando sono distribuiti su più livelli, dal più rapido al più completo.

In questa guida vediamo quali controlli mettere negli hook dell’agente, quali nel pre-commit, quali in CI e quali dopo il merge, con esempi di configurazione pronti da adattare.

Per un’azienda i controlli automatici sono la garanzia che la velocità degli agenti non si trasformi in errori davanti ai clienti. Sono anche il punto in cui si decide quanto rischio si accetta: cosa blocca un rilascio, chi può forzarlo, cosa viene verificato prima che un cliente veda una modifica.

In breve

  • I controlli si distribuiscono su quattro livelli: hook dell’agente, pre-commit, CI sulla pull request, verifiche dopo il merge.
  • Negli hook a ogni modifica vanno solo controlli istantanei e locali, come la formattazione del file modificato.
  • Il pre-commit è il punto naturale per lint, tipi e test veloci sui file toccati: l’agente fa commit quando pensa di aver finito.
  • La CI esegue la suite completa, i test end-to-end e i controlli costosi; i risultati tornano all’agente come errori da correggere.
  • Con molti agenti in parallelo servono test selettivi, cache e talvolta verifiche dopo il merge.
  • Un controllo che fallisce deve produrre un messaggio breve e azionabile, non mille righe di log.
  • Per chi decide: la pipeline dei controlli è la vera assicurazione dello sviluppo con agenti. Chiedi al team o al fornitore cosa blocca un rilascio e quanto tempo passa da una modifica alla sua verifica.

Perché il momento del controllo conta

Un controllo di qualità ha tre caratteristiche: quanto dura, quanto output produce e quanto è affidabile su codice incompleto. Un formattatore impiega millisecondi, produce poco output e funziona su qualsiasi file. Una suite end-to-end impiega minuti, può produrre migliaia di righe e fallisce se l’applicazione non è in uno stato coerente.

Un agente modifica spesso più file in sequenza per completare un cambiamento: prima il tipo, poi la funzione, poi il componente che la usa. Tra un passo e l’altro il codice è, legittimamente, incoerente. Se il type checker gira dopo la prima modifica, segnala errori che l’agente avrebbe risolto due passi dopo. L’agente si distrae, prova a correggerli subito, a volte cambia strategia. Il risultato è più lento e spesso peggiore.

È il punto centrale del video di Matt Pocock STOP running your checks in harness hooks: i controlli a ogni modifica di file creano rumore; i controlli al momento del commit arrivano quando l’agente ritiene il lavoro coerente. È un caso concreto del principio che abbiamo visto nella guida all’harness engineering: i sensori devono restituire segnali utili, al momento utile.

Cosa chiedere come azienda

Non serve conoscere lint e test runner per valutare se i controlli di un progetto sono adeguati. Bastano alcune domande e quattro indicatori.

Le domande

  • Una modifica può arrivare in produzione senza che i controlli automatici siano passati? Chi può forzarla, e resta traccia?
  • Le modifiche scritte dagli agenti passano dagli stessi controlli di quelle scritte dalle persone?
  • Quanto tempo passa tra una modifica e il risultato dei controlli?
  • Cosa viene verificato prima di ogni rilascio, oltre ai test automatici?
  • Per ogni rilascio, possiamo vedere quali controlli sono stati eseguiti e con quale esito?

Gli indicatori

Il programma di ricerca DORA ha individuato quattro indicatori che descrivono bene la capacità di un team di consegnare software: frequenza dei rilasci, tempo dalla modifica alla produzione, quota di rilasci che causano problemi, tempo per rimediare a un problema. Con gli agenti i primi due dovrebbero migliorare; i controlli servono a evitare che peggiorino gli altri due.

Costi da prevedere

Con più modifiche, la CI lavora di più. I minuti di esecuzione dei servizi di CI sono una voce di costo che cresce con l’adozione degli agenti, insieme ai token. Vanno messi a budget, e ottimizzati con le tecniche descritte in questo articolo.

Evidenze per clienti e certificazioni

Un registro dei controlli eseguiti su ogni rilascio è utile anche fuori dal team di sviluppo: risponde alle richieste dei clienti più strutturati sui processi di qualità e fornisce evidenze per certificazioni come la ISO/IEC 27001.

I quattro livelli dei controlli

Livello Quando Durata tipica Controlli adatti
1. Hook dell’agente Dopo ogni modifica o a fine turno Meno di 2 secondi a modifica Formattazione del file modificato, controlli di sicurezza sui comandi
2. Pre-commit A ogni commit Meno di 30-60 secondi Lint e tipi sui file toccati, test unitari correlati, ricerca di segreti
3. CI sulla pull request A ogni push o pull request Pochi minuti Suite completa, build, test di integrazione ed end-to-end, analisi statica
4. Dopo il merge Sul ramo principale o prima del rilascio Variabile Test lenti, prestazioni, verifiche su staging, mutation testing completo

La regola generale: più un controllo è veloce e locale, più può stare vicino all’agente. Più è lento e globale, più va spostato verso la CI o dopo il merge.

Livello 1: gli hook dell’agente

Gli hook sono comandi che l’agente esegue automaticamente in momenti precisi del suo ciclo. In Claude Code si configurano in settings.json; la guida agli hook mostra gli eventi disponibili, tra cui prima e dopo l’uso di uno strumento e alla fine del turno.

Cosa mettere dopo ogni modifica

Solo controlli istantanei che lavorano sul singolo file e non dipendono dal resto del codice. Il caso tipico è la formattazione: formatta il file appena modificato e non restituisce errori, se non in casi eccezionali.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs -I{} npx biome format --write {} 2>/dev/null || true"
          }
        ]
      }
    ]
  }
}

Formattatori veloci come Biome per JavaScript e TypeScript o Ruff per Python sono ideali perché impiegano millisecondi.

Cosa mettere prima dell’esecuzione dei comandi

Controlli di sicurezza: bloccare comandi distruttivi o che toccano credenziali. Ne abbiamo parlato nella guida alla sicurezza degli agenti AI. Anche qui la regola è la velocità: un filtro su stringhe, non un’analisi complessa.

Cosa mettere a fine turno

L’evento di fine turno (in Claude Code si chiama Stop) è un buon compromesso: l’agente ha finito di lavorare e ritiene il codice coerente. Qui ha senso un controllo rapido di tipi e lint sui file modificati. Se fallisce, l’hook può restituire l’errore all’agente e chiedergli di correggere prima di dichiarare il lavoro concluso. Va però usato con prudenza: se il controllo dura un minuto, ogni risposta dell’agente durerà un minuto in più.

Cosa non mettere negli hook

  • la suite di test completa;
  • la build dell’intera applicazione;
  • test end-to-end;
  • qualsiasi controllo che produce output lunghi.

Livello 2: il pre-commit

Il pre-commit è il momento in cui l’agente, o la persona, dichiara “questa modifica è pronta”. È il punto naturale per i controlli di media durata. Se falliscono, il commit non avviene e l’agente riceve l’errore: un segnale chiaro, al momento giusto.

Gli strumenti più usati sono pre-commit (multi-linguaggio, molto diffuso in Python), Husky con lint-staged nel mondo JavaScript, e Lefthook, veloce e con esecuzione parallela. Un esempio con Lefthook per un progetto TypeScript:

# lefthook.yml
pre-commit:
  parallel: true
  commands:
    lint:
      glob: "*.{ts,tsx}"
      run: npx eslint --max-warnings=0 {staged_files}
    types:
      run: npx tsc --noEmit --incremental
    test:
      glob: "*.{ts,tsx}"
      run: npx vitest related --run {staged_files}
    secrets:
      run: npx secretlint {staged_files}

Tre accorgimenti rendono il pre-commit sostenibile:

  • Solo i file in commit: lint e ricerca di segreti sui file modificati, non su tutto il progetto.
  • Test correlati: Vitest con il comando related esegue solo i test che dipendono dai file modificati; Jest offre opzioni simili.
  • Type checking incrementale: il flag --incremental di TypeScript, e i project references nei progetti grandi, riducono molto i tempi.

Un dettaglio importante per gli agenti: istruiscili a non saltare i controlli. Un agente che riceve un errore dal pre-commit può essere tentato di usare git commit --no-verify. Va vietato esplicitamente nel file di istruzioni del progetto e, se l’agente lo permette, bloccato con un hook sui comandi.

Livello 3: la CI sulla pull request

La CI è il controllo completo e affidabile, eseguito in un ambiente pulito. Qui vanno la suite di test intera, la build, i test di integrazione ed end-to-end, l’analisi statica di sicurezza, i controlli di accessibilità e prestazioni quando servono.

# .github/workflows/ci.yml (estratto)
name: CI
on: [pull_request]
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22, cache: pnpm }
      - run: pnpm install --frozen-lockfile
      - run: pnpm lint
      - run: pnpm typecheck
      - run: pnpm test -- --reporter=dot
      - run: pnpm build
  e2e:
    needs: check
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pnpm install --frozen-lockfile && pnpm exec playwright install --with-deps
      - run: pnpm test:e2e

Due aspetti diventano critici quando gli agenti producono molte pull request.

Velocità

Una CI da venti minuti va bene per pochi merge al giorno, non per decine. Le leve principali sono la cache delle dipendenze e delle build, l’esecuzione in parallelo e i test selettivi: strumenti come Nx affected o Turborepo eseguono solo i progetti toccati dalla modifica in un monorepo.

Output utilizzabile dall’agente

Quando la CI fallisce, l’agente deve poter leggere l’errore e correggerlo. Reporter compatti (solo i test falliti, con le prime righe dell’errore) aiutano molto. Alcuni team aggiungono un passaggio che riassume il fallimento in un commento sulla pull request, così l’agente lo trova senza scorrere i log.

Livello 4: dopo il merge

Alcuni controlli sono troppo lenti o costosi per ogni pull request: test di prestazioni, test su più browser e dispositivi, mutation testing completo, verifiche su un ambiente di staging con dati realistici. Vanno eseguiti sul ramo principale dopo il merge, prima del rilascio o con cadenza notturna.

A volumi molto alti, anche alcuni controlli normalmente pre-merge si spostano qui. Anthropic racconta nel post Redesigning source control che con decine di migliaia di merge al giorno una coda di merge tradizionale con un blocco globale non regge più, e che si affida a test automatici dopo il merge e prima del deploy. È una scelta che ha senso solo con un’ottima capacità di rilevare e annullare rapidamente le regressioni.

Per la maggior parte dei team il compromesso giusto è una merge queue: le pull request approvate entrano in coda, vengono testate insieme alle modifiche che le precedono e unite solo se tutto passa. Evita che due modifiche corrette singolarmente rompano il ramo principale una volta combinate, un rischio che cresce con molti agenti in parallelo.

Quale controllo dove: una mappa pratica

Controllo Hook Pre-commit CI Dopo il merge
Formattazione Sì Sì Verifica No
Blocco comandi pericolosi Sì No No No
Lint No Sui file modificati Completo No
Tipi A fine turno, se veloce Incrementale Completo No
Test unitari No Correlati Completi No
Ricerca di segreti No Sì Sì No
Build No No Sì No
Test end-to-end No No Principali Completi
Analisi di sicurezza No No Sì Periodica
Prestazioni e mutation testing completo No No Mirati Sì

Per il mutation testing, che merita un discorso a parte, rimandiamo alla guida al mutation testing con gli agenti AI.

Il percorso di una modifica, livello per livello

Per rendere concreta la distribuzione dei controlli, seguiamo una modifica tipica: l’agente deve aggiungere un campo “note interne” agli ordini, visibile solo agli amministratori.

L’agente modifica lo schema del database, il tipo dell’ordine, l’endpoint e il componente della pagina. A ogni file salvato, l’hook lo formatta in pochi millisecondi: nessun output, nessuna interruzione. Durante questi passi il type checker segnalerebbe errori, perché il componente usa un campo che il tipo non ha ancora: per fortuna non gira, e l’agente completa la sequenza senza distrazioni.

A fine turno l’agente esegue i controlli rapidi e fa commit. Il pre-commit lancia lint e tipi sui quattro file modificati e i test correlati. Il lint segnala un import diretto del client del database nel componente, vietato da una regola del progetto con un messaggio chiaro su dove importare. L’agente corregge e il commit passa in una ventina di secondi.

L’agente apre la pull request. La CI esegue la suite completa e la build, poi i test end-to-end principali. Un test end-to-end fallisce: la pagina degli ordini per gli utenti non amministratori ora mostra un’etichetta vuota. Il reporter compatto indica il test, il passo e la differenza attesa. L’agente legge il fallimento nel commento sulla pull request, corregge la condizione di visibilità e rilancia. Verde.

Dopo la revisione umana la modifica entra nella merge queue, viene testata insieme a due altre pull request in coda e unita. Di notte, i test più lenti sul ramo principale confermano che nulla si è rotto.

Nessun livello ha fatto tutto il lavoro, e nessun controllo è stato eseguito nel momento sbagliato. È questo l’obiettivo: ogni errore scoperto il prima possibile, ma non prima che abbia senso cercarlo.

Messaggi di errore pensati per l’agente

Un controllo è utile solo se l’agente capisce cosa correggere. Alcuni principi:

  • Breve: file, riga, regola violata, una frase di spiegazione. Non lo stack trace completo.
  • Azionabile: se esiste una correzione standard, indicarla. “Importa da @/server/repo invece che da prisma direttamente” è meglio di “import non consentito”.
  • Stabile: lo stesso errore produce lo stesso messaggio, così l’agente (e le persone) imparano a riconoscerlo.
  • Silenzioso quando va tutto bene: un controllo che passa non deve produrre output. Ogni riga è contesto consumato, come abbiamo visto nella guida al consumo di token.

Le regole di lint personalizzate sono particolarmente efficaci: trasformano una convenzione del progetto in un errore preciso con un messaggio scritto da voi.

Errori comuni

Suite completa a ogni modifica

È l’errore descritto da Matt Pocock: rallenta l’agente, riempie il contesto e genera falsi allarmi su stati intermedi.

Pre-commit troppo lento

Se il pre-commit dura cinque minuti, le persone lo disattivano e gli agenti cercano di aggirarlo. Sopra il minuto, sposta qualcosa in CI.

Controlli diversi in locale e in CI

Se il lint locale e quello della CI usano configurazioni diverse, l’agente passa il pre-commit e fallisce in CI. Una sola configurazione, versionata.

Permettere di saltare i controlli

Un agente che usa --no-verify per completare il task ha rispettato la lettera della richiesta, non lo spirito. Vietalo esplicitamente.

Output enormi

Reporter verbosi in CI rendono difficile per l’agente trovare l’errore e consumano contesto. Configura reporter compatti per i passaggi letti dagli agenti.

Nessuna CI sulle pull request degli agenti

Alcuni team eseguono la CI solo sulle pull request umane. Le modifiche degli agenti richiedono gli stessi controlli, se non di più.

Portarlo in produzione nel team

  • Configurazione nel repository: hook dell’agente, pre-commit e workflow di CI versionati insieme al codice, uguali per tutti.
  • Tempi monitorati: misura la durata di pre-commit e CI e fissa un budget (per esempio 60 secondi e 10 minuti). Quando lo superi, ottimizza o sposta.
  • Rami protetti: nessun merge senza CI verde, nessuna eccezione per gli agenti.
  • Merge queue quando più agenti o persone lavorano in parallelo sullo stesso ramo principale.
  • Revisione periodica delle regole: quelle che non trovano mai nulla vanno riconsiderate, quelle che falliscono spesso vanno spiegate meglio.

I controlli del tuo progetto rallentano il lavoro invece di proteggerlo? Come partner tecnico rivediamo pipeline, hook e configurazioni per team che lavorano con gli agenti, e nello sviluppo di web app impostiamo la qualità fin dal primo commit.

Da dove partire questa settimana

  1. Elenca i controlli che oggi esegui e annota la durata di ciascuno.
  2. Togli dagli hook dell’agente tutto ciò che non è istantaneo; lascia formattazione e blocchi di sicurezza.
  3. Configura un pre-commit con lint e test correlati sui soli file modificati, sotto il minuto.
  4. Verifica che la CI giri su tutte le pull request, comprese quelle degli agenti, con reporter compatti.
  5. Aggiungi al file di istruzioni il divieto di saltare i controlli e misura per una settimana quante volte l’agente li supera al primo tentativo.

Checklist dei controlli di qualità

  • Gli hook a ogni modifica eseguono solo controlli istantanei.
  • Il pre-commit dura meno di un minuto e lavora sui file modificati.
  • I test eseguiti nel pre-commit sono solo quelli correlati alle modifiche.
  • La CI esegue suite completa, build ed end-to-end principali su ogni pull request.
  • La configurazione di lint e test è la stessa in locale e in CI.
  • I messaggi di errore sono brevi, stabili e azionabili.
  • Gli agenti non possono saltare i controlli.
  • Il ramo principale è protetto da CI obbligatoria.
  • Con molte modifiche in parallelo è attiva una merge queue.
  • I controlli lenti girano dopo il merge o con cadenza notturna.

Domande frequenti

Perché non eseguire i test dopo ogni modifica dell’agente?

Perché l’agente modifica spesso più file in sequenza e tra un passo e l’altro il codice è legittimamente incoerente. I test falliscono su stati intermedi, l’agente si distrae a correggerli e il contesto si riempie di output. Meglio eseguirli quando l’agente ritiene il lavoro completo, al commit o a fine turno.

Meglio Husky, Lefthook o pre-commit?

Dipende dallo stack. Husky con lint-staged è il più diffuso nei progetti JavaScript, Lefthook è veloce ed esegue i comandi in parallelo, pre-commit è lo standard nei progetti Python e multi-linguaggio. Conta più la configurazione che lo strumento: pochi controlli, veloci, sui file modificati.

Quanto deve durare il pre-commit?

Idealmente meno di 30 secondi, al massimo un minuto. Oltre questa soglia le persone tendono a disattivarlo e gli agenti a cercare di aggirarlo. I controlli più lenti vanno spostati in CI.

Come impedisco all’agente di saltare i controlli?

Scrivi il divieto nel file di istruzioni del progetto e, se l’agente lo supporta, aggiungi un hook che blocca i comandi con --no-verify. Proteggi comunque il ramo principale con una CI obbligatoria, così un controllo saltato in locale viene intercettato prima del merge.

Serve una merge queue?

Quando più persone o agenti fanno merge frequenti sullo stesso ramo, sì. La merge queue testa ogni modifica insieme a quelle che la precedono e impedisce che due modifiche corrette singolarmente rompano il ramo principale quando vengono combinate.

Cosa fare se la CI è troppo lenta per i volumi degli agenti?

Usa cache per dipendenze e build, esegui i job in parallelo, attiva i test selettivi sui progetti toccati e sposta i controlli più lenti dopo il merge. Misura la durata e fissa un budget: è la metrica che più di tutte limita la velocità di una software factory.

Quali indicatori usare per capire se lo sviluppo con agenti funziona?

I quattro indicatori DORA sono un buon punto di partenza: frequenza dei rilasci, tempo dalla modifica alla produzione, quota di rilasci con problemi e tempo di ripristino. Se gli agenti aumentano frequenza e velocità senza peggiorare gli altri due, l’adozione sta funzionando.

Fonti e approfondimenti

Vuoi una pipeline che tenga il passo dei tuoi agenti? Parliamo del tuo progetto: partiamo da tempi e risultati dei controlli di oggi.