Hook Claude Code non parte: guida al debug
Diagnostica un hook Claude Code che non parte: settings caricati, matcher, input JSON, timeout e policy. Prove locali e casi di errore riproducibili.
Tempo di lettura: 11 min

Per fare debug di un hook Claude Code che non parte, verifica nell’ordine configurazione caricata, evento, matcher, avvio dell’handler, input e output. “Non vedo l’effetto” può significare che la registrazione manca, che il filtro esclude la chiamata o che il comando parte ma fallisce. Cambiare tutti questi elementi insieme impedisce di sapere quale fosse il problema. Debug Hooks nella reference ufficiale.
Il primo strumento è /hooks, che mostra i controlli disponibili nella sessione. Poi serve una prova con dati sintetici per il singolo passaggio sospetto. Un messaggio nel log e un blocco della tool call sono prove differenti; un errore tecnico non è automaticamente una decisione della policy. Se devi ancora scegliere il meccanismo, leggi la guida ai Claude Code Hooks.
Le fonti sono state verificate il 9 ottobre 2026. Le fixture proposte sono esempi didattici non eseguiti in questa guida. Il percorso non richiede copiare transcript di clienti, segreti o variabili ambiente complete.
In sintesi
- Prima controlla se la registrazione è visibile nella sessione.
- Il matcher va verificato sul campo dell’evento corretto.
- Prova lo script direttamente con un JSON sintetico.
- Separa stdout, stderr ed exit code durante la diagnosi.
- Osserva anche l’effetto sul tool, non soltanto il messaggio di errore.
Il hook è caricato dal file che hai modificato?
I settings possono provenire da scope utente, progetto, locale e amministrativo. Il file aperto nell’editor non è necessariamente l’unica fonte della configurazione. Alcune liste si uniscono fra livelli, mentre valori scalari seguono una precedenza. Una copia del hook in un altro scope può produrre un effetto che sembra venire dalla modifica appena fatta. Settings di Claude Code.
Apri /hooks e controlla evento, matcher e handler. Se la registrazione non compare, leggi gli errori di parsing e verifica il file effettivamente usato. /status e claude doctor possono aiutare a individuare configurazioni scartate o problemi dell’ambiente. Non cambiare lo script finché non hai un motivo per pensare che venga chiamato.
Un JSON non valido è diverso da un JSON valido con chiavi sbagliate. Il parser può leggere il file ma Claude Code può non accettare la struttura. Mantieni il blocco hooks nel contenitore previsto e conserva gli altri settings. Due proprietà uguali nel medesimo oggetto rendono la lettura del file ambigua e possono nascondere la registrazione desiderata.
È l’evento giusto per il risultato che cerchi?
Un formatter dopo un edit appartiene a un percorso successivo all’azione. Una regola che deve impedire l’edit appartiene a un controllo precedente. La fine di una risposta riguarda Stop; una richiesta di attenzione può riguardare Notification. Prima di cercare un errore di codice, descrivi il fatto che dovrebbe attivare l’automazione. Lifecycle dei Hooks.
Se la chiamata al tool fallisce, PostToolUse non è il medesimo evento di PostToolUseFailure. Se un programma shell modifica un file, il matcher Edit|Write non vede automaticamente quella chiamata Bash. Queste differenze possono spiegare un hook silenzioso senza che esista un guasto del runtime.
Consulta PostToolUse per formatter e test per i controlli successivi e PreToolUse per file protetti per i controlli preventivi. La diagnosi diventa più rapida quando il requisito e il momento coincidono.
Il matcher include esattamente il caso previsto?
La reference corrente distingue nomi semplici, liste di nomi e regex. Un valore come Edit|Write è una lista di nomi esatti; metacaratteri diversi possono portare a una regex JavaScript non ancorata. Un pattern come Edit.* può includere valori che contengono Edit senza coincidere con quel tool. Se vuoi una corrispondenza completa, rendi espliciti gli ancoraggi. Matcher patterns.
Verifica il campo filtrato. Nei tool event è il nome del tool; per SessionStart è il motivo di avvio; per Notification il tipo di notifica. Usare un nome di file nel matcher PreToolUse non è un filtro sul percorso dell’input. Il controllo del percorso appartiene alla logica successiva o a campi di condizione supportati.
Prepara un caso incluso, uno escluso e uno dal nome simile. Non allargare subito il matcher a tutto per far vedere un risultato: la prova potrebbe funzionare e lasciare una configurazione troppo ampia. Se devi temporaneamente osservare più eventi in un ambiente sintetico, ripristina poi il perimetro previsto e ripeti il caso negativo.
Come provare lo script senza Claude Code?
Un handler command riceve JSON sullo standard input. Puoi simulare questo passaggio con una fixture locale che contiene soltanto i campi utili. Lo script seguente verifica che l’input sia un oggetto, stampa una categoria diagnostica su stderr e restituisce un JSON vuoto su stdout. È un esempio non eseguito, non un controllo di sicurezza. Input e output.
import json
import sys
try:
event = json.load(sys.stdin)
if not isinstance(event, dict):
raise ValueError("oggetto richiesto")
name = event.get("hook_event_name", "evento-assente")
allowed = {"PreToolUse", "PostToolUse", "Stop", "Notification"}
label = name if name in allowed else "evento-non-previsto"
print("Diagnosi hook: " + label, file=sys.stderr)
print("{}")
except (ValueError, TypeError):
print("Diagnosi hook: input non valido", file=sys.stderr)
sys.exit(1)
Una fixture minima può essere salvata come hook-input-demo.json nel repository di prova. Non riutilizzare un input reale contenente codice o informazioni del cliente soltanto per risparmiare la scrittura di pochi campi.
{
"hook_event_name": "PreToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "demo/example.txt"
}
}
La chiamata diretta usa la redirezione del file: python3 inspect_hook.py < hook-input-demo.json. Se fallisce qui, il problema non è il matcher di Claude Code. Se riesce, hai provato solo input e runtime; restano registrazione, percorso d’avvio e contratto del risultato nella sessione.
Perché stdout e stderr devono rimanere separati?
Stdout può essere interpretato come risposta del hook. Una riga di log prima del JSON può rompere il formato oppure cambiarne il significato. Stderr è il luogo adatto per un messaggio tecnico breve, secondo il comportamento documentato per l’evento e il codice di uscita. L’exit code resta un terzo dato distinto. Exit code output.
Non leggere “nessun errore stampato” come prova di successo. Lo script potrebbe aver saltato un caso perché mancava il campo o perché il percorso non era incluso. Definisci cosa deve produrre ciascuna fixture: JSON, nessuna decisione, esito negativo oppure errore tecnico. La tabella delle prove rende leggibili anche i rami silenziosi.
Per controlli preventivi, osserva l’effetto sulla tool call. Un JSON valido con la chiave sbagliata non prova un deny. Per controlli successivi, osserva il feedback e il file risultante. PostToolUse non può annullare una modifica già eseguita soltanto perché il suo handler termina con errore.
Percorsi, quoting e runtime: dove cercare un avvio fallito?
Controlla se il comando esiste nell’ambiente del hook, non soltanto nel terminale personale. Un programma disponibile attraverso un profilo interattivo può non essere raggiungibile in una sessione diversa. I percorsi con spazi richiedono quoting; un percorso relativo può dipendere dalla directory corrente. Preferisci una posizione dichiarata nel progetto.
Il contenuto dell’input non deve diventare una stringa shell eseguibile. Se lo script richiama un programma con un percorso ricevuto, passa argomenti separati. Errori di quoting possono essere sia guasti di funzionamento sia una superficie di esecuzione non prevista. Una fixture con nome di file contenente spazi aiuta a verificare il caso ordinario senza usare dati riservati.
| Sintomo | Ipotesi iniziale | Prova minima |
|---|---|---|
| Comando non trovato | Runtime assente dal PATH | Avvio nell’ambiente del hook |
| Script trovato ma non parte | Permessi o interprete | Invocazione diretta dichiarata |
| Funziona solo da una cartella | Percorso relativo | Esecuzione con directory differente |
| File sbagliato elaborato | Quoting o input | Fixture con percorso sintetico |
| Output non riconosciuto | JSON contaminato | Stdout distinto dal log |
| Chiamata esclusa | Matcher o evento | Caso incluso e caso negativo |
Timeout: che cosa dimostra un controllo interrotto?
Un timeout dimostra che il controllo non è terminato entro il budget applicato. Non dimostra da solo che la tool call sia stata bloccata. La reference attuale descrive default di 600 secondi per command, HTTP e MCP, 30 per prompt e 60 per agent, con eccezioni e budget specifici per alcuni eventi. Non usare un valore storico senza verificare la sezione dell’evento corrente. Timeouts.
Il timeout può dipendere da una richiesta di input nascosta, un processo lento o una dipendenza non disponibile. Aumentarlo senza capire la causa può rendere soltanto più lunga l’attesa. Prova prima lo stesso controllo direttamente e verifica se richiede una shell interattiva o un servizio non avviato.
La release 2.1.295 dell’8 ottobre 2026 introduce onFailure: "block" per command e HTTP. In questa verifica l’introduzione è confermata, ma lo schema completo e le interazioni non sono stati verificati per tutti gli eventi. Non viene proposto un campo inventato per risolvere il problema. Release ufficiale.
Il servizio HTTP o MCP è raggiungibile dall’ambiente giusto?
Un endpoint su localhost può riferirsi a un ambiente diverso dal computer del lettore. Un server MCP può essere configurato ma non autenticato. Prima di modificare il JSON della decisione, prova la connessione con dati sintetici e identifica dove gira il client. Se il trasporto non è completato, la policy non ha ancora prodotto una valutazione.
Per HTTP, una risposta 500 non è un deny equivalente a un exit code di blocco. La decisione ordinaria deve arrivare attraverso il contratto JSON. HTTP Hooks descrive i diversi esiti. Per MCP controlla nome scoped del server, tool e input; Hooks e MCP separa intercettazione e handler.
Non risolvere un problema di connessione esponendo automaticamente il servizio sulla rete o copiando credenziali nel file. La diagnosi deve preservare il perimetro del progetto. Se un prerequisito manca, il report dice “controllo non disponibile”, senza inventare il risultato dello scanner o del servizio.
La policy amministrativa impedisce l’esecuzione?
Le organizzazioni possono restringere i hook con managed settings e allowlist. Un file locale valido può essere intenzionalmente escluso dalla policy. Controlla le sorgenti effettive e il messaggio di rifiuto; non cercare di aggirare il limite distribuendo lo stesso comando con un nome diverso. Gestione amministrativa dei hook.
Per una configurazione in plugin, verifica anche il componente realmente caricato e la sua versione. Un agente incluso in un plugin ignora il campo frontmatter hooks, secondo la documentazione dei componenti. Il controllo deve quindi essere registrato nel livello supportato. Plugin agent frontmatter.
Hooks per subagent e team approfondisce questo confine. Mods per team e sicurezza aiuta se la distribuzione comprende altre personalizzazioni. Una policy organizzativa e un bug dello script sono cause differenti, con percorsi di correzione diversi.
Serve riavviare dopo ogni modifica?
Il comportamento corrente include meccanismi di ricaricamento dei settings. Non copiare come regola assoluta un tutorial storico che impone sempre il riavvio. Verifica invece se la registrazione aggiornata è visibile nella sessione e se il tipo di componente ha un proprio percorso di reload. Troubleshooting ufficiale.
Anche un file nel repository ufficiale può essere materiale storico. La skill plugin-dev recuperata contiene indicazioni differenti dalla reference attuale su timeout e schemi di prompt. La fonte principale per il contratto operativo resta la reference aggiornata, confrontata con la versione installata. Materiale storico plugin-dev.
Per SessionStart prova il motivo di avvio previsto, senza assumere che una modifica al file abbia riprodotto automaticamente compact. La guida SessionStart e compaction spiega come verificare la ripresa senza copiare tutto il contesto.
Due guasti riproducibili in progetti italiani
Esempio ipotetico, non testato: un’agenzia a Lecce registra un formatter su Edit|Write, ma le modifiche avvengono attraverso uno script Bash. Il hook appare in /hooks e lo script funziona con la fixture diretta. La diagnosi mostra un evento non corrispondente al matcher, senza richiedere una riscrittura del formatter. Il team decide quale percorso di modifica adottare e conserva una prova negativa per la chiamata esclusa.
Esempio ipotetico, non testato: una PMI a Udine configura un servizio HTTP locale per controllare un’operazione sintetica. In una sessione remota il servizio non è raggiungibile, mentre sul portatile risponde. Il team identifica la macchina su cui gira localhost, poi prova il collegamento previsto senza aprire indiscriminatamente la porta. Non tratta l’errore di connessione come un rifiuto della policy.
Entrambi i guasti hanno una causa osservabile e una correzione circoscritta. Il report utile indica quale passaggio è stato verificato e quale ha fallito, invece di riassumere tutto con “i Hooks non funzionano”.
Come chiudere la diagnosi con una prova utile?
Ripeti il caso che falliva e almeno un caso escluso dalla regola. Controlla output, exit code ed effetto nella sessione. Conserva una fixture sintetica e annota la versione: servirà quando cambia il runtime, il plugin o il servizio. Evita log permanenti dell’intero input solo per ricordare il guasto.
Il hook funziona ma continua a chiedere lavoro
Controlla se il problema riguarda Stop e la gestione di stop_hook_active. Una condizione impossibile o una prova mai aggiornata può produrre continuazioni ripetute anche quando lo script parte correttamente. La diagnosi deve riguardare il criterio di completamento, non soltanto l’avvio del comando.
Stop hook senza loop descrive quel caso specifico. Per personalizzazioni che disegnano l’interfaccia, Mods di Claude distingue un altro livello di estensione: non tutti i problemi di un mod appartengono ai settings hook.
Se i controlli fanno parte di un’applicazione interna, il servizio di software su misura può includere fixture, osservabilità e manutenzione del workflow. Una diagnosi è conclusa quando il passaggio guasto è identificato, la correzione è provata e il perimetro originario del controllo rimane verificabile.
Metodo e fonti delle guide di Giallo Studio
Come lo applichiamo in azienda
Risorse correlate
Claude Code Hooks: guida pratica in italiano
PreToolUse: proteggere file in Claude Code
PostToolUse: formatter e test in Claude Code
Notifiche Claude Code: hook locali e permessi
SessionStart: contesto dopo compaction
Mods di Claude: cosa sono e quando servono in Claude Code
Claude AI per codice e sviluppoFAQ
Da dove iniziare se un hook non parte?
Controlla in /hooks se la registrazione è visibile. Poi verifica evento, matcher e configurazione effettivamente caricata prima di modificare lo script.
Devo riavviare sempre Claude Code?
Le versioni attuali hanno meccanismi di ricaricamento dei settings. Verifica la registrazione nella sessione e le regole della versione usata invece di copiare istruzioni storiche.
Perché un matcher Edit non intercetta Bash?
Il matcher dei tool event guarda il nome del tool, non l’effetto sul file. Uno script shell che modifica un file rimane una chiamata Bash.
Come verificare il JSON dello script?
Usa un input sintetico salvato localmente e controlla separatamente stdout, stderr e codice di uscita. Il JSON di risposta deve essere valido e coerente con l’evento.
Un timeout dimostra che il tool è stato bloccato?
No. Devi osservare anche la decisione e il comportamento dell’evento. Errori ordinari e deny esplicito sono esiti differenti.
Posso usare un tutorial vecchio dal repo ufficiale?
Confrontalo con la reference attuale. Anche materiale ufficiale storico può descrivere timeout, schemi di risposta o procedure non più corrispondenti alla versione installata.