Salta al contenuto principale

Hooks system: PreToolUse / PostToolUse / Stop in Claude Code

Cluster 14 della serie Claude Code Workflow (Platform). I 3 hook type di Claude Code (PreToolUse, PostToolUse, Stop) permettono di intercettare invocazioni…

Cosa ne pensi di questo articolo?

Hooks system: PreToolUse / PostToolUse / Stop in Claude Code
Claude Code WorkflowFoto:PixabayPexels

In Breve

Cluster 14 della serie Claude Code Workflow (Platform). I 3 hook type di Claude Code (PreToolUse, PostToolUse, Stop) permettono di intercettare invocazioni…

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 con exit 1 non protegge nulla. Gli esempi qui sotto sono stati corretti a exit 2.
  • Formato della configurazione. Ogni voce ha un matcher e un array hooks di handler con type e command; il vecchio formato con command direttamente sulla voce è stato sostituito nell'esempio. Il payload su stdin usa tool_input (non params).
  • «Stop» non è la fine della sessione. Stop scatta quando Claude finisce di rispondere (a ogni turno); la chiusura della sessione è l'evento SessionEnd.

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

  1. 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.
  2. 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.
  3. 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:

  1. Aggiungi set -x al top dello script per trace.
  2. Redirect stderr a file dedicato (2>> ~/.claude/hook-debug.log).
  3. 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.

Fonti e approfondimenti

Commenti

Caricamento commenti...

Accedi per commentare

Discuti questo articolo nella community

Unisciti al gruppo Telegram per discutere con altri sviluppatori, fare domande e condividere le tue esperienze.

Ti è piaciuto questo articolo?

Esplora altri contenuti sul blog o scopri i miei progetti