Vai al contenuto principale
Gli hooks sono comandi shell definiti dall’utente che si eseguono in punti specifici del ciclo di vita di Claude Code. Forniscono un controllo deterministico sul comportamento di Claude Code, garantendo che determinate azioni avvengano sempre piuttosto che affidarsi al modello linguistico per scegliere di eseguirle. Utilizzate gli hooks per applicare le regole del progetto, automatizzare attività ripetitive e integrare Claude Code con i vostri strumenti esistenti. Per decisioni che richiedono giudizio piuttosto che regole deterministiche, potete anche utilizzare hooks basati su prompt o hooks basati su agenti che utilizzano un modello Claude per valutare le condizioni. Per altri modi di estendere Claude Code, consultate skills per fornire a Claude istruzioni aggiuntive e comandi eseguibili, subagents per eseguire attività in contesti isolati, e plugins per pacchettizzare estensioni da condividere tra i progetti.
Questa guida copre i casi d’uso comuni e come iniziare. Per schemi di eventi completi, formati di input/output JSON e funzionalità avanzate come hooks asincroni e hooks di strumenti MCP, consultate il riferimento Hooks.

Configurare il vostro primo hook

Per creare un hook, aggiungete un blocco hooks a un file di impostazioni. Questa procedura crea un hook di notifica desktop, in modo da ricevere un avviso ogni volta che Claude sta aspettando il vostro input invece di guardare il terminale.
1

Aggiungere l'hook alle vostre impostazioni

Aprite ~/.claude/settings.json e aggiungete un hook Notification. L’esempio sottostante utilizza osascript per macOS; consultate Ricevere una notifica quando Claude ha bisogno di input per i comandi Linux e Windows.
{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}
Se il vostro file di impostazioni ha già una chiave hooks, unite la voce Notification ad essa piuttosto che sostituire l’intero oggetto. Potete anche chiedere a Claude di scrivere l’hook per voi descrivendo quello che volete nella CLI.
2

Verificare la configurazione

Digitate /hooks per aprire il browser degli hooks. Vedrete un elenco di tutti gli eventi hook disponibili, con un conteggio accanto a ogni evento che ha hook configurati. Selezionate Notification per confermare che il vostro nuovo hook appare nell’elenco. Selezionando l’hook vengono mostrati i suoi dettagli: l’evento, il matcher, il tipo, il file di origine e il comando.
3

Testare l'hook

Premete Esc per tornare alla CLI. Chiedete a Claude di fare qualcosa che richieda autorizzazione, quindi passate a un’altra finestra dal terminale. Dovreste ricevere una notifica desktop.
Il menu /hooks è di sola lettura. Per aggiungere, modificare o rimuovere hooks, modificate il vostro JSON di impostazioni direttamente o chiedete a Claude di fare il cambiamento.

Cosa potete automatizzare

Gli hooks vi permettono di eseguire codice in punti chiave del ciclo di vita di Claude Code: formattare file dopo le modifiche, bloccare comandi prima che si eseguano, inviare notifiche quando Claude ha bisogno di input, iniettare contesto all’inizio della sessione, e altro ancora. Per l’elenco completo degli eventi hook, consultate il riferimento Hooks. Ogni esempio include un blocco di configurazione pronto all’uso che aggiungete a un file di impostazioni. I modelli più comuni:

Ricevere una notifica quando Claude ha bisogno di input

Ricevete una notifica desktop ogni volta che Claude finisce di lavorare e ha bisogno del vostro input, in modo da poter passare ad altri compiti senza controllare il terminale. Questo hook utilizza l’evento Notification, che si attiva quando Claude sta aspettando input o autorizzazione. Ogni scheda sottostante utilizza il comando di notifica nativo della piattaforma. Aggiungete questo a ~/.claude/settings.json:
{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

Formattare automaticamente il codice dopo le modifiche

Eseguite automaticamente Prettier su ogni file che Claude modifica, in modo che la formattazione rimanga coerente senza intervento manuale. Questo hook utilizza l’evento PostToolUse con un matcher Edit|Write, quindi si esegue solo dopo gli strumenti di modifica dei file. Il comando estrae il percorso del file modificato con jq e lo passa a Prettier. Aggiungete questo a .claude/settings.json nella radice del vostro progetto:
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}
Gli esempi Bash in questa pagina utilizzano jq per l’analisi JSON. Installatelo con brew install jq (macOS), apt-get install jq (Debian/Ubuntu), o consultate i download di jq.

Bloccare le modifiche ai file protetti

Impedite a Claude di modificare file sensibili come .env, package-lock.json, o qualsiasi cosa in .git/. Claude riceve un feedback che spiega perché la modifica è stata bloccata, in modo da poter adattare il suo approccio. Questo esempio utilizza un file di script separato che l’hook chiama. Lo script controlla il percorso del file di destinazione rispetto a un elenco di modelli protetti ed esce con il codice 2 per bloccare la modifica.
1

Creare lo script dell'hook

Salvate questo in .claude/hooks/protect-files.sh:
#!/bin/bash
# protect-files.sh

INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")

for pattern in "${PROTECTED_PATTERNS[@]}"; do
  if [[ "$FILE_PATH" == *"$pattern"* ]]; then
    echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
    exit 2
  fi
done

exit 0
2

Rendere lo script eseguibile (macOS/Linux)

Gli script degli hook devono essere eseguibili affinché Claude Code li esegua:
chmod +x .claude/hooks/protect-files.sh
3

Registrare l'hook

Aggiungete un hook PreToolUse a .claude/settings.json che esegue lo script prima di qualsiasi chiamata dello strumento Edit o Write:
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
          }
        ]
      }
    ]
  }
}

Reiniettare il contesto dopo la compattazione

Quando la finestra di contesto di Claude si riempie, la compattazione riassume la conversazione per liberare spazio. Questo può perdere dettagli importanti. Utilizzate un hook SessionStart con un matcher compact per reiniettare il contesto critico dopo ogni compattazione. Qualsiasi testo che il vostro comando scrive su stdout viene aggiunto al contesto di Claude. Questo esempio ricorda a Claude le convenzioni del progetto e il lavoro recente. Aggiungete questo a .claude/settings.json nella radice del vostro progetto:
{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "compact",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Reminder: use Bun, not npm. Run bun test before committing. Current sprint: auth refactor.'"
          }
        ]
      }
    ]
  }
}
Potete sostituire l’echo con qualsiasi comando che produce output dinamico, come git log --oneline -5 per mostrare i commit recenti. Per iniettare contesto all’inizio di ogni sessione, considerate di utilizzare CLAUDE.md invece. Per le variabili di ambiente, consultate CLAUDE_ENV_FILE nel riferimento.

Controllare le modifiche di configurazione

Tracciate quando i file di impostazioni o skills cambiano durante una sessione. L’evento ConfigChange si attiva quando un processo esterno o un editor modifica un file di configurazione, in modo da poter registrare le modifiche per la conformità o bloccare le modifiche non autorizzate. Questo esempio aggiunge ogni modifica a un registro di controllo. Aggiungete questo a ~/.claude/settings.json:
{
  "hooks": {
    "ConfigChange": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "jq -c '{timestamp: now | todate, source: .source, file: .file_path}' >> ~/claude-config-audit.log"
          }
        ]
      }
    ]
  }
}
Il matcher filtra per tipo di configurazione: user_settings, project_settings, local_settings, policy_settings, o skills. Per bloccare una modifica dall’avere effetto, uscite con il codice 2 o restituite {"decision": "block"}. Consultate il riferimento ConfigChange per lo schema di input completo.

Ricaricare l’ambiente quando la directory o i file cambiano

Alcuni progetti impostano variabili di ambiente diverse a seconda di quale directory siete. Strumenti come direnv lo fanno automaticamente nella vostra shell, ma lo strumento Bash di Claude non raccoglie quei cambiamenti da solo. Un hook CwdChanged risolve questo: si esegue ogni volta che Claude cambia directory, in modo da poter ricaricare le variabili corrette per la nuova posizione. L’hook scrive i valori aggiornati su CLAUDE_ENV_FILE, che Claude Code applica prima di ogni comando Bash. Aggiungete questo a ~/.claude/settings.json:
{
  "hooks": {
    "CwdChanged": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "direnv export bash >> \"$CLAUDE_ENV_FILE\""
          }
        ]
      }
    ]
  }
}
Per reagire a file specifici invece di ogni cambio di directory, utilizzate FileChanged con un matcher che elenca i nomi dei file da guardare (separati da pipe). Il matcher sia configura quali file guardare che filtra quali hook si eseguono. Questo esempio guarda .envrc e .env per i cambiamenti nella directory corrente:
{
  "hooks": {
    "FileChanged": [
      {
        "matcher": ".envrc|.env",
        "hooks": [
          {
            "type": "command",
            "command": "direnv export bash >> \"$CLAUDE_ENV_FILE\""
          }
        ]
      }
    ]
  }
}
Consultate le voci di riferimento CwdChanged e FileChanged per gli schemi di input, l’output watchPaths, e i dettagli di CLAUDE_ENV_FILE.

Approvare automaticamente specifici prompt di autorizzazione

Saltate la finestra di dialogo di approvazione per le chiamate di strumenti che consentite sempre. Questo esempio approva automaticamente ExitPlanMode, lo strumento che Claude chiama quando finisce di presentare un piano e chiede di procedere, in modo da non essere richiesto ogni volta che un piano è pronto. A differenza degli esempi di codice di uscita sopra, l’approvazione automatica richiede che il vostro hook scriva una decisione JSON su stdout. Un hook PermissionRequest si attiva quando Claude Code sta per mostrare una finestra di dialogo di autorizzazione, e restituire "behavior": "allow" la risponde per vostro conto. Il matcher limita l’hook a ExitPlanMode solo, in modo che nessun altro prompt sia interessato. Aggiungete questo a ~/.claude/settings.json:
{
  "hooks": {
    "PermissionRequest": [
      {
        "matcher": "ExitPlanMode",
        "hooks": [
          {
            "type": "command",
            "command": "echo '{\"hookSpecificOutput\": {\"hookEventName\": \"PermissionRequest\", \"decision\": {\"behavior\": \"allow\"}}}'"
          }
        ]
      }
    ]
  }
}
Quando l’hook approva, Claude Code esce dalla modalità piano e ripristina qualsiasi modalità di autorizzazione fosse attiva prima di entrare in modalità piano. La trascrizione mostra “Allowed by PermissionRequest hook” dove la finestra di dialogo sarebbe apparsa. Il percorso dell’hook mantiene sempre la conversazione corrente: non può cancellare il contesto e avviare una sessione di implementazione fresca come la finestra di dialogo può. Per impostare una modalità di autorizzazione specifica invece, l’output del vostro hook può includere un array updatedPermissions con una voce setMode. Il valore mode è qualsiasi modalità di autorizzazione come default, acceptEdits, o bypassPermissions, e destination: "session" la applica solo per la sessione corrente. Per passare la sessione a acceptEdits, il vostro hook scrive questo JSON su stdout:
{
  "hookSpecificOutput": {
    "hookEventName": "PermissionRequest",
    "decision": {
      "behavior": "allow",
      "updatedPermissions": [
        { "type": "setMode", "mode": "acceptEdits", "destination": "session" }
      ]
    }
  }
}
Mantenete il matcher il più ristretto possibile. Corrispondere a .* o lasciare il matcher vuoto approverebbe automaticamente ogni prompt di autorizzazione, incluse le scritture di file e i comandi shell. Consultate il riferimento PermissionRequest per l’insieme completo di campi di decisione.

Come funzionano gli hooks

Gli eventi hook si attivano in punti specifici del ciclo di vita di Claude Code. Quando un evento si attiva, tutti gli hooks corrispondenti si eseguono in parallelo, e i comandi hook identici vengono automaticamente deduplicati. La tabella sottostante mostra ogni evento e quando si attiva:
EventWhen it fires
SessionStartWhen a session begins or resumes
UserPromptSubmitWhen you submit a prompt, before Claude processes it
PreToolUseBefore a tool call executes. Can block it
PermissionRequestWhen a permission dialog appears
PermissionDeniedWhen a tool call is denied by the auto mode classifier. Return {retry: true} to tell the model it may retry the denied tool call
PostToolUseAfter a tool call succeeds
PostToolUseFailureAfter a tool call fails
NotificationWhen Claude Code sends a notification
SubagentStartWhen a subagent is spawned
SubagentStopWhen a subagent finishes
TaskCreatedWhen a task is being created via TaskCreate
TaskCompletedWhen a task is being marked as completed
StopWhen Claude finishes responding
StopFailureWhen the turn ends due to an API error. Output and exit code are ignored
TeammateIdleWhen an agent team teammate is about to go idle
InstructionsLoadedWhen a CLAUDE.md or .claude/rules/*.md file is loaded into context. Fires at session start and when files are lazily loaded during a session
ConfigChangeWhen a configuration file changes during a session
CwdChangedWhen the working directory changes, for example when Claude executes a cd command. Useful for reactive environment management with tools like direnv
FileChangedWhen a watched file changes on disk. The matcher field specifies which filenames to watch
WorktreeCreateWhen a worktree is being created via --worktree or isolation: "worktree". Replaces default git behavior
WorktreeRemoveWhen a worktree is being removed, either at session exit or when a subagent finishes
PreCompactBefore context compaction
PostCompactAfter context compaction completes
ElicitationWhen an MCP server requests user input during a tool call
ElicitationResultAfter a user responds to an MCP elicitation, before the response is sent back to the server
SessionEndWhen a session terminates
Ogni hook ha un type che determina come si esegue. La maggior parte degli hooks utilizza "type": "command", che esegue un comando shell. Sono disponibili altri tre tipi:

Leggere l’input e restituire l’output

Gli hooks comunicano con Claude Code attraverso stdin, stdout, stderr e codici di uscita. Quando un evento si attiva, Claude Code passa i dati specifici dell’evento come JSON allo stdin del vostro script. Il vostro script legge quei dati, fa il suo lavoro, e dice a Claude Code cosa fare dopo tramite il codice di uscita.

Input dell’hook

Ogni evento include campi comuni come session_id e cwd, ma ogni tipo di evento aggiunge dati diversi. Ad esempio, quando Claude esegue un comando Bash, un hook PreToolUse riceve qualcosa di simile su stdin:
{
  "session_id": "abc123",          // unique ID for this session
  "cwd": "/Users/sarah/myproject", // working directory when the event fired
  "hook_event_name": "PreToolUse", // which event triggered this hook
  "tool_name": "Bash",             // the tool Claude is about to use
  "tool_input": {                  // the arguments Claude passed to the tool
    "command": "npm test"          // for Bash, this is the shell command
  }
}
Il vostro script può analizzare quel JSON e agire su qualsiasi di quei campi. Gli hooks UserPromptSubmit ricevono il testo prompt invece, gli hook SessionStart ricevono la source (startup, resume, clear, compact), e così via. Consultate Campi di input comuni nel riferimento per i campi condivisi, e la sezione di ogni evento per gli schemi specifici dell’evento.

Output dell’hook

Il vostro script dice a Claude Code cosa fare dopo scrivendo su stdout o stderr e uscendo con un codice specifico. Ad esempio, un hook PreToolUse che vuole bloccare un comando:
#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')

if echo "$COMMAND" | grep -q "drop table"; then
  echo "Blocked: dropping tables is not allowed" >&2  # stderr becomes Claude's feedback
  exit 2 # exit 2 = block the action
fi

exit 0  # exit 0 = let it proceed
Il codice di uscita determina cosa succede dopo:
  • Exit 0: l’azione procede. Per gli hook UserPromptSubmit e SessionStart, qualsiasi cosa scriviate su stdout viene aggiunta al contesto di Claude.
  • Exit 2: l’azione è bloccata. Scrivete un motivo su stderr, e Claude lo riceve come feedback in modo da poter adattarsi.
  • Qualsiasi altro codice di uscita: l’azione procede. Stderr viene registrato ma non mostrato a Claude. Attivate la modalità verbose con Ctrl+O per vedere questi messaggi nella trascrizione.

Output JSON strutturato

I codici di uscita vi danno due opzioni: consentire o bloccare. Per un controllo maggiore, uscite con 0 e stampate un oggetto JSON su stdout invece.
Utilizzate exit 2 per bloccare con un messaggio stderr, o exit 0 con JSON per un controllo strutturato. Non mescolateli: Claude Code ignora JSON quando uscite con 2.
Ad esempio, un hook PreToolUse può negare una chiamata di strumento e dire a Claude perché, o escalarlo all’utente per l’approvazione:
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Use rg instead of grep for better performance"
  }
}
Claude Code legge permissionDecision e annulla la chiamata dello strumento, quindi alimenta permissionDecisionReason di nuovo a Claude come feedback. Queste tre opzioni sono specifiche per PreToolUse:
  • "allow": procedi senza mostrare un prompt di autorizzazione interattivo. Le regole di negazione e richiesta, incluse le liste di negazione gestite dall’azienda, si applicano ancora
  • "deny": annulla la chiamata dello strumento e invia il motivo a Claude
  • "ask": mostra il prompt di autorizzazione all’utente come al solito
Restituire "allow" salta il prompt interattivo ma non sostituisce le regole di autorizzazione. Se una regola di negazione corrisponde alla chiamata dello strumento, la chiamata viene bloccata anche quando il vostro hook restituisce "allow". Se una regola di richiesta corrisponde, l’utente viene comunque richiesto. Questo significa che le regole di negazione da qualsiasi ambito di impostazioni, incluse le impostazioni gestite, hanno sempre la precedenza sulle approvazioni degli hook. Altri eventi utilizzano modelli di decisione diversi. Ad esempio, gli hook PostToolUse e Stop utilizzano un campo decision: "block" di livello superiore, mentre PermissionRequest utilizza hookSpecificOutput.decision.behavior. Consultate la tabella di riepilogo nel riferimento per una suddivisione completa per evento. Per gli hook UserPromptSubmit, utilizzate additionalContext invece per iniettare testo nel contesto di Claude. Gli hooks basati su prompt (type: "prompt") gestiscono l’output diversamente: consultate Hooks basati su prompt.

Filtrare gli hooks con i matcher

Senza un matcher, un hook si attiva su ogni occorrenza del suo evento. I matcher vi permettono di restringerlo. Ad esempio, se volete eseguire un formattatore solo dopo le modifiche ai file (non dopo ogni chiamata di strumento), aggiungete un matcher al vostro hook PostToolUse:
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "prettier --write ..." }
        ]
      }
    ]
  }
}
Il matcher "Edit|Write" è un modello regex che corrisponde al nome dello strumento. L’hook si attiva solo quando Claude utilizza lo strumento Edit o Write, non quando utilizza Bash, Read, o qualsiasi altro strumento. Ogni tipo di evento corrisponde a un campo specifico. I matcher supportano stringhe esatte e modelli regex:
EventoCosa filtra il matcherValori matcher di esempio
PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequestnome dello strumentoBash, Edit|Write, mcp__.*
SessionStartcome è iniziata la sessionestartup, resume, clear, compact
SessionEndperché è terminata la sessioneclear, resume, logout, prompt_input_exit, bypass_permissions_disabled, other
Notificationtipo di notificapermission_prompt, idle_prompt, auth_success, elicitation_dialog
SubagentStarttipo di agenteBash, Explore, Plan, o nomi di agenti personalizzati
PreCompact, PostCompactcosa ha attivato la compattazionemanual, auto
SubagentStoptipo di agentestessi valori di SubagentStart
ConfigChangefonte di configurazioneuser_settings, project_settings, local_settings, policy_settings, skills
StopFailuretipo di errorerate_limit, authentication_failed, billing_error, invalid_request, server_error, max_output_tokens, unknown
InstructionsLoadedmotivo del caricamentosession_start, nested_traversal, path_glob_match, include, compact
Elicitationnome del server MCPi vostri nomi di server MCP configurati
ElicitationResultnome del server MCPstessi valori di Elicitation
FileChangednome del file (basename del file modificato).envrc, .env, qualsiasi nome di file che volete guardare
UserPromptSubmit, Stop, TeammateIdle, TaskCompleted, WorktreeCreate, WorktreeRemove, CwdChangednessun supporto matchersi attiva sempre su ogni occorrenza
Alcuni altri esempi che mostrano i matcher su diversi tipi di evento:
Corrispondere solo alle chiamate dello strumento Bash e registrare ogni comando in un file. L’evento PostToolUse si attiva dopo che il comando è completato, quindi tool_input.command contiene quello che è stato eseguito. L’hook riceve i dati dell’evento come JSON su stdin, e jq -r '.tool_input.command' estrae solo la stringa del comando, che >> aggiunge al file di log:
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.command' >> ~/.claude/command-log.txt"
          }
        ]
      }
    ]
  }
}
Per la sintassi completa del matcher, consultate il riferimento Hooks.

Configurare la posizione dell’hook

Dove aggiungete un hook determina il suo ambito:
PosizioneAmbitoCondivisibile
~/.claude/settings.jsonTutti i vostri progettiNo, locale alla vostra macchina
.claude/settings.jsonSingolo progettoSì, può essere committato nel repo
.claude/settings.local.jsonSingolo progettoNo, gitignored
Impostazioni di policy gestiteOrganizzazione interaSì, controllato dall’amministratore
Plugin hooks/hooks.jsonQuando il plugin è abilitatoSì, raggruppato con il plugin
Skill o agente frontmatterMentre la skill o l’agente è attivoSì, definito nel file del componente
Eseguite /hooks in Claude Code per sfogliare tutti gli hooks configurati raggruppati per evento. Per disabilitare tutti gli hooks contemporaneamente, impostate "disableAllHooks": true nel vostro file di impostazioni. Se modificate i file di impostazioni direttamente mentre Claude Code è in esecuzione, il file watcher normalmente raccoglie i cambiamenti degli hook automaticamente.

Hooks basati su prompt

Per decisioni che richiedono giudizio piuttosto che regole deterministiche, utilizzate gli hook type: "prompt". Invece di eseguire un comando shell, Claude Code invia il vostro prompt e i dati di input dell’hook a un modello Claude (Haiku per impostazione predefinita) per prendere la decisione. Potete specificare un modello diverso con il campo model se avete bisogno di più capacità. L’unico lavoro del modello è restituire una decisione sì/no come JSON:
  • "ok": true: l’azione procede
  • "ok": false: l’azione è bloccata. Il "reason" del modello viene alimentato di nuovo a Claude in modo da poter adattarsi.
Questo esempio utilizza un hook Stop per chiedere al modello se tutti i compiti richiesti sono completi. Se il modello restituisce "ok": false, Claude continua a lavorare e utilizza il reason come sua prossima istruzione:
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Check if all tasks are complete. If not, respond with {\"ok\": false, \"reason\": \"what remains to be done\"}."
          }
        ]
      }
    ]
  }
}
Per le opzioni di configurazione complete, consultate Hooks basati su prompt nel riferimento.

Hooks basati su agenti

Quando la verifica richiede l’ispezione di file o l’esecuzione di comandi, utilizzate gli hook type: "agent". A differenza degli hook di prompt che effettuano una singola chiamata LLM, gli hook di agenti generano un subagent che può leggere file, cercare codice e utilizzare altri strumenti per verificare le condizioni prima di restituire una decisione. Gli hook di agenti utilizzano lo stesso formato di risposta "ok" / "reason" degli hook di prompt, ma con un timeout predefinito più lungo di 60 secondi e fino a 50 turni di utilizzo dello strumento. Questo esempio verifica che i test passino prima di consentire a Claude di fermarsi:
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "agent",
            "prompt": "Verify that all unit tests pass. Run the test suite and check the results. $ARGUMENTS",
            "timeout": 120
          }
        ]
      }
    ]
  }
}
Utilizzate gli hook di prompt quando i dati di input dell’hook da soli sono sufficienti per prendere una decisione. Utilizzate gli hook di agenti quando avete bisogno di verificare qualcosa rispetto allo stato effettivo della base di codice. Per le opzioni di configurazione complete, consultate Hooks basati su agenti nel riferimento.

HTTP hooks

Utilizzate gli hook type: "http" per POST dei dati dell’evento a un endpoint HTTP invece di eseguire un comando shell. L’endpoint riceve lo stesso JSON che un hook di comando riceverebbe su stdin, e restituisce i risultati attraverso il corpo della risposta HTTP utilizzando lo stesso formato JSON. Gli HTTP hooks sono utili quando volete che un server web, una funzione cloud o un servizio esterno gestisca la logica dell’hook: ad esempio, un servizio di controllo condiviso che registra gli eventi di utilizzo dello strumento in un team. Questo esempio pubblica ogni utilizzo dello strumento a un servizio di registrazione locale:
{
  "hooks": {
    "PostToolUse": [
      {
        "hooks": [
          {
            "type": "http",
            "url": "http://localhost:8080/hooks/tool-use",
            "headers": {
              "Authorization": "Bearer $MY_TOKEN"
            },
            "allowedEnvVars": ["MY_TOKEN"]
          }
        ]
      }
    ]
  }
}
L’endpoint dovrebbe restituire un corpo di risposta JSON utilizzando lo stesso formato di output degli hook di comando. Per bloccare una chiamata di strumento, restituite una risposta 2xx con i campi hookSpecificOutput appropriati. I codici di stato HTTP da soli non possono bloccare le azioni. I valori dell’intestazione supportano l’interpolazione delle variabili di ambiente utilizzando la sintassi $VAR_NAME o ${VAR_NAME}. Solo le variabili elencate nell’array allowedEnvVars vengono risolte; tutti gli altri riferimenti $VAR rimangono vuoti. Per le opzioni di configurazione complete e la gestione delle risposte, consultate HTTP hooks nel riferimento.

Limitazioni e risoluzione dei problemi

Limitazioni

  • Gli hook di comando comunicano solo attraverso stdout, stderr e codici di uscita. Non possono attivare comandi o chiamate di strumenti direttamente. Gli HTTP hooks comunicano attraverso il corpo della risposta invece.
  • Il timeout dell’hook è di 10 minuti per impostazione predefinita, configurabile per hook con il campo timeout (in secondi).
  • Gli hook PostToolUse non possono annullare le azioni poiché lo strumento è già stato eseguito.
  • Gli hook PermissionRequest non si attivano in modalità non interattiva (-p). Utilizzate gli hook PreToolUse per le decisioni di autorizzazione automatizzate.
  • Gli hook Stop si attivano ogni volta che Claude finisce di rispondere, non solo al completamento dell’attività. Non si attivano su interruzioni dell’utente. Gli errori API attivano StopFailure invece.

Hook non si attiva

L’hook è configurato ma non si esegue mai.
  • Eseguite /hooks e confermate che l’hook appare sotto l’evento corretto
  • Controllate che il modello del matcher corrisponda esattamente al nome dello strumento (i matcher sono sensibili alle maiuscole)
  • Verificate che state attivando il tipo di evento corretto (ad esempio, PreToolUse si attiva prima dell’esecuzione dello strumento, PostToolUse si attiva dopo)
  • Se utilizzate gli hook PermissionRequest in modalità non interattiva (-p), passate a PreToolUse invece

Errore dell’hook nell’output

Vedete un messaggio come “PreToolUse hook error: …” nella trascrizione.
  • Il vostro script è uscito con un codice diverso da zero inaspettatamente. Testatelo manualmente inviando JSON di esempio:
    echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh
    echo $?  # Check the exit code
    
  • Se vedete “command not found”, utilizzate percorsi assoluti o $CLAUDE_PROJECT_DIR per fare riferimento agli script
  • Se vedete “jq: command not found”, installate jq o utilizzate Python/Node.js per l’analisi JSON
  • Se lo script non si esegue affatto, rendetelo eseguibile: chmod +x ./my-hook.sh

/hooks non mostra hook configurati

Avete modificato un file di impostazioni ma gli hooks non appaiono nel menu.
  • Le modifiche ai file vengono normalmente raccolte automaticamente. Se non sono apparse dopo alcuni secondi, il file watcher potrebbe aver perso il cambiamento: riavviate la vostra sessione per forzare un ricaricamento.
  • Verificate che il vostro JSON sia valido (le virgole finali e i commenti non sono consentiti)
  • Confermate che il file di impostazioni è nella posizione corretta: .claude/settings.json per gli hook del progetto, ~/.claude/settings.json per gli hook globali

L’hook Stop si esegue per sempre

Claude continua a lavorare in un ciclo infinito invece di fermarsi. Il vostro script di hook Stop deve controllare se ha già attivato una continuazione. Analizzate il campo stop_hook_active dall’input JSON e uscite presto se è true:
#!/bin/bash
INPUT=$(cat)
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
  exit 0  # Allow Claude to stop
fi
# ... rest of your hook logic

Convalida JSON non riuscita

Claude Code mostra un errore di analisi JSON anche se il vostro script di hook produce JSON valido. Quando Claude Code esegue un hook, genera una shell che fornisce il vostro profilo (~/.zshrc o ~/.bashrc). Se il vostro profilo contiene istruzioni echo incondizionate, quell’output viene anteposto al vostro JSON dell’hook:
Shell ready on arm64
{"decision": "block", "reason": "Not allowed"}
Claude Code tenta di analizzare questo come JSON e fallisce. Per risolvere questo, avvolgete le istruzioni echo nel vostro profilo shell in modo che si eseguano solo in shell interattive:
# In ~/.zshrc or ~/.bashrc
if [[ $- == *i* ]]; then
  echo "Shell ready"
fi
La variabile $- contiene i flag della shell, e i significa interattiva. Gli hooks si eseguono in shell non interattive, quindi l’echo viene saltato.

Tecniche di debug

Attivate la modalità verbose con Ctrl+O per vedere l’output dell’hook nella trascrizione, o eseguite claude --debug per i dettagli di esecuzione completi incluso quali hook hanno corrisposto e i loro codici di uscita.

Ulteriori informazioni