Passa al contenuto principale

Hook: automazione deterministica

Avanzato

Gli hook sono comandi shell che Claude Code esegue automaticamente in punti definiti del suo ciclo di vita. Mentre i permessi decidono se un'azione è consentita, gli hook permettono a te di eseguire logica deterministica attorno a essa — formattazione, validazione, logging, gate. Sono il modo per rendere un comportamento garantito anziché un "ricordati di".

What you'll learn
  • Quando ricorrere a un hook invece che a un'istruzione o a un permesso
  • Come si configura un hook: evento, matcher e il payload JSON su stdin
  • I due modi in cui un hook blocca un'azione — codice di uscita 2 contro JSON su stdout
  • Le buone pratiche e gli errori comuni che distinguono gli hook veloci e sicuri da quelli lenti e silenziosi

Quando ricorrere a un hook

Ricorri a un hook quando vuoi che un comportamento sia garantito, non semplicemente richiesto. Ogni compito comune si associa a un evento del ciclo di vita:

  • Auto-formattazione / lint dopo ogni modifica di file (PostToolUse).
  • Bloccare un'azione che viola una regola prima che venga eseguita (PreToolUse).
  • Notificare o registrare quando una sessione termina o un'attività si conclude (Stop).
  • Iniettare contesto all'avvio della sessione.
Gli eventi hook a colpo d'occhio
Premi Invio o Spazio per girare la carta. Usa le frecce sinistra e destra per spostarti tra le carte.Termine mostrato.
1 / 4

Come funzionano

Registri gli hook in settings.json, associandoli a un evento (e spesso a un matcher di strumento). Quando l'evento si verifica, Claude esegue il tuo comando, passando un payload JSON su stdin (il nome dello strumento, i suoi input, la sessione). Il codice di uscita e l'output del tuo comando decidono cosa succede dopo.

Guided walkthrough1 of 4
  1. Registra l'hook in settings.json sotto l'evento del ciclo di vita che ti interessa — per esempio PostToolUse.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }
]
}
]
}
}

L'hook qui sopra legge il percorso del file modificato dal JSON su stdin (.tool_input.file_path) e lo formatta. Non dare per scontato che una variabile d'ambiente contenga il percorso — leggilo da stdin. Utili segnaposto di percorso come ${CLAUDE_PROJECT_DIR} sono disponibili per individuare gli script.

Come un hook blocca

Due modi, a seconda dell'evento:

  • Codice di uscita 2 — l'hook fa fallire l'azione e qualunque cosa abbia scritto su stderr diventa il messaggio che Claude vede. Semplice e funziona per gli hook di tipo command.
  • JSON su stdout (uscita 0) — restituisci una decisione strutturata. Per PreToolUse, è un permissionDecision pari a deny; per PostToolUse/Stop/ecc. è {"decision": "block", "reason": "…"}.

Lo script qui sotto è un hook PreToolUse sullo strumento Bash. Leggilo dall'alto in basso: estrae il comando da stdin e, se sembra distruttivo, scrive una motivazione su stderr ed esce con codice 2 per bloccare.

#!/usr/bin/env bash
# PreToolUse hook on the Bash tool: refuse to delete things.
command=$(jq -r '.tool_input.command' < /dev/stdin)
if [[ "$command" == rm\ * || "$command" == *"rm -rf"* ]]; then
echo "Blocked: destructive 'rm' is not allowed by policy." >&2
exit 2
fi
exit 0

Il modello mentale

Un hook PreToolUse viene eseguito prima dell'azione e può bloccarla; un hook PostToolUse viene eseguito dopo che ha avuto successo e reagisce al risultato.

Buone pratiche

  • Mantieni gli hook veloci e idempotenti — vengono eseguiti molto spesso.
  • Segnala forte i problemi reali, ma non bloccare per questioni estetiche.
  • Tratta l'output dell'hook come feedback per Claude — un messaggio chiaro lo aiuta a correggersi da solo.
  • Gli hook vengono eseguiti con i privilegi della tua shell — rivedi qualsiasi hook che non hai scritto tu (Revisione del codice di terze parti).

Errori comuni

  • Leggere il percorso del file da una variabile d'ambiente. Il percorso vive nel JSON su stdin (.tool_input.file_path), non in $CLAUDE_FILE_PATH. Fai passare stdin attraverso jq.
  • Blocchi silenziosi. Se un hook PreToolUse esce con codice 2 senza nulla su stderr, Claude è bloccato ma non sa perché e non può adattarsi. Scrivi sempre una motivazione chiara.
  • Hook lenti. Un hook PostToolUse viene eseguito dopo ogni modifica corrispondente. Un linter da 3 secondi rende l'intera sessione lenta e pesante — mantieni gli hook veloci e, idealmente, fai agire solo su ciò che è cambiato.
  • Matcher troppo ampi. matcher: ".*" scatta su ogni strumento. Restringi con un nome esatto, una lista Edit|Write, o il campo if per singolo handler (ad es. "if": "Bash(git push *)").
  • Fidarsi di hook che non hai scritto. Un hook esegue shell arbitraria con i tuoi privilegi. Rivedi prima ogni hook proveniente da un plugin o da un template — vedi Revisione del codice di terze parti.
Watch out
  • Un hook esegue shell arbitraria con i tuoi privilegi — non configurare mai un hook proveniente da un plugin o da un template senza prima leggerlo.

Starter da copia-incolla si trovano in Ricette per hook e settings.json.

Auto-formattare i file modificati (PostToolUse su Edit|Write)

{
"hooks": {
  "PostToolUse": [
    {
      "matcher": "Edit|Write",
      "hooks": [
        { "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }
      ]
    }
  ]
}
}

Mettiti alla prova

0/3
  1. Dove trova un hook il percorso del file appena modificato?
  2. Un hook PreToolUse esce con codice 2. Cosa succede?
  3. Perché matcher ".*" è considerato un errore comune?
Key takeaways
  • Gli hook rendono un comportamento garantito, non richiesto — eseguono logica deterministica attorno ad azioni che i permessi si limitano a consentire o negare.
  • Registra un hook in settings.json contro un evento più un matcher; Claude convoglia un payload JSON su stdin e legge il tuo codice di uscita e il tuo output.
  • Leggi il percorso del file da stdin (.tool_input.file_path) — non da una variabile d'ambiente.
  • Blocca con il codice di uscita 2 (stderr diventa il messaggio) o con JSON strutturato su stdout (uscita 0); includi sempre una motivazione chiara.
  • Mantieni gli hook veloci, idempotenti e con matcher ristretto — e rivedi qualsiasi hook che non hai scritto tu, dato che viene eseguito con i privilegi della tua shell.

Prossimi passi