Vai al contenuto principale
Per una guida di avvio rapido con esempi, consulta Iniziare con gli hook di Claude Code.

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 locale (non sottoposte a commit)
  • Impostazioni di policy gestite
Gli amministratori aziendali possono utilizzare allowManagedHooksOnly per bloccare gli hook utente, progetto e plugin. Consulta Configurazione degli hook.

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, sensibile alle maiuscole (applicabile solo per PreToolUse, PermissionRequest e PostToolUse)
    • Le stringhe semplici corrispondono esattamente: Write corrisponde solo allo strumento Write
    • Supporta regex: Edit|Write o Notebook.*
    • Usa * per abbinare tutti gli strumenti. Puoi anche usare una stringa vuota ("") o lasciare matcher vuoto.
  • hooks: Array di hook da eseguire quando il pattern corrisponde
    • type: Tipo di esecuzione dell’hook - "command" per comandi bash o "prompt" per valutazione basata su LLM
    • command: (Per type: "command") Il comando bash da eseguire (può usare la variabile di ambiente $CLAUDE_PROJECT_DIR)
    • prompt: (Per type: "prompt") Il prompt da inviare all’LLM per la valutazione
    • timeout: (Opzionale) Quanto tempo un hook dovrebbe eseguire, in secondi, prima di annullare quello specifico hook
Per eventi come UserPromptSubmit, Stop e SubagentStop che non utilizzano matcher, puoi omettere il campo matcher:
{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/prompt-validator.py"
          }
        ]
      }
    ]
  }
}

Script di hook specifici del progetto

Puoi usare la variabile di ambiente CLAUDE_PROJECT_DIR (disponibile solo quando Claude Code genera il comando hook) per fare riferimento a script archiviati nel tuo progetto, assicurando che funzionino indipendentemente dalla directory corrente di Claude:
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/check-style.sh"
          }
        ]
      }
    ]
  }
}

Hook dei plugin

I plugin possono fornire hook che si integrano perfettamente con i tuoi hook utente e progetto. Gli hook dei plugin vengono automaticamente uniti alla tua configurazione quando i plugin sono abilitati. Come funzionano gli hook dei plugin:
  • Gli hook dei plugin sono definiti nel file hooks/hooks.json del plugin o in un file fornito da un percorso personalizzato al campo hooks.
  • Quando un plugin è abilitato, i suoi hook vengono uniti agli hook utente e progetto
  • Più hook da diverse fonti possono rispondere allo stesso evento
  • Gli hook dei plugin utilizzano la variabile di ambiente ${CLAUDE_PLUGIN_ROOT} per fare riferimento ai file del plugin
Esempio di configurazione degli hook del plugin:
{
  "description": "Automatic code formatting",
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh",
            "timeout": 30
          }
        ]
      }
    ]
  }
}
Gli hook dei plugin utilizzano lo stesso formato degli hook regolari con un campo description opzionale per spiegare lo scopo dell’hook.
Gli hook dei plugin vengono eseguiti insieme ai tuoi hook personalizzati. Se più hook corrispondono a un evento, vengono tutti eseguiti in parallelo.
Variabili di ambiente per i plugin:
  • ${CLAUDE_PLUGIN_ROOT}: Percorso assoluto della directory del plugin
  • ${CLAUDE_PROJECT_DIR}: Directory radice del progetto (uguale a quella degli hook del progetto)
  • Tutte le variabili di ambiente standard sono disponibili
Consulta il riferimento dei componenti del plugin per i dettagli sulla creazione degli hook del plugin.

Hook in Skills, Agenti e Slash Commands

Oltre ai file di impostazioni e ai plugin, gli hook possono essere definiti direttamente in Skills, subagenti e slash commands utilizzando il frontmatter. Questi hook sono limitati al ciclo di vita del componente e vengono eseguiti solo quando quel componente è attivo. Eventi supportati: PreToolUse, PostToolUse e Stop Esempio in una Skill:
---
name: secure-operations
description: Perform operations with security checks
hooks:
  PreToolUse:
    - matcher: "Bash"
      hooks:
        - type: command
          command: "./scripts/security-check.sh"
---
Esempio in un agente:
---
name: code-reviewer
description: Review code changes
hooks:
  PostToolUse:
    - matcher: "Edit|Write"
      hooks:
        - type: command
          command: "./scripts/run-linter.sh"
---
Gli hook con ambito componente seguono lo stesso formato di configurazione degli hook basati su impostazioni ma vengono automaticamente puliti quando l’esecuzione del componente termina. Opzione aggiuntiva per skill e slash command:
  • once: Impostare su true per eseguire l’hook solo una volta per sessione. Dopo la prima esecuzione riuscita, l’hook viene rimosso. Nota: questa opzione è attualmente supportata solo per skill e slash command, non per gli agenti.

Hook basati su prompt

Oltre agli hook di comando bash (type: "command"), Claude Code supporta hook basati su prompt (type: "prompt") che utilizzano un LLM per valutare se consentire o bloccare un’azione. Gli hook basati su prompt sono attualmente supportati solo per gli hook Stop e SubagentStop, dove abilitano decisioni intelligenti e consapevoli del contesto.

Come funzionano gli hook basati su prompt

Invece di eseguire un comando bash, gli hook basati su prompt:
  1. Inviano l’input dell’hook e il tuo prompt a un LLM veloce (Haiku)
  2. L’LLM risponde con JSON strutturato contenente una decisione
  3. Claude Code elabora automaticamente la decisione

Configurazione

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Evaluate if Claude should stop: $ARGUMENTS. Check if all tasks are complete."
          }
        ]
      }
    ]
  }
}
Campi:
  • type: Deve essere "prompt"
  • prompt: Il testo del prompt da inviare all’LLM
    • Usa $ARGUMENTS come segnaposto per l’input dell’hook JSON
    • Se $ARGUMENTS non è presente, l’input JSON viene aggiunto al prompt
  • timeout: (Opzionale) Timeout in secondi (predefinito: 30 secondi)

Schema di risposta

L’LLM deve rispondere con JSON contenente:
{
  "ok": true | false,
  "reason": "Explanation for the decision"
}
Campi di risposta:
  • ok: true consente l’azione, false la previene
  • reason: Obbligatorio quando ok è false. Spiegazione mostrata a Claude

Eventi di hook supportati

Gli hook basati su prompt funzionano con qualsiasi evento di hook, ma sono più utili per:
  • Stop: Decidere in modo intelligente se Claude dovrebbe continuare a lavorare
  • SubagentStop: Valutare se un subagente ha completato il suo compito
  • UserPromptSubmit: Convalidare i prompt dell’utente con l’assistenza dell’LLM
  • PreToolUse: Prendere decisioni di autorizzazione consapevoli del contesto
  • PermissionRequest: Consentire o negare in modo intelligente i dialoghi di autorizzazione

Esempio: Hook Stop intelligente

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "You are evaluating whether Claude should stop working. Context: $ARGUMENTS\n\nAnalyze the conversation and determine if:\n1. All user-requested tasks are complete\n2. Any errors need to be addressed\n3. Follow-up work is needed\n\nRespond with JSON: {\"ok\": true} to allow stopping, or {\"ok\": false, \"reason\": \"your explanation\"} to continue working.",
            "timeout": 30
          }
        ]
      }
    ]
  }
}

Esempio: SubagentStop con logica personalizzata

{
  "hooks": {
    "SubagentStop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Evaluate if this subagent should stop. Input: $ARGUMENTS\n\nCheck if:\n- The subagent completed its assigned task\n- Any errors occurred that need fixing\n- Additional context gathering is needed\n\nReturn: {\"ok\": true} to allow stopping, or {\"ok\": false, \"reason\": \"explanation\"} to continue."
          }
        ]
      }
    ]
  }
}

Confronto con gli hook di comando bash

FunzionalitàHook di comando BashHook basati su prompt
EsecuzioneEsegue script bashInterroga LLM
Logica decisionaleImplementi nel codiceLLM valuta il contesto
Complessità di configurazioneRichiede file scriptConfigura prompt
Consapevolezza del contestoLimitata alla logica dello scriptComprensione del linguaggio naturale
PrestazioniVeloce (esecuzione locale)Più lento (chiamata API)
Caso d’usoRegole deterministicheDecisioni consapevoli del contesto

Best practice

  • Sii specifico nei prompt: Dichiara chiaramente cosa vuoi che l’LLM valuti
  • Includi criteri decisionali: Elenca i fattori che l’LLM dovrebbe considerare
  • Testa i tuoi prompt: Verifica che l’LLM prenda decisioni corrette per i tuoi casi d’uso
  • Imposta timeout appropriati: L’impostazione predefinita è 30 secondi, regola se necessario
  • Usa per decisioni complesse: Gli hook bash sono migliori per regole semplici e deterministiche
Consulta il riferimento dei componenti del plugin per i dettagli sulla creazione degli hook del plugin.

Eventi di hook

PreToolUse

Viene eseguito dopo che Claude crea i parametri dello strumento e prima di elaborare la chiamata dello strumento. Matcher comuni:
  • Task - Compiti del subagente (consulta la documentazione dei subagenti)
  • Bash - Comandi shell
  • Glob - Corrispondenza di pattern di file
  • Grep - Ricerca di contenuti
  • Read - Lettura di file
  • Edit - Modifica di file
  • Write - Scrittura di file
  • WebFetch, WebSearch - Operazioni web
Usa il controllo decisionale PreToolUse per consentire, negare o chiedere il permesso di utilizzare lo strumento.

PermissionRequest

Viene eseguito quando all’utente viene mostrato un dialogo di autorizzazione. Usa il controllo decisionale PermissionRequest per consentire o negare per conto dell’utente. Riconosce gli stessi valori di matcher di PreToolUse.

PostToolUse

Viene eseguito immediatamente dopo il completamento riuscito di uno strumento. Riconosce gli stessi valori di matcher di PreToolUse.

Notification

Viene eseguito quando Claude Code invia notifiche. Supporta matcher per filtrare per tipo di notifica. Matcher comuni:
  • permission_prompt - Richieste di autorizzazione da Claude Code
  • idle_prompt - Quando Claude è in attesa di input dell’utente (dopo 60+ secondi di inattività)
  • auth_success - Notifiche di successo dell’autenticazione
  • elicitation_dialog - Quando Claude Code ha bisogno di input per l’elicitazione dello strumento MCP
Puoi usare i matcher per eseguire diversi hook per diversi tipi di notifica, o omettere il matcher per eseguire hook per tutte le notifiche. Esempio: Notifiche diverse per tipi diversi
{
  "hooks": {
    "Notification": [
      {
        "matcher": "permission_prompt",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/permission-alert.sh"
          }
        ]
      },
      {
        "matcher": "idle_prompt",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/idle-notification.sh"
          }
        ]
      }
    ]
  }
}

UserPromptSubmit

Viene eseguito quando l’utente invia un prompt, prima che Claude lo elabori. Questo ti consente di aggiungere contesto aggiuntivo in base al prompt/conversazione, convalidare i prompt o bloccare determinati tipi di prompt.

Stop

Viene eseguito quando l’agente Claude Code principale ha finito di rispondere. Non viene eseguito se l’arresto si è verificato a causa di un’interruzione dell’utente.

SubagentStop

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

PreCompact

Viene eseguito prima che Claude Code stia per eseguire un’operazione di compattazione. Matcher:
  • manual - Richiamato da /compact
  • auto - Richiamato da auto-compact (a causa della finestra di contesto piena)

SessionStart

Viene eseguito quando Claude Code avvia una nuova sessione o riprende una sessione esistente (che attualmente avvia una nuova sessione sotto il cofano). Utile per caricare il contesto di sviluppo come problemi esistenti o modifiche recenti al tuo codebase, installare dipendenze o impostare variabili di ambiente. Matcher:
  • startup - Richiamato all’avvio
  • resume - Richiamato da --resume, --continue o /resume
  • clear - Richiamato da /clear
  • compact - Richiamato da compattazione automatica o manuale.

Persistenza delle variabili di ambiente

Gli hook SessionStart hanno accesso alla variabile di ambiente CLAUDE_ENV_FILE, che fornisce un percorso di file in cui puoi persistere le variabili di ambiente per i successivi comandi bash. Esempio: Impostazione di singole variabili di ambiente
#!/bin/bash

if [ -n "$CLAUDE_ENV_FILE" ]; then
  echo 'export NODE_ENV=production' >> "$CLAUDE_ENV_FILE"
  echo 'export API_KEY=your-api-key' >> "$CLAUDE_ENV_FILE"
  echo 'export PATH="$PATH:./node_modules/.bin"' >> "$CLAUDE_ENV_FILE"
fi

exit 0
Esempio: Persistenza di tutti i cambiamenti di ambiente dall’hook Quando la tua configurazione modifica l’ambiente (ad esempio, nvm use), acquisisci e persistisci tutti i cambiamenti confrontando l’ambiente:
#!/bin/bash

ENV_BEFORE=$(export -p | sort)

# Run your setup commands that modify the environment
source ~/.nvm/nvm.sh
nvm use 20

if [ -n "$CLAUDE_ENV_FILE" ]; then
  ENV_AFTER=$(export -p | sort)
  comm -13 <(echo "$ENV_BEFORE") <(echo "$ENV_AFTER") >> "$CLAUDE_ENV_FILE"
fi

exit 0
Qualsiasi variabile scritta in questo file sarà disponibile in tutti i successivi comandi bash che Claude Code esegue durante la sessione.
CLAUDE_ENV_FILE è disponibile solo per gli hook SessionStart. Altri tipi di hook non hanno accesso a questa variabile.

SessionEnd

Viene eseguito quando una sessione Claude Code termina. Utile per attività di pulizia, registrazione delle statistiche della sessione o salvataggio dello stato della sessione. Il campo reason nell’input dell’hook sarà uno di:
  • clear - Sessione cancellata con il comando /clear
  • logout - Utente disconnesso
  • prompt_input_exit - Utente uscito mentre l’input del prompt era visibile
  • other - Altri motivi di uscita

Input dell’hook

Gli hook ricevono dati JSON tramite stdin contenenti informazioni sulla sessione e dati specifici dell’evento:
{
  // Common fields
  session_id: string
  transcript_path: string  // Path to conversation JSON
  cwd: string              // The current working directory when the hook is invoked
  permission_mode: string  // Current permission mode: "default", "plan", "acceptEdits", "dontAsk", or "bypassPermissions"

  // Event-specific fields
  hook_event_name: string
  ...
}

Input PreToolUse

Lo schema esatto per tool_input dipende dallo strumento.
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "PreToolUse",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.txt",
    "content": "file content"
  },
  "tool_use_id": "toolu_01ABC123..."
}

Input PostToolUse

Lo schema esatto per tool_input e tool_response dipende dallo strumento.
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "PostToolUse",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.txt",
    "content": "file content"
  },
  "tool_response": {
    "filePath": "/path/to/file.txt",
    "success": true
  },
  "tool_use_id": "toolu_01ABC123..."
}

Input Notification

{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "Notification",
  "message": "Claude needs your permission to use Bash",
  "notification_type": "permission_prompt"
}

Input UserPromptSubmit

{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "UserPromptSubmit",
  "prompt": "Write a function to calculate the factorial of a number"
}

Input Stop e SubagentStop

stop_hook_active è true quando Claude Code sta già continuando come risultato di un hook di stop. Controlla questo valore o elabora la trascrizione per evitare che Claude Code continui indefinitamente.
{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "permission_mode": "default",
  "hook_event_name": "Stop",
  "stop_hook_active": true
}

Input PreCompact

Per manual, custom_instructions proviene da quello che l’utente passa in /compact. Per auto, custom_instructions è vuoto.
{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "permission_mode": "default",
  "hook_event_name": "PreCompact",
  "trigger": "manual",
  "custom_instructions": ""
}

Input SessionStart

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "permission_mode": "default",
  "hook_event_name": "SessionStart",
  "source": "startup"
}

Input SessionEnd

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "SessionEnd",
  "reason": "exit"
}

Output dell’hook

Ci sono due modi mutuamente esclusivi per gli hook di restituire l’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à verbose (ctrl+o), ad eccezione di UserPromptSubmit e SessionStart, dove stdout viene aggiunto al contesto. L’output JSON in stdout viene analizzato per il controllo strutturato (consulta Avanzate: Output JSON).
  • Codice di uscita 2: Errore di blocco. Solo stderr viene utilizzato come messaggio di errore e restituito a Claude. Il formato è [command]: {stderr}. JSON in stdout non viene elaborato per il codice di uscita 2. Consulta il comportamento per evento di hook di seguito.
  • Altri codici di uscita: Errore non bloccante. stderr viene mostrato all’utente in modalità verbose (ctrl+o) con formato Failed with non-blocking status code: {stderr}. Se stderr è vuoto, mostra No stderr output. L’esecuzione continua.
Promemoria: Claude Code non vede stdout se il codice di uscita è 0, ad eccezione del hook UserPromptSubmit dove stdout viene iniettato come contesto.

Comportamento del codice di uscita 2

Evento di hookComportamento
PreToolUseBlocca la chiamata dello strumento, mostra stderr a Claude
PermissionRequestNega l’autorizzazione, mostra stderr a Claude
PostToolUseMostra stderr a Claude (lo strumento è già stato eseguito)
NotificationN/A, mostra stderr solo all’utente
UserPromptSubmitBlocca l’elaborazione del prompt, cancella il prompt, mostra stderr solo all’utente
StopBlocca l’arresto, mostra stderr a Claude
SubagentStopBlocca l’arresto, mostra stderr al subagente Claude
PreCompactN/A, mostra stderr solo all’utente
SessionStartN/A, mostra stderr solo all’utente
SessionEndN/A, mostra stderr solo all’utente

Avanzate: Output JSON

Gli hook possono restituire JSON strutturato in stdout per un controllo più sofisticato.
L’output JSON viene elaborato solo quando l’hook esce con il codice 0. Se il tuo hook esce con il codice 2 (errore di blocco), il testo stderr viene utilizzato direttamente—qualsiasi JSON in stdout viene ignorato. Per altri codici di uscita diversi da zero, solo stderr viene mostrato all’utente in modalità verbose (ctrl+o).

Campi JSON comuni

Tutti i tipi di hook possono includere questi campi opzionali:
{
  "continue": true, // Whether Claude should continue after hook execution (default: true)
  "stopReason": "string", // Message shown when continue is false

  "suppressOutput": true, // Hide stdout from transcript mode (default: false)
  "systemMessage": "string" // Optional warning message shown to the user
}
Se continue è false, Claude interrompe l’elaborazione dopo l’esecuzione degli hook.
  • Per PreToolUse, questo è diverso da "permissionDecision": "deny", che blocca solo una specifica chiamata dello strumento e fornisce feedback automatico a Claude.
  • Per PostToolUse, questo è diverso da "decision": "block", che fornisce feedback automatizzato a Claude.
  • Per UserPromptSubmit, questo impedisce l’elaborazione del prompt.
  • Per Stop e SubagentStop, questo ha la precedenza su qualsiasi output "decision": "block".
  • In tutti i casi, "continue" = false ha la precedenza su qualsiasi output "decision": "block".
stopReason accompagna continue con un motivo mostrato all’utente, non mostrato a Claude.

Controllo decisionale PreToolUse

Gli hook PreToolUse possono controllare se una chiamata dello strumento procede.
  • "allow" bypassa il sistema di autorizzazione. permissionDecisionReason viene mostrato all’utente ma non a Claude.
  • "deny" impedisce l’esecuzione della chiamata dello strumento. permissionDecisionReason viene mostrato a Claude.
  • "ask" chiede all’utente di confermare la chiamata dello strumento nell’interfaccia utente. permissionDecisionReason viene mostrato all’utente ma non a Claude.
Inoltre, gli hook possono modificare gli input dello strumento prima dell’esecuzione utilizzando updatedInput:
  • updatedInput modifica i parametri di input dello strumento prima dell’esecuzione dello strumento
  • Combina con "permissionDecision": "allow" per modificare l’input e approvare automaticamente la chiamata dello strumento
  • Combina con "permissionDecision": "ask" per modificare l’input e mostrarlo all’utente per la conferma
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow",
    "permissionDecisionReason": "My reason here",
    "updatedInput": {
      "field_to_modify": "new value"
    }
  }
}
I campi decision e reason sono deprecati per gli hook PreToolUse. Usa invece hookSpecificOutput.permissionDecision e hookSpecificOutput.permissionDecisionReason. I campi deprecati "approve" e "block" si mappano a "allow" e "deny" rispettivamente.

Controllo decisionale PermissionRequest

Gli hook PermissionRequest possono consentire o negare le richieste di autorizzazione mostrate all’utente.
  • Per "behavior": "allow" puoi anche facoltativamente passare un "updatedInput" che modifica i parametri di input dello strumento prima dell’esecuzione dello strumento.
  • Per "behavior": "deny" puoi anche facoltativamente passare una stringa "message" che dice al modello perché l’autorizzazione è stata negata, e un booleano "interrupt" che interromperà Claude.
{
  "hookSpecificOutput": {
    "hookEventName": "PermissionRequest",
    "decision": {
      "behavior": "allow",
      "updatedInput": {
        "command": "npm run lint"
      }
    }
  }
}

Controllo decisionale PostToolUse

Gli hook PostToolUse possono fornire feedback a Claude dopo l’esecuzione dello strumento.
  • "block" richiede automaticamente a Claude con reason.
  • undefined non fa nulla. reason viene ignorato.
  • "hookSpecificOutput.additionalContext" aggiunge contesto per Claude da considerare.
{
  "decision": "block" | undefined,
  "reason": "Explanation for decision",
  "hookSpecificOutput": {
    "hookEventName": "PostToolUse",
    "additionalContext": "Additional information for Claude"
  }
}

Controllo decisionale UserPromptSubmit

Gli hook UserPromptSubmit possono controllare se un prompt dell’utente viene elaborato e aggiungere contesto. Aggiunta di contesto (codice di uscita 0): Ci sono due modi per aggiungere contesto alla conversazione:
  1. Stdout di testo semplice (più semplice): Qualsiasi testo non-JSON scritto su stdout viene aggiunto come contesto. Questo è il modo più semplice per iniettare informazioni.
  2. JSON con additionalContext (strutturato): Usa il formato JSON di seguito per un controllo maggiore. Il campo additionalContext viene aggiunto come contesto.
Entrambi i metodi funzionano con il codice di uscita 0. Il testo semplice viene mostrato come output dell’hook nella trascrizione; additionalContext viene aggiunto più discretamente. Blocco dei prompt:
  • "decision": "block" impedisce l’elaborazione del prompt. Il prompt inviato viene cancellato dal contesto. "reason" viene mostrato all’utente ma non aggiunto al contesto.
  • "decision": undefined (o omesso) consente al prompt di procedere normalmente.
{
  "decision": "block" | undefined,
  "reason": "Explanation for decision",
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": "My additional context here"
  }
}
Il formato JSON non è richiesto per i casi d’uso semplici. Per aggiungere contesto, puoi stampare testo semplice su stdout con il codice di uscita 0. Usa JSON quando hai bisogno di bloccare i prompt o vuoi un controllo più strutturato.

Controllo decisionale Stop/SubagentStop

Gli hook Stop e SubagentStop possono controllare se Claude deve continuare.
  • "block" impedisce a Claude di fermarsi. Devi popolare reason affinché Claude sappia come procedere.
  • undefined consente a Claude di fermarsi. reason viene ignorato.
{
  "decision": "block" | undefined,
  "reason": "Must be provided when Claude is blocked from stopping"
}

Controllo decisionale SessionStart

Gli hook SessionStart ti consentono di caricare il contesto all’inizio di una sessione.
  • "hookSpecificOutput.additionalContext" aggiunge la stringa al contesto.
  • I valori additionalContext di più hook vengono concatenati.
{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": "My additional context here"
  }
}

Controllo decisionale SessionEnd

Gli hook SessionEnd vengono eseguiti quando una sessione termina. Non possono bloccare la terminazione della sessione ma possono eseguire attività di pulizia.

Esempio di codice di uscita: Convalidazione del comando Bash

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

# Define validation rules as a list of (regex pattern, message) tuples
VALIDATION_RULES = [
    (
        r"\bgrep\b(?!.*\|)",
        "Use 'rg' (ripgrep) instead of 'grep' for better performance and features",
    ),
    (
        r"\bfind\s+\S+\s+-name\b",
        "Use 'rg --files | rg pattern' or 'rg --files -g pattern' instead of 'find -name' for better performance",
    ),
]


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"Error: Invalid JSON input: {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)

# Validate the command
issues = validate_command(command)

if issues:
    for message in issues:
        print(f"• {message}", file=sys.stderr)
    # Exit code 2 blocks tool call and shows stderr to Claude
    sys.exit(2)

Esempio di output JSON: UserPromptSubmit per aggiungere contesto e convalidazione

Per gli hook UserPromptSubmit, puoi iniettare il contesto utilizzando uno dei due metodi:
  • Stdout di testo semplice con codice di uscita 0: Approccio più semplice, stampa testo
  • Output JSON con codice di uscita 0: Usa "decision": "block" per rifiutare i prompt, o additionalContext per l’iniezione di contesto strutturato
Ricorda: il codice di uscita 2 utilizza solo stderr per il messaggio di errore. Per bloccare utilizzando JSON (con un motivo personalizzato), usa "decision": "block" con il codice di uscita 0.
#!/usr/bin/env python3
import json
import sys
import re
import datetime

# Load input from stdin
try:
    input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
    print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
    sys.exit(1)

prompt = input_data.get("prompt", "")

# Check for sensitive patterns
sensitive_patterns = [
    (r"(?i)\b(password|secret|key|token)\s*[:=]", "Prompt contains potential secrets"),
]

for pattern, message in sensitive_patterns:
    if re.search(pattern, prompt):
        # Use JSON output to block with a specific reason
        output = {
            "decision": "block",
            "reason": f"Security policy violation: {message}. Please rephrase your request without sensitive information."
        }
        print(json.dumps(output))
        sys.exit(0)

# Add current time to context
context = f"Current time: {datetime.datetime.now()}"
print(context)

"""
The following is also equivalent:
print(json.dumps({
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": context,
  },
}))
"""

# Allow the prompt to proceed with the additional context
sys.exit(0)

Esempio di output JSON: PreToolUse con approvazione

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

# Load input from stdin
try:
    input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
    print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
    sys.exit(1)

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

# Example: Auto-approve file reads for documentation files
if tool_name == "Read":
    file_path = tool_input.get("file_path", "")
    if file_path.endswith((".md", ".mdx", ".txt", ".json")):
        # Use JSON output to auto-approve the tool call
        output = {
            "decision": "approve",
            "reason": "Documentation file auto-approved",
            "suppressOutput": True  # Don't show in verbose mode
        }
        print(json.dumps(output))
        sys.exit(0)

# For other cases, let the normal permission flow proceed
sys.exit(0)

Lavoro con gli 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 degli strumenti MCP

Gli strumenti MCP seguono il pattern mcp__<server>__<tool>, ad esempio:
  • mcp__memory__create_entities - Strumento create entities del server Memory
  • mcp__filesystem__read_file - Strumento read file del server Filesystem
  • mcp__github__search_repositories - Strumento search del server GitHub

Configurazione degli hook per gli strumenti MCP

Puoi indirizzare strumenti MCP specifici o interi server MCP:
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "mcp__memory__.*",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Memory operation initiated' >> ~/mcp-operations.log"
          }
        ]
      },
      {
        "matcher": "mcp__.*__write.*",
        "hooks": [
          {
            "type": "command",
            "command": "/home/user/scripts/validate-mcp-write.py"
          }
        ]
      }
    ]
  }
}

Esempi

Per esempi pratici inclusi formattazione del codice, notifiche e protezione dei file, consulta Altri esempi nella guida di avvio.

Considerazioni sulla sicurezza

Disclaimer

UTILIZZO A TUO RISCHIO: Gli hook di Claude Code eseguono comandi shell arbitrari sul tuo sistema automaticamente. Utilizzando gli hook, riconosci che:
  • Sei l’unico responsabile dei comandi che configuri
  • Gli hook possono modificare, eliminare o accedere a qualsiasi file a cui il tuo account utente può accedere
  • Gli hook dannosi o scritti male possono causare perdita di dati o danni al sistema
  • Anthropic non fornisce alcuna garanzia e non assume alcuna responsabilità per eventuali danni derivanti dall’utilizzo degli hook
  • Dovresti testare accuratamente gli hook in un ambiente sicuro prima dell’uso in produzione
Rivedi sempre e comprendi qualsiasi comando di hook prima di aggiungerlo alla tua configurazione.

Best practice di sicurezza

Ecco alcune pratiche chiave per scrivere hook più sicuri:
  1. Convalida e igienizza gli input - Non fidarti mai ciecamente dei dati di input
  2. Cita sempre le variabili shell - Usa "$VAR" non $VAR
  3. Blocca l’attraversamento di percorsi - Controlla .. nei percorsi dei file
  4. Usa percorsi assoluti - Specifica percorsi completi per gli script (usa “$CLAUDE_PROJECT_DIR” per il percorso del progetto)
  5. Salta file sensibili - Evita .env, .git/, chiavi, ecc.

Sicurezza della configurazione

Le modifiche dirette agli hook nei file di impostazioni non hanno effetto immediato. Claude Code:
  1. Acquisisce uno snapshot degli hook all’avvio
  2. Utilizza questo snapshot durante tutta la sessione
  3. Avvisa se gli hook vengono modificati esternamente
  4. Richiede la revisione nel menu /hooks affinché le modifiche abbiano effetto
Questo impedisce che le modifiche degli hook dannose influenzino la tua sessione corrente.

Dettagli dell’esecuzione degli hook

  • Timeout: Limite di esecuzione di 60 secondi per impostazione predefinita, configurabile per comando.
    • Un timeout per un singolo comando non influisce sugli altri comandi.
  • Parallelizzazione: Tutti gli hook corrispondenti vengono eseguiti in parallelo
  • Deduplicazione: I comandi di hook identici multipli vengono automaticamente deduplicati
  • Ambiente: Viene eseguito nella directory corrente con l’ambiente di Claude Code
    • La variabile di ambiente CLAUDE_PROJECT_DIR è disponibile e contiene il percorso assoluto della directory radice del progetto (dove Claude Code è stato avviato)
    • La variabile di ambiente CLAUDE_CODE_REMOTE indica se l’hook è in esecuzione in un ambiente remoto (web) ("true") o ambiente CLI locale (non impostato o vuoto). Usalo per eseguire logica diversa in base al contesto di esecuzione.
  • Input: JSON tramite stdin
  • Output:
    • PreToolUse/PermissionRequest/PostToolUse/Stop/SubagentStop: Progresso mostrato in modalità verbose (ctrl+o)
    • Notification/SessionEnd: Registrato solo per il debug (--debug)
    • UserPromptSubmit/SessionStart: stdout aggiunto come contesto per Claude

Debug

Risoluzione dei problemi di base

Se i tuoi hook non funzionano:
  1. Controlla la configurazione - Esegui /hooks per vedere se il tuo hook è registrato
  2. Verifica la sintassi - Assicurati che le tue impostazioni JSON siano valide
  3. Testa i comandi - Esegui i comandi degli hook manualmente prima
  4. Controlla i permessi - Assicurati che gli script siano eseguibili
  5. Rivedi i log - Usa claude --debug per vedere i dettagli dell’esecuzione degli hook
Problemi comuni:
  • Virgolette non sfuggite - Usa \" all’interno delle stringhe JSON
  • Matcher sbagliato - Controlla che i nomi degli strumenti corrispondano esattamente (sensibile alle maiuscole)
  • Comando non trovato - Usa percorsi completi per gli script

Debug avanzato

Per problemi di hook complessi:
  1. Ispeziona l’esecuzione dell’hook - Usa claude --debug per vedere il debug dettagliato dell’esecuzione
  2. Convalida gli schemi JSON - Testa l’input/output dell’hook con strumenti esterni
  3. Controlla le variabili di ambiente - Verifica che l’ambiente di Claude Code sia corretto
  4. Testa i casi limite - Prova gli hook con percorsi di file o input insoliti
  5. Monitora le risorse di sistema - Controlla l’esaurimento delle risorse durante l’esecuzione dell’hook
  6. Usa la registrazione strutturata - Implementa la registrazione negli script degli hook

Esempio di output di debug

Usa claude --debug per vedere i dettagli dell’esecuzione degli hook:
[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à verbose (ctrl+o) mostrando:
  • Quale hook è in esecuzione
  • Comando in esecuzione
  • Stato di successo/fallimento
  • Messaggi di output o errore