Risposta diretta
Gli hook di Claude Code sono utili quando si hanno vincoli enforceable o quando è necessario eseguire operazioni complesse in modo automatizzato, ma possono essere eccessivi se usati per gestire situazioni che possono essere risolte con istruzioni nel file CLAUDE.md e una buona revisione del codice.
Gli hook di Claude Code permettono di intercettare invocazioni tool ed eventi di sessione con comandi shell custom. Sono potenti e overkill al tempo stesso: utili quando hai vincoli enforceable, eccessivi quando bastano istruzioni nel CLAUDE.md. Questo articolo spiega quando vale la candela.
Disclaimer di indipendenza: non sono affiliato ad Anthropic. Uso 2 hook attivi sul portfolio: uno per auto-format post-Edit/Write, uno per audit log su Stop. Niente di più.
Aggiornamento del 30 ottobre 2026: tre correzioni che contano
In breve: questo articolo presentava tre tipi di hook; la documentazione ufficiale oggi elenca 33 eventi e cinque tipi di handler. Soprattutto, due dettagli dell'originale erano sbagliati e uno era pericoloso:
- Solo l'exit code 2 blocca. L'originale diceva che qualunque exit code diverso da zero blocca il tool, e lo script di esempio usava
exit 1. Secondo la documentazione ufficiale, exit 1 non blocca: l'azione procede e l'utente vede solo un avviso. Uno script di sicurezza scritto conexit 1non protegge nulla. Gli esempi qui sotto sono stati corretti aexit 2. - Formato della configurazione. Ogni voce ha un
matchere un arrayhooksdi handler contypeecommand; il vecchio formato concommanddirettamente sulla voce è stato sostituito nell'esempio. Il payload su stdin usatool_input(nonparams). - «Stop» non è la fine della sessione.
Stopscatta quando Claude finisce di rispondere (a ogni turno); la chiusura della sessione è l'eventoSessionEnd.
Eventi (33): SessionStart, Setup, SessionEnd; UserPromptSubmit, UserPromptExpansion, Stop, StopFailure; PreToolUse, PermissionRequest, PermissionDenied, PostToolUse, PostToolUseFailure, PostToolBatch; SubagentStart, SubagentStop, TaskCreated, TaskCompleted, TeammateIdle; InstructionsLoaded, ConfigChange, CwdChanged, DirectoryAdded, FileChanged, WorktreeCreate, WorktreeRemove; PreCompact, PostCompact, PreModelSwitch, PostModelSwitch; Elicitation, ElicitationResult; Notification, MessageDisplay.
Handler: command, http, mcp_tool, prompt e agent (quest'ultimo sperimentale).
Novità recenti: onFailure: "block" (dalla v2.1.295) fa bloccare l'azione a un hook che fallisce o va in timeout; once: true nelle skill; dal 27 ottobre 2026 (v2.1.312) gli hook prompt e agent girano al massimo 24 alla volta per sessione, e dal 14 ottobre 2026 (v2.1.300) l'updatedInput di PreToolUse è validato come l'input di Claude.
Trade-off: un hook è l'unico modo per imporre una regola (CLAUDE.md è solo contesto, non è applicato), ma ogni hook lento rallenta ogni azione e un hook onFailure: "block" può bloccare il lavoro se lo script si rompe.
Fonte (consultata il 30 ottobre 2026): documentazione hook di Claude Code e changelog.
I tre tipi di hook
-
PreToolUse - eseguito PRIMA che Claude Code invochi
un tool. Riceve in stdin payload con tool name +
tool_input. Può: modificare l'input (updatedInput), bloccare l'esecuzione (exit code 2), permetterla (exit 0). Un exit code diverso da 0 e da 2 non blocca. - PostToolUse - eseguito DOPO un'invocazione tool successful. Riceve payload con tool name + result. Tipicamente usato per auto-format, audit log, notifiche.
-
Stop - eseguito quando Claude finisce di rispondere
(a ogni turno; la fine della sessione è
SessionEnd, corretto il 30 ottobre 2026). Util per summary di turno, usage tracking, cleanup temporaneo.
Configurazione
File: ~/.claude/settings.json (user) o
.claude/settings.json (project). Esempio illustrativo:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "/usr/local/bin/auto-format-hook.sh" }
]
}
],
"Stop": [
{
"hooks": [
{ "type": "command", "command": "/usr/local/bin/session-summary.sh" }
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "/usr/local/bin/bash-safety-check.sh" }
]
}
]
}
}
matcher è regex sul tool name (omettilo per "tutti i tool").
command è path eseguibile a uno script o binary.
Esempio: auto-format hook
Uno dei due hook che uso. Script ricevuto in stdin payload JSON con file path appena modificato:
#!/usr/bin/env bash
# /usr/local/bin/auto-format-hook.sh
# Esegue prettier su file .ts / .tsx / .json appena modificati
PAYLOAD=$(cat)
FILE=$(echo "$PAYLOAD" | jq -r '.tool_input.file_path // empty')
if [ -z "$FILE" ]; then exit 0; fi
case "$FILE" in
*.ts|*.tsx|*.json) npx --no-install prettier --write "$FILE" 2>/dev/null ;;
*) exit 0 ;;
esac
Effetto: ogni Edit / Write su file TS/JSON è auto-formattato. Risparmiati commit "chore: format" cumulati e diff puliti.
Esempio: bash safety check
Hook PreToolUse su Bash per bloccare comandi distruttivi senza confirm esplicito:
#!/usr/bin/env bash
# /usr/local/bin/bash-safety-check.sh
# Blocca rm -rf / e simili senza confirm utente in shell
PAYLOAD=$(cat)
CMD=$(echo "$PAYLOAD" | jq -r '.tool_input.command')
if echo "$CMD" | grep -qE 'rm\s+-rf\s+/|drop\s+database|truncate\s+table'; then
echo "BLOCKED: destructive command detected. Require explicit user confirm in chat." >&2
exit 2
fi
exit 0
Solo l'exit code 2 blocca l'esecuzione del tool (in origine l'esempio usava exit 1, che invece lascia proseguire l'azione: corretto il 30 ottobre 2026). Il messaggio in stderr arriva
al modello, che reagisce (tipicamente chiede confirm utente prima di
ripetere). Nota: il pattern grep sopra è un esempio didattico, non una barriera di sicurezza completa.
Esempio: Stop hook per usage tracking
Hook Stop tipico: appende riga al log usage personale.
#!/usr/bin/env bash
# /usr/local/bin/session-summary.sh
LOG="$HOME/.claude/usage-log.csv"
DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)
SESSION_ID="${CLAUDE_SESSION_ID:-unknown}"
echo "$DATE,$SESSION_ID,session_end" >> "$LOG"
Effetto: log usage per audit personale. Util se vuoi tracking effettivo di quanto tempo Claude Code attivo per progetto.
Quando NON scrivere hook
- Quando un'istruzione CLAUDE.md basta. Se la regola è "non modificare /infra senza confirm", istruzione nel CLAUDE.md è più semplice di un PreToolUse hook che lo blocca.
- Quando il vincolo è soft. Hook sono enforcement duri. Per regole indicative ("preferibilmente usa async/await"), un commento nel CLAUDE.md o una code-reviewer skill basta.
- Quando il setup costa più del valore. Hook richiedono script funzionante + debug + manutenzione. Per regole one-shot, non ne vale la pena.
Anti-pattern: hook troppo invasivo
Un PostToolUse hook che esegue full test suite dopo ogni Edit è enforcement zelante che paralizza il workflow. Un Edit richiede 30s → con hook test suite 2 minuti = ogni small change costa 2.5min.
Mitigation: hook devono essere veloci (sotto 5s). Se serve heavy operation, eseguila out-of-band (background job) o solo su Stop, non PostToolUse.
Debugging hook
Hook gira in subprocess silenzioso. Output stderr arriva al modello (e a te se hai verbose mode). Per debug:
- Aggiungi
set -xal top dello script per trace. - Redirect stderr a file dedicato (
2>> ~/.claude/hook-debug.log). - Test lo script manualmente con payload finto via stdin.
Cosa ho imparato scrivendo questo articolo
I hook sono come i decoratori in Python: utili in pochi casi strategici, dannosi se usati ovunque. Sul mio portfolio uso 2 hook (auto-format + Stop log) ed è il numero giusto. Provato a 5+ ho avuto friction continui.
Secondo insight: la maggior parte delle regole che pensavo richiedessero hook si risolvono meglio in CLAUDE.md instructions + code-reviewer skill. Hook restano per i pochissimi casi di "questo NON deve mai succedere a prescindere dal contesto".
Anti-pattern evitati
- Hook come sostituto di CLAUDE.md instructions. Istruzioni soft vanno in CLAUDE.md. Hook per enforcement vero.
- PostToolUse con heavy operation. Auto-format OK, full test suite no.
Una storia ricevuta che vale la pena condividere
Sezione segnaposto. Se hai hook custom interessanti, scrivimi
a federico@federicocalo.dev.
← Cluster precedente: MCP server development Prossimo cluster: IDE/web/CLI Claude Code environments →
Domande frequenti
Quali sono i tipi di hook disponibili per Claude Code?
Ci sono tre tipi di hook: Hook PreToolUse, Hook PostToolUse e Hook Stop.
Come si configura un hook in Claude Code?
La configurazione di un hook consiste nel specificare il nome del tool (opzionale) e il percorso eseguibile a uno script o binary utilizzando una regex.
Quando non è consigliabile utilizzare i hook in Claude Code?
I hook sono dannosi se usati ovunque, quindi è importante utilizzarli solo nei pochi casi strategici in cui sono necessari. In particolare, è importante evitare di eseguire operazioni pesanti all'interno dei hook PostToolUse.
Come si debuggano i hook in Claude Code?
I hook girano in subprocess silenzioso e l'output stderr arriva al modello (e a te se hai verbose mode). Per debug, è possibile utilizzare il verbose mode per visualizzare le informazioni di debug.
Commenti
Caricamento commenti...
Accedi per commentare