Gli hook di Claude Code non funzionano su Windows: cause e soluzioni

Lo stesso hook che funziona benissimo su Mac non fa nulla su Windows o, peggio, blocca ogni comando. Quasi sempre la colpa è della shell. Ecco come Claude Code esegue gli hook su Windows e come rendere affidabili i tuoi.

Di Aslan, team di Pet Island · Aggiornato il 26 ott 2026 · 5 min di lettura

RISPOSTA BREVE

Su Windows, Claude Code esegue il command di un hook con Git Bash, oppure con PowerShell se Git Bash non è installato. Indica quale intendi con "shell": "powershell" o "shell": "bash", limita stdout a un solo oggetto JSON (niente echo dal profilo), usa il codice di uscita 2 per bloccare e aggiorna Claude Code (diversi bug degli hook su Windows sono stati corretti nelle versioni fino alla 2.1.310). Esegui il debug con /hooks e claude --debug.

Quale shell esegue il tuo hook

Claude Code passa la stringa command a una shell: sh -c su macOS e Linux, Git Bash su Windows, oppure PowerShell se Git Bash non è installato. Questa sola frase del riferimento degli hook spiega la maggior parte delle segnalazioni del tipo “sul mio Mac funziona”. Un comando scritto per PowerShell fallisce in Git Bash, uno script bash fallisce in PowerShell, e quale ti tocca dipende dal fatto che Git for Windows sia installato o meno.

Elimina l'incertezza con il campo shell. Accetta "bash" o "powershell":

%USERPROFILE%\.claude\settings.jsonCopia
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [
{
"type": "command",
"shell": "powershell",
"command": "[Console]::Beep(880, 200)"
}
]
}
]
}
}

Se vuoi Git Bash e Claude Code non lo trova, installa Git for Windows o imposta CLAUDE_CODE_GIT_BASH_PATH sul suo percorso, poi avvia una nuova sessione.

I sintomi e le loro cause

Cosa vediCausa probabileSoluzione
L'hook sembra non essere mai eseguitoVersione vecchia di Claude Code, evento o matcher sbagliato, JSON non valido nelle impostazioniAggiorna; controlla /hooks; rimuovi commenti e virgole finali
ParserError o “unexpected token”Sintassi PowerShell che arriva a Git Bash, o viceversaImposta shell in modo esplicito
Output dell'hook “does not start with {”Qualcosa è stato stampato prima del JSON, spesso dal profilo della shellSilenzia l'output del profilo; invia i log a stderr
Un percorso con \ e / mescolati non viene trovatoVariabile di percorso Windows unita a un suffisso in stile UnixUsa la forma exec: il programma in command, ogni argomento in args
powershell: Permission denied da Git BashSegnalato in modo intermittente nella 2.1.283 e nelle 2.1.304–2.1.305 (#103910, aperta)Usa "shell": "powershell" così Git Bash non si mette in mezzo
Un hook di controllo lascia passare tuttoCodice di uscita 1 invece di 2, oppure un bug fail-open nelle versioni precedentiEsci con 2 per bloccare; aggiorna alla 2.1.310 o successiva
L'hook termina subito senza outputUn programma del sottosistema GUI che la shell non attendeUsa un programma console, oppure attendi il processo

Solo JSON su stdout

Claude Code legge l'output standard dell'hook come sua risposta. La regola nella documentazione è breve: non stampare su stdout nient'altro che l'oggetto JSON. Su Windows questo si rompe in modo subdolo: Git Bash e alcune configurazioni caricano comunque il profilo della shell, e un echo incondizionato in quel profilo finisce davanti al tuo JSON. L'hook allora “funziona” in un terminale e fallisce dentro Claude Code.

Scrivi invece i log in un file o su stderr, e fai in modo che il profilo produca output solo in una shell interattiva.

Codici di uscita: 2 blocca, 1 no

L'uscita 0 indica successo. L'uscita 2 è un errore bloccante: negli eventi che possono essere bloccati, Claude Code ferma l'azione e mostra il tuo stderr. L'uscita 1 senza JSON valido è un errore non bloccante, e l'azione prosegue. Se il tuo hook applica un criterio, usa l'uscita 2.

Non tutti gli eventi possono essere bloccati in questo modo. Il codice di uscita di un hook Notification viene ignorato. Un hook Stop che esce con 2 fa continuare Claude a lavorare. Un hook PermissionRequest ignora del tutto l'uscita 2: decide tramite un oggetto decision nel suo JSON.

Claude Code 2.1.309 ha corretto gli hook PowerShell che non bloccavano quando il programma dell'hook usciva con codice 2. Se il tuo controllo in PowerShell sembra ignorato, verifica prima la versione.

Le correzioni per Windows per cui vale la pena aggiornare

Il changelog di Anthropic contiene una lunga serie di correzioni degli hook su Windows. Quelle che spiegano vecchie discussioni nei forum:

VersioneCorrezione
2.1.47Gli hook PreToolUse e PostToolUse fallivano in silenzio su Windows; ora vengono eseguiti con Git Bash invece di cmd.exe
2.1.161Gli hook che chiamano bash in modo esplicito (/usr/bin/bash script.sh) fallivano con “command not found”
2.1.299Gli hook PreToolUse e PermissionRequest senza shell impostata lasciavano passare tutto in caso di errore senza Git for Windows; ora un controllo che fallisce blocca
2.1.309Gli hook PowerShell non bloccavano con il codice di uscita 2; i controlli con "shell": "powershell" lasciavano passare tutto senza Git for Windows
2.1.310I controlli il cui comando era composto solo da stringhe tra virgolette (come un percorso tra virgolette) lasciavano passare tutto senza Git Bash

La vecchia issue intitolata “No hook is working on Windows” (#10450) è stata segnalata sulla 2.0.27; un utente nei commenti ha ricondotto il problema allo stdin che non arrivava ai comandi degli hook. Se usi una versione così vecchia, aggiorna prima di fare qualsiasi altro debug.

Chiamare direttamente un programma

Se il tuo hook è un programma compilato, puoi saltare la shell con la forma exec (il campo args; shell viene ignorato quando args è impostato). Su Windows, la forma exec richiede che command corrisponda a un vero eseguibile come un .exe; gli shim .cmd e .bat (compresa la maggior parte di ciò che installa npm) non possono essere avviati senza una shell. Punta al .exe, oppure usa la forma shell.

Una lezione imparata sviluppando il nostro helper per gli hook: su Windows, un programma compilato per il sottosistema GUI non viene atteso quando una shell lo avvia. La shell restituisce subito il controllo, l'agente legge un output vuoto e l'hook sembra morto. I programmi per gli hook devono essere programmi console.

Hook dei plugin e percorsi

Gli hook dei plugin che costruiscono percorsi come ${CLAUDE_PLUGIN_ROOT}/hooks/run.sh non funzionavano su Windows tra la v2.1.2 e la v2.1.12 (#18610): la variabile si espande in un percorso con barre rovesciate, e aggiungere un suffisso con barre normali produce un percorso misto che bash non sa risolvere. La documentazione attuale indica la soluzione pulita: usa la forma exec ogni volta che un hook fa riferimento a un segnaposto di percorso. Metti il programma in command e ogni argomento in args, ad esempio "command": "node", "args": ["${CLAUDE_PLUGIN_ROOT}/scripts/format.js"]. Ogni elemento viene passato come un singolo argomento, senza una shell che lo stravolga.

Checklist per il debug

  1. /hooks apre un elenco di sola lettura di tutti gli hook configurati e della loro provenienza.
  2. claude --debug (o /debug a sessione in corso) mostra ogni esecuzione di hook, il suo output e il codice di uscita. claude --debug-file <path> lo scrive in un file.
  3. Convalida il JSON. I file di impostazioni sono JSON rigoroso; una sola virgola finale disattiva l'intero file.
  4. Controlla il matcher. I matcher distinguono tra maiuscole e minuscole; "*", "" o nessun matcher corrispondono a tutto.
  5. Esegui tu il comando nella stessa shell che userà Claude Code, passandogli in pipe un JSON di esempio.
  6. Guarda il timeout. Gli hook di comando hanno un timeout predefinito di 600 secondi; un hook che attende una persona ha bisogno di quel margine.

Per disattivare tutti gli hook mentre indaghi, imposta "disableAllHooks": true.

Se volevi solo notifiche e approvazioni

Molte configurazioni di hook su Windows esistono per un solo motivo: sapere quando Claude Code ha bisogno di te e rispondergli. Pet Island lo fa senza alcuno script. Si collega a Claude Code con un clic, gestisce per te i dettagli di Windows e mette ogni richiesta di autorizzazione, domanda e piano su una piccola isola nella parte alta dello schermo, con il comando o il diff, dove puoi consentirli o negarli. Funziona anche quando Claude Code viene eseguito in WSL.

FAQ

Quale shell esegue gli hook di Claude Code su Windows?

Git Bash, oppure PowerShell se Git Bash non è installato. Imposta "shell": "powershell" o "shell": "bash" nell'hook per scegliere in modo esplicito.

Perché il mio hook di Claude Code funziona nel terminale ma non in Claude Code?

Di solito per un output in più: un profilo della shell che stampa del testo finisce davanti al JSON dell'hook. Stampa su stdout solo l'oggetto JSON.

Come faccio a far bloccare una chiamata a uno strumento da un hook?

Esci con codice 2 (oppure restituisci una decisione deny in JSON). Il codice di uscita 1 è un errore non bloccante e l'azione prosegue. Gli hook PermissionRequest ignorano l'uscita 2 e usano invece un oggetto decision.

Il comando di un hook può essere un file .cmd o .bat?

Non nella forma exec. Su Windows deve corrispondere a un vero eseguibile come un .exe. Usa la forma shell per eseguire file .cmd o .bat.

Come vedo perché un hook è fallito?

Esegui claude --debug o digita /debug, e usa /hooks per vedere quali hook sono caricati.

Fonti

Ogni impostazione e comportamento descritti in questa pagina sono stati verificati su queste pagine il 26 ottobre 2026. Gli agenti cambiano in fretta: se qualcosa non corrisponde più, fa fede la pagina ufficiale.

CONTINUA A LEGGERE

Rispondi a tutti i tuoi agenti dalla parte alta dello schermo.

Windows e Mac · 7 giorni gratis, poi 8,99 $ una tantum · 1 $ di ogni vendita sfama gli animali randagi

Prova Pet Island gratis