- Bloccare operazioni pericolose prima che vengano eseguite, come comandi shell distruttivi o accesso a file non autorizzato
- Registrare e controllare ogni chiamata a uno strumento per conformità, debug o analitiche
- Trasformare input e output per sanitizzare i dati, iniettare credenziali o reindirizzare i percorsi dei file
- Richiedere approvazione umana per azioni sensibili come scritture su database o chiamate API
- Tracciare il ciclo di vita della sessione per gestire lo stato, pulire le risorse o inviare notifiche
Come funzionano gli hooks
Un evento si attiva
Qualcosa accade durante l’esecuzione dell’agente e l’SDK attiva un evento: uno strumento sta per essere chiamato (
PreToolUse), uno strumento ha restituito un risultato (PostToolUse), un subagente è stato avviato o interrotto, l’agente è inattivo o l’esecuzione è terminata. Consultate l’elenco completo degli eventi.L'SDK raccoglie gli hooks registrati
L’SDK verifica la presenza di hooks registrati per quel tipo di evento. Questo include gli hooks di callback che passate in
options.hooks e gli hooks dei comandi shell dai file di impostazioni quando la voce settingSources o setting_sources corrispondente è abilitata, come avviene per le opzioni predefinite di query().I matcher filtrano quali hooks vengono eseguiti
Se un hook ha un modello
matcher (come "Write|Edit"), l’SDK lo testa rispetto al target dell’evento (ad esempio, il nome dello strumento). Gli hooks senza un matcher vengono eseguiti per ogni evento di quel tipo.Le funzioni di callback vengono eseguite
Ogni hook corrispondente riceve la sua funzione di callback con input su ciò che sta accadendo: il nome dello strumento, i suoi argomenti, l’ID della sessione e altri dettagli specifici dell’evento.
Il vostro callback restituisce una decisione
Dopo aver eseguito qualsiasi operazione (registrazione, chiamate API, convalida), il vostro callback restituisce un oggetto di output che dice all’agente cosa fare: consentire l’operazione, bloccarla, modificare l’input o iniettare contesto nella conversazione.
PreToolUse (passaggio 1) con un matcher "Write|Edit" (passaggio 3) in modo che il callback si attivi solo per gli strumenti di scrittura di file. Quando attivato, il callback riceve l’input dello strumento (passaggio 4), verifica se il percorso del file è destinato a un file .env e restituisce permissionDecision: "deny" per bloccare l’operazione (passaggio 5):
Hook disponibili
L’SDK fornisce hooks per diverse fasi dell’esecuzione dell’agente. Alcuni hooks sono disponibili in entrambi gli SDK, mentre altri sono solo per TypeScript.| Hook Event | Python SDK | TypeScript SDK | Cosa lo attiva | Caso d’uso di esempio |
|---|---|---|---|---|
PreToolUse | Sì | Sì | Richiesta di chiamata a uno strumento (può bloccare o modificare) | Bloccare comandi shell pericolosi |
PostToolUse | Sì | Sì | Risultato dell’esecuzione dello strumento | Registrare tutte le modifiche ai file nel registro di controllo |
PostToolUseFailure | Sì | Sì | Errore di esecuzione dello strumento | Gestire o registrare errori dello strumento |
PostToolBatch | No | Sì | Un intero batch di chiamate a strumenti si risolve, una volta per batch prima della prossima chiamata al modello | Iniettare convenzioni una volta per l’intero batch |
UserPromptSubmit | Sì | Sì | Invio del prompt dell’utente | Iniettare contesto aggiuntivo nei prompt |
MessageDisplay | No | Sì | Un messaggio dell’assistente con testo si completa, una volta per messaggio con il testo completo del messaggio | Oscurare o riformattare il testo visualizzato senza modificare la trascrizione |
Stop | Sì | Sì | Arresto dell’esecuzione dell’agente | Salvare lo stato della sessione prima dell’uscita |
SubagentStart | Sì | Sì | Inizializzazione del subagente | Tracciare l’avvio di attività parallele |
SubagentStop | Sì | Sì | Completamento del subagente | Aggregare i risultati dalle attività parallele |
PreCompact | Sì | Sì | Richiesta di compattazione della conversazione | Archiviare la trascrizione completa prima del riepilogo |
PermissionRequest | Sì | Sì | La finestra di dialogo delle autorizzazioni verrebbe visualizzata | Gestione personalizzata delle autorizzazioni |
SessionStart | No | Sì | Inizializzazione della sessione | Inizializzare la registrazione e la telemetria |
SessionEnd | No | Sì | Terminazione della sessione | Pulire le risorse temporanee |
Notification | Sì | Sì | Messaggi di stato dell’agente | Inviare aggiornamenti dello stato dell’agente a Slack o PagerDuty |
Setup | No | Sì | Configurazione/manutenzione della sessione | Eseguire attività di inizializzazione |
TeammateIdle | No | Sì | Il compagno di squadra diventa inattivo | Riassegnare il lavoro o notificare |
TaskCompleted | No | Sì | L’attività in background si completa | Aggregare i risultati dalle attività parallele |
ConfigChange | No | Sì | Il file di configurazione cambia | Ricaricare le impostazioni dinamicamente |
WorktreeCreate | No | Sì | Git worktree creato | Tracciare gli spazi di lavoro isolati |
WorktreeRemove | No | Sì | Git worktree rimosso | Pulire le risorse dello spazio di lavoro |
Configurare gli hooks
Per configurare un hook, passatelo nel campohooks delle opzioni dell’agente (ClaudeAgentOptions in Python, l’oggetto options in TypeScript):
hooks è un dizionario (Python) o un oggetto (TypeScript) dove:
- Le chiavi sono nomi degli eventi hook (ad es.
'PreToolUse','PostToolUse','Stop') - I valori sono array di matcher, ognuno contenente un modello di filtro opzionale e le vostre funzioni di callback
Matcher
Utilizzate i matcher per filtrare quando i vostri callback si attivano. Il campomatcher corrisponde a un valore diverso a seconda del tipo di evento hook. Ad esempio, gli hook basati su strumenti corrispondono al nome dello strumento, mentre gli hook Notification corrispondono al tipo di notifica. Consultate il riferimento degli hooks di Claude Code per l’elenco completo dei valori di matcher per ogni tipo di evento.
I matcher SDK seguono le stesse regole dei matcher nei file di impostazioni: un matcher contenente solo lettere, cifre, _ e | viene confrontato come una stringa esatta, con | che separa le alternative, quindi Write|Edit corrisponde esattamente a questi due strumenti. Un matcher di *, una stringa vuota, o l’omissione del matcher interamente corrisponde a ogni occorrenza dell’evento; un matcher contenente qualsiasi altro carattere viene valutato come un’espressione regolare, quindi ^mcp__ corrisponde a ogni strumento MCP. Un matcher come mcp__memory contiene solo lettere e sottolineature, quindi viene confrontato come una stringa esatta e non corrisponde a nessuno strumento; utilizzate mcp__memory__.* per corrispondere a ogni strumento da quel server.
| Opzione | Tipo | Predefinito | Descrizione |
|---|---|---|---|
matcher | string | undefined | Modello abbinato al campo di filtro dell’evento, seguendo le regole di confronto sopra. Per gli hook degli strumenti, questo è il nome dello strumento. Gli strumenti incorporati includono Bash, Read, Write, Edit, Glob, Grep, WebFetch, Agent e altri (consultate Tipi di input degli strumenti per l’elenco completo). Gli strumenti MCP utilizzano il modello mcp__<server>__<action>. |
hooks | HookCallback[] | - | Obbligatorio. Array di funzioni di callback da eseguire quando il modello corrisponde |
timeout | number | 60 | Timeout in secondi |
matcher per indirizzare strumenti specifici quando possibile. Un matcher con 'Bash' viene eseguito solo per i comandi Bash, mentre omettere il modello esegue i vostri callback per ogni occorrenza dell’evento. Notate che per gli hook basati su strumenti, i matcher filtrano solo per nome dello strumento, non per percorsi di file o altri argomenti. Per filtrare per percorso di file, controllate tool_input.file_path all’interno del vostro callback.
Funzioni di callback
Input
Ogni callback hook riceve tre argomenti:- Dati di input: un oggetto tipizzato contenente i dettagli dell’evento. Ogni tipo di hook ha la sua forma di input (ad esempio,
PreToolUseHookInputincludetool_nameetool_input, mentreNotificationHookInputincludemessage). Consultate le definizioni di tipo complete nei riferimenti SDK TypeScript e Python.- Tutti gli input hook condividono
session_id,cwdehook_event_name. agent_ideagent_typevengono popolati quando l’hook si attiva all’interno di un subagente. In TypeScript, questi si trovano sull’input hook di base e sono disponibili per tutti i tipi di hook. In Python, si trovano solo suPreToolUse,PostToolUseePostToolUseFailure.
- Tutti gli input hook condividono
- ID di utilizzo dello strumento (
str | None/string | undefined): correla gli eventiPreToolUseePostToolUseper la stessa chiamata a uno strumento. - Contesto: in TypeScript, contiene una proprietà
signal(AbortSignal) per l’annullamento. In Python, questo argomento è riservato per uso futuro.
Output
Il vostro callback restituisce un oggetto con due categorie di campi:- Campi di livello superiore funzionano allo stesso modo su ogni evento:
systemMessagemostra un messaggio all’utente, econtinue(continue_in Python) determina se l’agente continua a funzionare dopo questo hook. hookSpecificOutputcontrolla l’operazione corrente. I campi all’interno dipendono dal tipo di evento hook. Per gli hookPreToolUse, è qui che impostatepermissionDecision("allow","deny","ask"o"defer"),permissionDecisionReasoneupdatedInput. Restituire"defer"termina la query in modo da poter riprendere in seguito. Per gli hookPostToolUse, potete impostareadditionalContextper aggiungere informazioni al risultato dello strumento. Per sostituire l’output dello strumento prima che Claude lo veda, impostateupdatedToolOutput, che funziona per qualsiasi strumento in entrambi gli SDK. Il campo più vecchioupdatedMCPToolOutputsostituisce solo l’output dello strumento MCP ed è deprecato.
{} per consentire l’operazione senza modifiche. Gli hook di callback SDK utilizzano lo stesso formato di output JSON degli hook dei comandi shell di Claude Code, che documenta ogni campo e opzione specifica dell’evento. Per le definizioni di tipo SDK, consultate i riferimenti SDK TypeScript e Python.
Quando si applicano più hook o regole di autorizzazione, deny ha priorità su defer, che ha priorità su ask, che ha priorità su allow. Se un hook restituisce
deny, l’operazione viene bloccata indipendentemente dagli altri hook.Output asincrono
Per impostazione predefinita, l’agente attende che il vostro hook restituisca prima di procedere. Se il vostro hook esegue un effetto collaterale (registrazione, invio di un webhook) e non ha bisogno di influenzare il comportamento dell’agente, potete restituire un output asincrono. Questo dice all’agente di continuare immediatamente senza attendere il completamento dell’hook:| Campo | Tipo | Descrizione |
|---|---|---|
async | true | Segnala la modalità asincrona. L’agente procede senza attendere. In Python, utilizzate async_ per evitare la parola chiave riservata. |
asyncTimeout | number | Timeout opzionale in millisecondi per l’operazione in background |
Gli output asincroni non possono bloccare, modificare o iniettare contesto nell’operazione poiché l’agente ha già proseguito. Utilizzateli solo per effetti collaterali come registrazione, metriche o notifiche.
Esempi
Modificare l’input dello strumento
Questo esempio intercetta le chiamate allo strumento Write e riscrive l’argomentofile_path per anteporre /sandbox, reindirizzando tutte le scritture di file a una directory sandbox. Il callback restituisce updatedInput con il percorso modificato e permissionDecision: 'allow' per approvare automaticamente l’operazione riscritta:
Quando utilizzate
updatedInput, dovete anche includere permissionDecision: 'allow' per approvare automaticamente l’input modificato o permissionDecision: 'ask' per mostrarlo all’utente. Con 'defer', updatedInput viene ignorato. Restituite sempre un nuovo oggetto piuttosto che mutare l’originale tool_input.Aggiungere contesto e bloccare uno strumento
Questo esempio blocca le scritture nella directory/etc e spiega il motivo sia al modello che all’utente:
permissionDecision: 'deny'interrompe la chiamata dello strumento.permissionDecisionReasoncomunica al modello il motivo, in modo che eviti di ritentare.systemMessagemostra all’utente cosa è accaduto.
Approvare automaticamente strumenti specifici
Per impostazione predefinita, l’agente potrebbe richiedere l’autorizzazione prima di utilizzare determinati strumenti. Questo esempio approva automaticamente gli strumenti del file system di sola lettura (Read, Glob, Grep) restituendopermissionDecision: 'allow', consentendo loro di funzionare senza conferma dell’utente mentre lascia tutti gli altri strumenti soggetti ai normali controlli di autorizzazione:
Registrare più hook
Quando un evento si attiva, tutti gli hook corrispondenti vengono eseguiti in parallelo. Per le decisioni di autorizzazione, il risultato più restrittivo vince: un singolodeny blocca la chiamata dello strumento indipendentemente da ciò che gli altri hook restituiscono. Poiché l’ordine di completamento è non deterministico, scrivete ogni hook per agire in modo indipendente piuttosto che fare affidamento su un altro hook che sia stato eseguito per primo.
L’esempio seguente registra tre controlli indipendenti per ogni chiamata a uno strumento:
Filtrare con matcher multi-strumento
Utilizzate matcher multi-strumento per condividere un callback tra strumenti correlati. Questo esempio registra tre matcher con ambiti diversi:- Un elenco esatto separato da pipe (
Write|Edit|Delete) attivafile_security_hooksolo per gli strumenti di modifica dei file. - Un’espressione regolare (
^mcp__) attivamcp_audit_hookper qualsiasi strumento MCP il cui nome inizia conmcp__. - Un matcher omesso attiva
global_loggerper ogni chiamata a uno strumento indipendentemente dal nome.
Tracciare l’attività dei subagenti
Utilizzate gli hookSubagentStop per monitorare quando i subagenti completano il loro lavoro. Consultate il tipo di input completo nei riferimenti SDK TypeScript e Python. Questo esempio registra un riepilogo ogni volta che un subagente si completa:
Effettuare richieste HTTP dagli hooks
Gli hooks possono eseguire operazioni asincrone come richieste HTTP. Catturate gli errori all’interno del vostro hook invece di lasciarli propagare, poiché un’eccezione non gestita può interrompere l’agente. Questo esempio invia un webhook dopo il completamento di ogni strumento, registrando quale strumento è stato eseguito e quando. L’hook cattura gli errori in modo che un webhook non riuscito non interrompa l’agente:Inoltrare le notifiche a Slack
Utilizzate gli hookNotification per ricevere notifiche di sistema dall’agente e inoltrarle a servizi esterni. Le notifiche si attivano per tipi di evento specifici come:
permission_promptquando Claude ha bisogno di autorizzazioneidle_promptquando Claude è in attesa di inputauth_successquando l’autenticazione si completaelicitation_dialog,elicitation_completeeelicitation_responseper i flussi di elicitazione dell’input dell’utente
message con una descrizione leggibile dall’uomo e facoltativamente un title.
Questo esempio inoltra ogni notifica a un canale Slack. Richiede un URL webhook in arrivo di Slack, che create aggiungendo un’app al vostro spazio di lavoro Slack e abilitando i webhook in arrivo:
Risolvere i problemi comuni
Hook non si attiva
- Verificate che il nome dell’evento hook sia corretto e sensibile alle maiuscole (
PreToolUse, nonpreToolUse) - Controllate che il vostro modello di matcher corrisponda esattamente al nome dello strumento
- Assicuratevi che l’hook sia sotto il tipo di evento corretto in
options.hooks - Per gli hook non basati su strumenti come
StopeSubagentStop, i matcher corrispondono a campi diversi (consultate modelli di matcher) - Gli hooks potrebbero non attivarsi quando l’agente raggiunge il limite
max_turnsperché la sessione termina prima che gli hooks possano essere eseguiti
Matcher non filtra come previsto
I matcher corrispondono solo ai nomi degli strumenti, non ai percorsi dei file o ad altri argomenti. Per filtrare per percorso di file, controllatetool_input.file_path all’interno del vostro hook:
Timeout dell’hook
- Aumentate il valore
timeoutnella configurazioneHookMatcher - Utilizzate
AbortSignaldal terzo argomento del callback per gestire l’annullamento con eleganza in TypeScript
Strumento bloccato inaspettatamente
- Controllate tutti gli hook
PreToolUseper i ritornipermissionDecision: 'deny' - Aggiungete la registrazione ai vostri hook per vedere quale
permissionDecisionReasonstanno restituendo - Verificate che i modelli di matcher non siano troppo ampi (un matcher vuoto corrisponde a tutti gli strumenti)
Input modificato non applicato
-
Assicuratevi che
updatedInputsia all’interno dihookSpecificOutput, non al livello superiore: -
Restituite
permissionDecision: 'allow'per approvare automaticamente l’input modificato, oppure'ask'per mostrarlo all’utente per l’approvazione -
Includete
hookEventNameinhookSpecificOutputper identificare quale tipo di hook è l’output
Hook di sessione non disponibili in Python
SessionStart e SessionEnd possono essere registrati come hook di callback SDK in TypeScript, ma non sono disponibili nell’SDK Python (HookEvent li omette). In Python, sono disponibili solo come hook dei comandi shell definiti nei file di impostazioni (ad esempio, .claude/settings.json). Per caricare gli hook dei comandi shell dalla vostra applicazione SDK, includete la fonte di impostazione appropriata con setting_sources o settingSources:
client.receive_response() come trigger.
I prompt di autorizzazione dei subagenti si moltiplicano
Quando si avviano più subagenti, ognuno potrebbe richiedere autorizzazioni separatamente. I subagenti non ereditano automaticamente le autorizzazioni dell’agente genitore. Per evitare prompt ripetuti, utilizzate gli hookPreToolUse per approvare automaticamente strumenti specifici o configurate regole di autorizzazione che si applicano alle sessioni dei subagenti.
Loop ricorsivi di hook con subagenti
Un hookUserPromptSubmit che avvia subagenti può creare loop infiniti se quei subagenti attivano lo stesso hook. Per prevenire questo:
- Controllate un indicatore di subagente nell’input dell’hook prima di avviare
- Utilizzate una variabile condivisa o lo stato della sessione per tracciare se siete già all’interno di un subagente
- Limitate gli hook per l’esecuzione solo per la sessione dell’agente di livello superiore
systemMessage non appare nell’output
Il camposystemMessage mostra un messaggio all’utente, non al modello. Per impostazione predefinita, l’SDK non fa emergere l’output degli hook nel flusso dei messaggi, quindi il messaggio potrebbe non apparire a meno che non impostiate includeHookEvents (include_hook_events in Python). Per passare il contesto al modello, restituite additionalContext.
Se avete bisogno di far emergere le decisioni degli hook alla vostra applicazione in modo affidabile, registratele separatamente o utilizzate un canale di output dedicato.
Risorse correlate
- Riferimento degli hooks di Claude Code: schemi JSON di input/output completi, documentazione degli eventi e modelli di matcher
- Guida agli hooks di Claude Code: esempi di hook dei comandi shell e procedure dettagliate
- Riferimento SDK TypeScript: tipi di hook, definizioni di input/output e opzioni di configurazione
- Riferimento SDK Python: tipi di hook, definizioni di input/output e opzioni di configurazione
- Autorizzazioni: controllare cosa può fare il vostro agente
- Strumenti personalizzati: creare strumenti per estendere le capacità dell’agente