Introduzione

Gli hook di Claude Code sono comandi shell definiti dall’utente che vengono eseguiti in vari punti del ciclo di vita di Claude Code. Gli hook forniscono un controllo deterministico sul comportamento di Claude Code, garantendo che certe azioni avvengano sempre piuttosto che affidarsi al LLM per scegliere di eseguirle.

Esempi di casi d’uso includono:

  • Notifiche: Personalizza come ricevi notifiche quando Claude Code è in attesa del tuo input o permesso per eseguire qualcosa.
  • Formattazione automatica: Esegui prettier sui file .ts, gofmt sui file .go, ecc. dopo ogni modifica di file.
  • Logging: Traccia e conta tutti i comandi eseguiti per conformità o debug.
  • Feedback: Fornisci feedback automatizzato quando Claude Code produce codice che non segue le convenzioni della tua codebase.
  • Permessi personalizzati: Blocca modifiche ai file di produzione o directory sensibili.

Codificando queste regole come hook piuttosto che istruzioni di prompt, trasformi i suggerimenti in codice a livello di app che viene eseguito ogni volta che è previsto che venga eseguito.

Gli hook eseguono comandi shell con i tuoi pieni permessi utente senza conferma. Sei responsabile di garantire che i tuoi hook siano sicuri e protetti. Anthropic non è responsabile per qualsiasi perdita di dati o danno al sistema risultante dall’uso degli hook. Rivedi le Considerazioni sulla Sicurezza.

Guida Rapida

In questa guida rapida, aggiungerai un hook che registra i comandi shell che Claude Code esegue.

Prerequisito della Guida Rapida: Installa jq per l’elaborazione JSON nella riga di comando.

Passo 1: Apri la configurazione degli hook

Esegui il comando slash /hooks e seleziona l’evento hook PreToolUse.

Gli hook PreToolUse vengono eseguiti prima delle chiamate agli strumenti e possono bloccarle fornendo feedback a Claude su cosa fare diversamente.

Passo 2: Aggiungi un matcher

Seleziona + Add new matcher… per eseguire il tuo hook solo sulle chiamate agli strumenti Bash.

Digita Bash per il matcher.

Passo 3: Aggiungi l’hook

Seleziona + Add new hook… e inserisci questo comando:

jq -r '"\(.tool_input.command) - \(.tool_input.description // "No description")"' >> ~/.claude/bash-command-log.txt

Passo 4: Salva la tua configurazione

Per la posizione di archiviazione, seleziona User settings dato che stai registrando nella tua directory home. Questo hook si applicherà quindi a tutti i progetti, non solo al tuo progetto corrente.

Poi premi Esc fino a tornare al REPL. Il tuo hook è ora registrato!

Passo 5: Verifica il tuo hook

Esegui di nuovo /hooks o controlla ~/.claude/settings.json per vedere la tua configurazione:

"hooks": {
  "PreToolUse": [
    {
      "matcher": "Bash",
      "hooks": [
        {
          "type": "command",
          "command": "jq -r '\"\\(.tool_input.command) - \\(.tool_input.description // \"No description\")\"' >> ~/.claude/bash-command-log.txt"
        }
      ]
    }
  ]
}

Configurazione

Gli hook di Claude Code sono configurati nei tuoi file di impostazioni:

  • ~/.claude/settings.json - Impostazioni utente
  • .claude/settings.json - Impostazioni progetto
  • .claude/settings.local.json - Impostazioni progetto locali (non committate)
  • Impostazioni policy gestite dall’enterprise

Struttura

Gli hook sono organizzati per matcher, dove ogni matcher può avere più hook:

{
  "hooks": {
    "EventName": [
      {
        "matcher": "ToolPattern",
        "hooks": [
          {
            "type": "command",
            "command": "your-command-here"
          }
        ]
      }
    ]
  }
}
  • matcher: Pattern per abbinare i nomi degli strumenti (applicabile solo per PreToolUse e PostToolUse)
    • Le stringhe semplici corrispondono esattamente: Write corrisponde solo allo strumento Write
    • Supporta regex: Edit|Write o Notebook.*
    • Se omesso o stringa vuota, gli hook vengono eseguiti per tutti gli eventi corrispondenti
  • hooks: Array di comandi da eseguire quando il pattern corrisponde
    • type: Attualmente è supportato solo "command"
    • command: Il comando bash da eseguire
    • timeout: (Opzionale) Quanto tempo dovrebbe essere eseguito un comando, in secondi, prima di cancellare tutti gli hook in corso.

Eventi Hook

PreToolUse

Viene eseguito dopo che Claude crea i parametri dello strumento e prima di elaborare la chiamata allo strumento.

Matcher comuni:

  • Task - Attività dell’agente
  • Bash - Comandi shell
  • Glob - Corrispondenza pattern di file
  • Grep - Ricerca contenuto
  • Read - Lettura file
  • Edit, MultiEdit - Modifica file
  • Write - Scrittura file
  • WebFetch, WebSearch - Operazioni web

PostToolUse

Viene eseguito immediatamente dopo che uno strumento completa con successo.

Riconosce gli stessi valori matcher di PreToolUse.

Notification

Viene eseguito quando Claude Code invia notifiche.

Stop

Viene eseguito quando l’agente principale di Claude Code ha finito di rispondere.

SubagentStop

Viene eseguito quando un subagente di Claude Code (chiamata strumento Task) ha finito di rispondere.

Input Hook

Gli hook ricevono dati JSON tramite stdin contenenti informazioni di sessione e dati specifici dell’evento:

{
  // Campi comuni
  session_id: string
  transcript_path: string  // Percorso al JSON della conversazione

  // Campi specifici dell'evento
  ...
}

Input PreToolUse

Lo schema esatto per tool_input dipende dallo strumento.

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.txt",
    "content": "file content"
  }
}

Input PostToolUse

Lo schema esatto per tool_input e tool_response dipende dallo strumento.

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.txt",
    "content": "file content"
  },
  "tool_response": {
    "filePath": "/path/to/file.txt",
    "success": true
  }
}

Input Notification

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "message": "Task completed successfully",
  "title": "Claude Code"
}

Input Stop e SubagentStop

stop_hook_active è true quando Claude Code sta già continuando come risultato di un hook stop. Controlla questo valore o elabora la trascrizione per impedire a Claude Code di funzionare indefinitamente.

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "stop_hook_active": true
}

Output Hook

Ci sono due modi per gli hook di restituire output a Claude Code. L’output comunica se bloccare e qualsiasi feedback che dovrebbe essere mostrato a Claude e all’utente.

Semplice: Codice di Uscita

Gli hook comunicano lo stato attraverso codici di uscita, stdout e stderr:

  • Codice di uscita 0: Successo. stdout viene mostrato all’utente in modalità trascrizione (CTRL-R).
  • Codice di uscita 2: Errore bloccante. stderr viene restituito a Claude per elaborazione automatica. Vedi comportamento per evento hook di seguito.
  • Altri codici di uscita: Errore non bloccante. stderr viene mostrato all’utente e l’esecuzione continua.

Promemoria: Claude Code non vede stdout se il codice di uscita è 0.

Comportamento Codice di Uscita 2

Evento HookComportamento
PreToolUseBlocca la chiamata allo strumento, mostra errore a Claude
PostToolUseMostra errore a Claude (strumento già eseguito)
NotificationN/A, mostra stderr solo all’utente
StopBlocca l’arresto, mostra errore a Claude
SubagentStopBlocca l’arresto, mostra errore al subagente Claude

Avanzato: Output JSON

Gli hook possono restituire JSON strutturato in stdout per un controllo più sofisticato:

Campi JSON Comuni

Tutti i tipi di hook possono includere questi campi opzionali:

{
  "continue": true, // Se Claude dovrebbe continuare dopo l'esecuzione dell'hook (default: true)
  "stopReason": "string" // Messaggio mostrato quando continue è false
  "suppressOutput": true, // Nascondi stdout dalla modalità trascrizione (default: false)
}

Se continue è false, Claude smette di elaborare dopo l’esecuzione degli hook.

  • Per PreToolUse, questo è diverso da "decision": "block", che blocca solo una specifica chiamata allo strumento e fornisce feedback automatico a Claude.
  • Per PostToolUse, questo è diverso da "decision": "block", che fornisce feedback automatizzato a Claude.
  • Per Stop e SubagentStop, questo ha precedenza su qualsiasi output "decision": "block".
  • In tutti i casi, "continue" = false ha precedenza su qualsiasi output "decision": "block".

stopReason accompagna continue con una ragione mostrata all’utente, non mostrata a Claude.

Controllo Decisione PreToolUse

Gli hook PreToolUse possono controllare se una chiamata allo strumento procede.

  • “approve” bypassa il sistema di permessi. reason viene mostrato all’utente ma non a Claude.
  • “block” impedisce l’esecuzione della chiamata allo strumento. reason viene mostrato a Claude.
  • undefined porta al flusso di permessi esistente. reason viene ignorato.
{
  "decision": "approve" | "block" | undefined,
  "reason": "Spiegazione per la decisione"
}

Controllo Decisione PostToolUse

Gli hook PostToolUse possono controllare se una chiamata allo strumento procede.

  • “block” richiede automaticamente a Claude con reason.
  • undefined non fa nulla. reason viene ignorato.
{
  "decision": "block" | undefined,
  "reason": "Spiegazione per la decisione"
}

Controllo Decisione Stop/SubagentStop

Gli hook Stop e SubagentStop possono controllare se Claude deve continuare.

  • “block” impedisce a Claude di fermarsi. Devi popolare reason perché Claude sappia come procedere.
  • undefined permette a Claude di fermarsi. reason viene ignorato.
{
  "decision": "block" | undefined,
  "reason": "Deve essere fornito quando Claude è bloccato dal fermarsi"
}

Esempio Output JSON: Modifica Comando Bash

#!/usr/bin/env python3
import json
import re
import sys

# Definisci regole di validazione come lista di tuple (pattern regex, messaggio)
VALIDATION_RULES = [
    (
        r"\bgrep\b(?!.*\|)",
        "Usa 'rg' (ripgrep) invece di 'grep' per migliori prestazioni e funzionalità",
    ),
    (
        r"\bfind\s+\S+\s+-name\b",
        "Usa 'rg --files | rg pattern' o 'rg --files -g pattern' invece di 'find -name' per migliori prestazioni",
    ),
]


def validate_command(command: str) -> list[str]:
    issues = []
    for pattern, message in VALIDATION_RULES:
        if re.search(pattern, command):
            issues.append(message)
    return issues


try:
    input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
    print(f"Errore: Input JSON non valido: {e}", file=sys.stderr)
    sys.exit(1)

tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})
command = tool_input.get("command", "")

if tool_name != "Bash" or not command:
    sys.exit(1)

# Valida il comando
issues = validate_command(command)

if issues:
    for message in issues:
        print(f"• {message}", file=sys.stderr)
    # Codice di uscita 2 blocca la chiamata allo strumento e mostra stderr a Claude
    sys.exit(2)

Lavorare con Strumenti MCP

Gli hook di Claude Code funzionano perfettamente con gli strumenti Model Context Protocol (MCP). Quando i server MCP forniscono strumenti, appaiono con un pattern di denominazione speciale che puoi abbinare nei tuoi hook.

Denominazione Strumenti MCP

Gli strumenti MCP seguono il pattern mcp__<server>__<tool>, per esempio:

  • mcp__memory__create_entities - Strumento crea entità del server memory
  • mcp__filesystem__read_file - Strumento leggi file del server filesystem
  • mcp__github__search_repositories - Strumento ricerca del server GitHub

Configurazione Hook per Strumenti MCP

Puoi targetizzare strumenti MCP specifici o interi server MCP:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "mcp__memory__.*",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Operazione memory iniziata' >> ~/mcp-operations.log"
          }
        ]
      },
      {
        "matcher": "mcp__.*__write.*",
        "hooks": [
          {
            "type": "command",
            "command": "/home/user/scripts/validate-mcp-write.py"
          }
        ]
      }
    ]
  }
}

Esempi

Formattazione Codice

Formatta automaticamente il codice dopo le modifiche ai file:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "/home/user/scripts/format-code.sh"
          }
        ]
      }
    ]
  }
}

Notifica

Personalizza la notifica che viene inviata quando Claude Code richiede permesso o quando l’input del prompt è diventato inattivo.

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/my_custom_notifier.py"
          }
        ]
      }
    ]
  }
}

Considerazioni sulla Sicurezza

Disclaimer

USA A TUO RISCHIO: Gli hook di Claude Code eseguono comandi shell arbitrari sul tuo sistema automaticamente. Usando gli hook, riconosci che:

  • Sei l’unico responsabile per i comandi che configuri
  • Gli hook possono modificare, eliminare o accedere a qualsiasi file a cui il tuo account utente può accedere
  • Hook malevoli o scritti male possono causare perdita di dati o danni al sistema
  • Anthropic non fornisce garanzie e non si assume responsabilità per qualsiasi danno risultante dall’uso degli hook
  • Dovresti testare accuratamente gli hook in un ambiente sicuro prima dell’uso in produzione

Rivedi sempre e comprendi qualsiasi comando hook prima di aggiungerlo alla tua configurazione.

Migliori Pratiche di Sicurezza

Ecco alcune pratiche chiave per scrivere hook più sicuri:

  1. Valida e sanifica gli input - Non fidarti mai ciecamente dei dati di input
  2. Quota sempre le variabili shell - Usa "$VAR" non $VAR
  3. Blocca il path traversal - Controlla .. nei percorsi dei file
  4. Usa percorsi assoluti - Specifica percorsi completi per gli script
  5. Salta file sensibili - Evita .env, .git/, chiavi, ecc.

Sicurezza Configurazione

Le modifiche dirette agli hook nei file di impostazioni non hanno effetto immediatamente. Claude Code:

  1. Cattura uno snapshot degli hook all’avvio
  2. Usa questo snapshot durante tutta la sessione
  3. Avverte se gli hook vengono modificati esternamente
  4. Richiede revisione nel menu /hooks perché le modifiche si applichino

Questo impedisce che modifiche malevole agli hook influenzino la tua sessione corrente.

Dettagli Esecuzione Hook

  • Timeout: Limite di esecuzione di 60 secondi per default, configurabile per comando.
    • Se qualsiasi comando individuale va in timeout, tutti gli hook in corso vengono cancellati.
  • Parallelizzazione: Tutti gli hook corrispondenti vengono eseguiti in parallelo
  • Ambiente: Viene eseguito nella directory corrente con l’ambiente di Claude Code
  • Input: JSON tramite stdin
  • Output:
    • PreToolUse/PostToolUse/Stop: Progresso mostrato nella trascrizione (Ctrl-R)
    • Notification: Registrato solo nel debug (--debug)

Debug

Per risolvere problemi degli hook:

  1. Controlla se il menu /hooks mostra la tua configurazione
  2. Verifica che i tuoi file di impostazioni siano JSON validi
  3. Testa i comandi manualmente
  4. Controlla i codici di uscita
  5. Rivedi le aspettative di formato stdout e stderr
  6. Assicurati di un corretto escape delle virgolette
  7. Usa claude --debug per debuggare i tuoi hook. L’output di un hook riuscito appare come sotto.
[DEBUG] Executing hooks for PostToolUse:Write
[DEBUG] Getting matching hook commands for PostToolUse with query: Write
[DEBUG] Found 1 hook matchers in settings
[DEBUG] Matched 1 hooks for query "Write"
[DEBUG] Found 1 hook commands to execute
[DEBUG] Executing hook command: <Your command> with timeout 60000ms
[DEBUG] Hook command completed with status 0: <Your stdout>

I messaggi di progresso appaiono in modalità trascrizione (Ctrl-R) mostrando:

  • Quale hook è in esecuzione
  • Comando che viene eseguito
  • Stato di successo/fallimento
  • Messaggi di output o errore