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ù.
I tre tipi di hook
- PreToolUse - eseguito PRIMA che Claude Code invochi un tool. Riceve in stdin payload con tool name + params. Può: modificare params (output di replacement), bloccare l'esecuzione (exit code non-zero), permetterla (exit 0).
- PostToolUse - eseguito DOPO un'invocazione tool successful. Riceve payload con tool name + result. Tipicamente usato per auto-format, audit log, notifiche.
- Stop - eseguito quando la sessione termina (Claude Code CLI quit). Util per session summary, usage tracking, cleanup temporaneo.
Configurazione
File: ~/.claude/settings.json (user) o
.claude/settings.json (project). Esempio illustrativo:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"command": "/usr/local/bin/auto-format-hook.sh"
}
],
"Stop": [
{
"command": "/usr/local/bin/session-summary.sh"
}
],
"PreToolUse": [
{
"matcher": "Bash",
"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 '.params.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 '.params.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 1
fi
exit 0
Output non-zero blocca esecuzione del tool. Messaggio in stderr arriva al modello, che reagisce (tipicamente chiede confirm utente prima di ripetere).
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