Giacomo Mantovani

Articolo · 14 ottobre 2026 · Di Giacomo Mantovani

Gli errori più comuni con Claude Code (e come li ho eliminati dal mio flusso)

Dieci errori con Claude Code che ho fatto o visto nei miei repository, e la regola, l'hook o la review che oggi li ferma prima di main.

  • claude-code
  • agenti-ai
  • sviluppo-software
  • hook
  • code-review
Non fidarti del "fatto". Review prima del merge. Regola, Script, Gate, Hook, Review.

Uso Claude Code ogni giorno, sui progetti dei clienti e su questo sito. Nei primi mesi quasi nessun problema veniva da codice sbagliato. Veniva dall'agente che faceva una cosa sensata nel posto sbagliato: modificava la cartella in cui stavo lavorando io, faceva push sul ramo che va in produzione, apriva un file che non doveva leggere. Qui sotto ci sono i dieci errori che ho incontrato più spesso e il meccanismo che oggi li impedisce. Ogni correzione è una riga in un CLAUDE.md, un hook o un passaggio di review che gira già nei miei repository.

Quali errori con Claude Code fanno perdere più tempo?

La tabella riassume. Le sezioni successive spiegano ogni riga con la regola o la configurazione reale.

Errori comuni con Claude Code: sintomo e correzione
ErroreSintomoCorrezione
L'agente modifica la copia principaleLe tue modifiche e quelle dell'agente si mescolanoRegola: aprire un worktree prima di toccare file
Worktree orfaniCartelle e branch vecchi si accumulanoWorktree presi in prestito da un tool e restituiti
Attesa con pgrep -fIl ciclo non finisce maiComando in background o pattern con parentesi quadre
Niente testCodice "finito" che si rompe alla modifica dopoRegola TDD: prima il test che fallisce
Errori di tipo nascostiLa build passa, i tipi sono rottiTypecheck obbligatorio prima del merge
Documentazione vecchiaI documenti descrivono codice che non esiste piùSolo stato attuale, mappa aggiornata nello stesso diff
L'agente legge segretiIl contenuto del .env finisce nella conversazioneHook PreToolUse che nega il comando
Codice sovra-ingegnerizzatoAstrazioni che nessuno ha chiestoRegole YAGNI caricate a ogni sessione
PR o push non volutiPR aperte o main aggiornato al momento sbagliatoRegole di consegna esplicite per repository
Fidarsi del "fatto"Bug scoperti dopo il mergeAgenti di review e controlli prima del merge

Perché un agente non deve mai lavorare nella copia principale del repository?

Se Claude Code modifica la cartella in cui stai lavorando, le sue modifiche e le tue finiscono nello stesso albero. Non sai più cosa ha cambiato chi, un git stash si porta via tutto, e due agenti in parallelo si sovrascrivono. Il git worktree risolve il problema: è una copia separata su un proprio branch, con la stessa storia del repository. La documentazione ufficiale sui worktree descrive il flag --worktree e spiega che, in una sessione isolata, Claude Code blocca modifiche e comandi git diretti alla copia principale.

Nel mio CLAUDE.md globale questa è la regola di partenza: se il compito modifica file in un repository, si apre prima un worktree, e da lì si legge e si scrive solo dentro il worktree. La regola è una lista in ordine di priorità, così l'agente non deve scegliere da solo quale meccanismo usare.

Da dove vengono i worktree orfani e come si evitano?

L'isolamento porta il suo disordine. Secondo la documentazione di Claude Code, il worktree di un subagente che contiene modifiche resta su disco finché una pulizia periodica non può rimuoverlo senza perdere lavoro, e le esecuzioni non interattive con -p non hanno il prompt di uscita, quindi i loro worktree non vengono puliti. Dopo qualche settimana di agenti in parallelo avevo cartelle in .claude/worktrees/ di cui nessuno si ricordava.

La mia soluzione è togliere la creazione dei worktree agli strumenti interni dell'agente. Il CLAUDE.md globale vieta EnterWorktree e i subagenti con isolation: "worktree", che nel mio caso erano proprio quelli che lasciavano orfani. L'agente prende invece un worktree in prestito da una piccola CLI, ci lavora con percorsi assoluti e lo restituisce alla fine. Un prestito per ogni subagente. Un worktree restituito viene pulito; uno ancora in prestito ha un proprietario visibile.

path=$(treehouse get --lease --lease-holder claude)
# ... lavoro dentro "$path" ...
treehouse return "$path"

Perché il ciclo di attesa con pgrep non finisce mai?

Gli agenti aspettano volentieri una build o un server con un ciclo come until ! pgrep -f "next build"; do sleep 1; done. Con -f, pgrep confronta l'intera riga di comando, e la shell che esegue il ciclo contiene "next build" nella sua riga di comando. Il ciclo trova sé stesso e aspetta all'infinito, consumando il tempo della sessione.

La regola che ho aggiunto è breve: mai aspettare un processo con pgrep -f dentro un comando Bash. Si lancia il comando lungo in background e si aspetta la notifica, si usa wait <pid>, oppure un pattern che non può trovare il proprio testo. Il trucco delle parentesi quadre funziona perché la regex [n]ext build trova "next build", mentre nel comando la stringa letterale è "[n]ext build".

# non finisce: la shell trova sé stessa
until ! pgrep -f "next build"; do sleep 1; done

# funziona: il pattern non coincide con la propria riga di comando
until ! pgrep -f "[n]ext build"; do sleep 1; done

Come si ottiene che Claude Code scriva sempre i test?

Se chiedi a un agente una funzionalità, ti consegna la funzionalità. I test arrivano dopo o non arrivano, e la modifica successiva rompe la prima senza che nessuno se ne accorga. Nel CLAUDE.md di questo sito la prima regola è il TDD, non negoziabile: prima un test che fallisce, poi il codice, e nessuna modifica è completa senza test. Due skill, tdd e testing, dicono all'agente in quale livello va il test e come lanciarlo con pnpm test.

Partire dal test cambia anche la discussione con l'agente. Se non riesce a scrivere un test che fallisce, di solito non ha ancora capito il requisito, e lo scopri prima che esista una riga di codice.

Perché una build verde può nascondere errori di tipo?

La configurazione Next.js di questo sito imposta typescript.ignoreBuildErrors: true. I deploy non si bloccano, ma pnpm build riesce anche con i tipi rotti. Un agente che controlla solo la build dichiara successo. Il repository lo scrive in tre punti: nel CLAUDE.md ("gli errori di tipo non fanno fallire la build, lancia pnpm typecheck"), nella guida al flusso di lavoro e nella configurazione di consegna, dove il typecheck è obbligatorio proprio perché next build ignora i tipi. Qualsiasi progetto con una scorciatoia simile ha bisogno dello stesso controllo esplicito, altrimenti l'agente non ha modo di sapere che la build mente.

Come si evita che la documentazione invecchi quando l'agente cambia il codice?

Gli agenti scrivono documentazione volentieri e la cancellano malvolentieri. Mi sono servite due regole. La prima: la documentazione descrive solo lo stato attuale; quando il comportamento cambia, il vecchio testo si aggiorna o si cancella nello stesso diff, e la storia resta a git. La seconda: il repository ha una mappa del codice, schede brevi che citano path::symbol, e aggiornare le schede toccate fa parte del diff, non di un compito successivo.

In fase di consegna un agente dedicato alla documentazione parte dopo che il codice è definitivo, legge cosa ha cambiato davvero il diff e aggiorna mappa e documenti per gli agenti. È l'unico agente del processo con permessi di scrittura, quindi nemmeno i revisori possono far deragliare i documenti.

Come si impedisce a Claude Code di leggere i file .env?

Nella guida al flusso c'è la regola "leggi solo .env.example", ma una regola scritta resta una richiesta. Per un'azienda italiana un .env con le credenziali del database clienti letto da un agente è anche un tema GDPR, quindi serve un blocco vero. Il riferimento sugli hook spiega che un hook PreToolUse riceve l'input del tool in JSON su stdin e può restituire permissionDecision con valore deny e una motivazione, fermando la chiamata.

Nelle mie impostazioni utente c'è un hook PreToolUse sui tool Bash e PowerShell. Legge il comando da tool_input, cerca qualsiasi nome di file .env, lascia passare solo i modelli come .env.example, .env.sample, .env.template e .env.dist, e nega tutto il resto con un messaggio che rimanda l'agente al file di esempio. L'uscita ha questa forma:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Accesso via shell a .env.local bloccato: usa .env.example."
  }
}

Il matcher copre solo i comandi di shell, quindi la regola scritta serve ancora per gli altri tool che leggono file. Le due cose lavorano insieme: la regola spiega il perché, l'hook interviene quando l'agente se ne dimentica.

Come si evita che un agente AI complichi il codice più del necessario?

Chiedi una cache e rischi di ricevere una classe, un'interfaccia, un file di configurazione e una factory. Ogni pezzo sembra difendibile, ma insieme triplicano il diff da revisionare. In ogni sessione carico un insieme di regole da sviluppatore pigro: chiedersi se la cosa deve esistere, riusare quello che c'è già nel codice, preferire la libreria standard e le funzioni native della piattaforma, non aggiungere dipendenze per ciò che si fa in poche righe, scrivere il diff più piccolo che funziona. Le scorciatoie con un limite noto ricevono un commento che lo nomina, così si ritrovano in seguito. Gli standard del repository spingono nella stessa direzione: prima si riusano i componenti UI esistenti, poi semmai se ne scrive uno nuovo.

Come si impedisce a Claude Code di aprire PR o fare push su main?

Quasi tutti gli strumenti per agenti presuppongono un flusso a pull request. Questo sito non ce l'ha: Vercel pubblica main, e la consegna unisce il branch di lavoro direttamente. Il repository lo dice chiaro nel CLAUDE.md e lo ripete nella configurazione di consegna: mai aprire una PR, nessun comando gh pr. Il push è permesso solo con tutti i controlli verdi, dopo un rebase su origin/main. Un conflitto o un push rifiutato vuol dire fermarsi e chiedere, e il force push su main non è mai ammesso. Le regole globali aggiungono che l'agente fa commit o push solo su richiesta.

Per qualsiasi team vale lo stesso: scrivere il percorso di consegna di ogni repository, comprese le cose che l'agente non deve fare. Un agente non può rispettare una convenzione che non ha mai letto.

Perché non ci si può fidare quando l'agente dice che ha finito?

Quando un agente dice "fatto", vuol dire che si è fermato. Non vuol dire che i test possano fallire, che nulla sia stato indebolito o che il diff rispetti gli standard. Il mio passaggio /ship lancia agenti di review in parallelo su ogni diff prima del merge: un revisore generalista e uno dedicato ai test, che verifica se i test sono veritieri, se possono fallire davvero e se qualcuno li ha modificati o cancellati senza autorizzazione. Anche gli standard di codice vengono controllati su ogni diff. Lint, typecheck e test fanno da cancello. Se dopo i giri di correzione resta aperto qualcosa di bloccante, non si unisce nulla: l'agente riporta i problemi con un piano di correzione e chiede.

È il passaggio che cattura quello che sfugge alle altre nove correzioni. Costa qualche minuto per modifica, meno di un bug trovato in produzione.

Quali errori si fanno quando si introducono queste protezioni?

Il primo è scrivere regole senza un blocco per le cose rischiose: segreti e deploy vogliono hook o permessi. Il secondo è scrivere regole vaghe ("stai attento con git"); ogni regola nei miei file nomina un comando, un file o un flag. Il terzo è mettere tutto in un unico prompt enorme. Le regole globali stanno nel CLAUDE.md utente, quelle del progetto nel CLAUDE.md del repository, e i dettagli in documenti e skill collegati che l'agente apre quando servono. L'ultimo è non rivedere mai l'elenco. Ogni regola di questo articolo esiste perché l'agente ha sbagliato almeno una volta.

Prossimo passo

Vuoi questa configurazione nei repository del tuo team?

Aiuto i team a far lavorare gli agenti di programmazione AI con regole, hook e review che li tengono lontani dai guai in produzione.

Parliamone

Per agenti AI oltre agli assistenti di programmazione, vedi il mio servizio di sviluppo agenti AI.

Domande frequenti

Una regola nel CLAUDE.md garantisce che l'agente la rispetti?

No. Claude Code carica il CLAUDE.md come contesto e il modello di solito lo segue, ma niente lo obbliga. Per le azioni che non devono mai succedere, come leggere segreti o lanciare comandi distruttivi, serve un hook PreToolUse o una regola di permesso.

I worktree di Claude Code si puliscono da soli?

In parte. Secondo la documentazione di Claude Code, una sessione interattiva in un worktree chiede cosa fare all'uscita, il worktree pulito di un subagente viene rimosso quando il subagente finisce, e quelli con modifiche aspettano una pulizia periodica. I worktree delle esecuzioni con -p non vengono puliti: vanno rimossi con git worktree remove.

Un hook può bloccare anche il tool Read, oltre a Bash?

Sì. Il matcher di un hook PreToolUse decide su quali tool gira, quindi lo stesso controllo si può registrare anche sui tool che leggono file. Il mio hook copre i comandi di shell; per il resto vale la regola scritta.

Il TDD con un agente rallenta il lavoro?

Ogni modifica richiede un po' più di tempo. In cambio il test esiste prima del codice, l'agente ha un obiettivo chiaro e le modifiche successive non rompono in silenzio quelle precedenti.

Autore

Giacomo Mantovani

AI Engineer e Consulente AI per Aziende e Agenzie

LinkedInGitHub

Prossimo passo

Raccontami il processo. Lo definiamo in una call gratuita, poi una versione funzionante è operativa entro 10 giorni.

Prenota una call di analisi

Articoli correlati