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 tool ed eventi sessione. Quando scriverli, quando sono overhead, esempi reali dal portfolio.

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 tool ed eventi sessione. Quando scriverli, quando sono overhead, esempi reali dal portfolio.

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

  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