on(eventName, handler).
Costruite il vostro primo mod prima di iniziare qui. Per ogni evento e i suoi campi esatti, consultate il riferimento o leggete i tipi per la vostra build.
Come un hook gestisce un evento
Un hook si trova tra un evento e ciò che Claude Code farebbe al riguardo, quindi può osservare l’evento, riscriverlo o rispondere da solo. Riceve tre argomenti: l’API dei mods come$, l’evento come e e il gestore successivo come next. I gestori di un evento formano una catena middleware. next(e) chiama il gestore successivo, che è un hook di un altro mod o, alla fine della catena, il comportamento proprio di Claude Code, e si risolve nel risultato. Ciò che il vostro hook fa con next decide quale dei tre fa.
Osservare un evento
Per osservare un evento senza modificarlo, fate il vostro lavoro e restituitenext(e). Questo hook registra ogni strumento che Claude sta per utilizzare:
● my-mod: Claude is about to use Bash appare nella trascrizione, dove my-mod è il nome del vostro plugin. Lo strumento viene eseguito come farebbe senza il mod.
Per agire dopo l’evento, await next(e), fate il vostro lavoro e restituite il risultato. Questo hook registra ogni strumento dopo che è stato eseguito:
next(e) si è risolto.
Riscrivere un evento
Per modificare ciò su cui Claude Code agisce, ad esempio il testo di un prompt, chiamatenext con una copia modificata dell’evento. L’evento stesso è immutabile: è congelato a ogni profondità e l’assegnazione a un campo genera un errore. Questo hook taglia ogni prompt prima che venga inviato:
await next(e), quindi restituite una copia del risultato con un campo sostituito.
Rispondere a un evento
Per gestire un evento da soli, restituite un risultato senza chiamarenext. Questo cortocircuita la catena, quindi i mod successivi e il comportamento proprio di Claude Code non vengono eseguiti. Questo hook rifiuta ogni comando Bash:
deny come risultato dello strumento. Ogni evento ha la sua forma di risultato, che il riferimento degli eventi elenca.
Filtrare quali eventi un hook gestisce
Per eseguire un hook solo per alcuni eventi, passate un filtro come secondo argomento aon. Claude Code chiama il filtro un matcher. È un oggetto i cui campi vengono confrontati con quelli dell’evento e l’hook viene eseguito solo quando ogni campo corrisponde. Un campo può essere un valore, un array di valori consentiti o un’espressione regolare.
Ogni riga in questo esempio registra la stessa funzione, hook, per un insieme più ristretto di chiamate di strumenti:
hook viene eseguito una volta per una chiamata Bash, Edit o Write e una volta per una chiamata a uno strumento il cui nome inizia con mcp__github__. Una chiamata a qualsiasi altro strumento, come Read, non corrisponde a nessuno dei tre, quindi hook non viene eseguito per essa.
Il nome dell’evento può essere un wildcard. 'classic.*' corrisponde a ogni evento hook delle impostazioni. '*' corrisponde a ogni evento tranne gli eventi di telemetria, che potete agganciare per nome o come 'telemetry.*'.
Registrate ogni evento una volta per matcher. Se chiamate on due volte per session.start senza un matcher, il modulo non si carica con on("session.start") is registered twice without a matcher. Mettete tutto ciò che il vostro mod fa all’inizio della sessione in un hook.
Agganciare ciò che Claude sta facendo
Agganciate questi eventi per vedere o modificare una chiamata di strumento, un prompt o un turno mentre accade. Per ogni evento e ciò che un hook può restituire, consultate il riferimento degli eventi.Proteggere o modificare una chiamata di strumento
Un hooktool.call vede ogni strumento che Claude sta per utilizzare, quindi può rifiutare la chiamata, modificare i suoi argomenti o lasciarla passare. tool.call si attiva quando Claude Code sta per eseguire uno strumento, incluse le chiamate che un subagent effettua e le chiamate agli strumenti MCP. e.tool è il nome dello strumento e gli argomenti dello strumento sono campi di e, come e.command per Bash. Quando chiamate next(e), Claude Code esegue il controllo delle autorizzazioni e quindi lo strumento.
Questo hook rifiuta un comando Bash che fa un force-push e dice a Claude perché:
git push --force, il comando non viene eseguito e non appare alcun prompt di autorizzazione, perché l’hook non chiama mai next. Claude legge il testo deny come risultato dello strumento, quindi scrivilo come un’istruzione su cui Claude può agire. Ogni altro comando Bash viene eseguito come farebbe senza il mod.
Per agire dopo che uno strumento è stato eseguito, await next(e), fate il vostro lavoro e restituite ciò che next vi ha dato. Questo hook registra ogni file .mdx che Claude modifica, con $.ui.log, che aggiunge una riga attenuata alla trascrizione che Claude non legge:
.mdx, una riga attenuata nella trascrizione nomina il file. Nulla viene registrato per un altro tipo di file o per una chiamata che è stata rifiutata o non è riuscita. La vista di Claude della chiamata non cambia, perché l’hook restituisce il risultato che ha ricevuto.
Per modificare una chiamata, passate argomenti modificati a next. Per riprovare una chiamata, chiamate next(e) di nuovo: un hook che vede isError sul primo risultato può eseguire lo strumento una seconda volta e restituire quel risultato. Per rispondere a una chiamata da soli, restituite un oggetto con un campo result, come { result: 'Skipped by my-mod' }, senza chiamare next. Quando lo fate, non appare alcun prompt di autorizzazione e lo strumento non viene eseguito, quindi il risultato che restituite è tutto ciò che Claude apprende su ciò che è accaduto.
Gli hook nelle impostazioni gestite della vostra organizzazione vengono eseguiti prima di qualsiasi hook tool.call di un mod, e un blocco da uno di essi è definitivo.
Tenere una chiamata di strumento in sospeso fino a quando l’utente decide
Un hook può mettere in pausa una chiamata di strumento e chiedere all’utente cosa fare prima che proceda. Un hooktool.call può await prima di chiamare next o restituire, e la chiamata dello strumento rimane in sospeso fino ad allora. Per porre la domanda all’utente, chiamate $.ui.ask. Mostra la vostra domanda sopra un elenco numerato delle vostre opzioni, nella finestra di dialogo che Claude usa per chiedervi qualcosa, e si risolve nell’etichetta che l’utente sceglie. Dopo le vostre opzioni, la finestra di dialogo aggiunge una riga per digitare una risposta diversa e una riga Chat about this.
Il pattern RISKY in questo esempio corrisponde a rm -r, rm -rf, git reset --hard e git push con --force, e manca altre ortografie come git push -f. Questo modulo chiede prima di eseguire un comando Bash che corrisponde al pattern:
rm -rf build, la domanda appare con il comando in essa, e il comando attende la risposta:
- L’utente sceglie Run it: l’hook chiama
next(e)e il solito controllo delle autorizzazioni viene comunque eseguito dopo - L’utente sceglie Refuse: il comando non viene eseguito e Claude legge il testo
deny - L’utente digita una risposta:
$.ui.asksi risolve nel testo digitato. L’hook lo confronta conRun it, quindi qualsiasi altro testo rifiuta il comando. - Nessuno risponde:
$.ui.askrifiuta quando l’utente chiude la domanda o sceglie Chat about this, e in un’esecuzioneclaude -p, quindi il bloccocatchlascia la risposta aRefuse
$.ui.ask, perché quel tempo non conta rispetto al limite di tempo di 10 secondi dell’hook. Il tempo trascorso in attesa di una promessa propria conta. Claude Code salta un hook che scade, quindi il comando tenuto in sospeso verrebbe eseguito.
Riscrivere o aggiungere a un prompt
Un hookprompt.submit vede ogni prompt prima che il turno inizi, quindi può riscrivere il testo o aggiungervi. e.text è ciò che è stato digitato.
Questo hook aggiunge il nome del ramo corrente per Claude ogni volta che un prompt menziona una pull request:
open a PR for this change, il vostro messaggio appare uguale nella trascrizione e Claude legge anche una riga come Current branch: feature/auth dopo di esso. Un prompt che non menziona una pull request passa invariato e git non viene eseguito.
Altri eventi coprono il resto di ciò che Claude legge: prompt.section per ogni sezione del prompt di sistema, prompt.context per il contesto inviato con il primo messaggio e skill.prompt per il testo di una skill. Il testo da questi hook che cambia tra le richieste invalida la cache del prompt.
Seguire un turno
Un turno è tutto ciò che Claude fa in risposta a un prompt. Agganciateturn.start, turn.step e turn.complete per seguirne uno:
Scrivete un hook
turn.step come generatore asincrono, perché l’evento trasmette. yield* next(e) inoltra la risposta mentre trasmette e si valuta nel risultato finito. Questo hook registra quanto di ogni richiesta il Claude API ha servito dalla cache del prompt:
result.usage contiene i quattro conteggi di token che il Claude API riporta per una richiesta, più il model che ha risposto: input_tokens, output_tokens, cache_read_input_tokens e cache_creation_input_tokens. L’hook viene eseguito anche per le richieste dei subagent, quindi controllate e.agentId quando volete solo la conversazione principale.
Agganciare gli eventi hook delle impostazioni
Gli hook delle impostazioni sono gli hook di comando, HTTP, prompt e agente che configurate nei file delle impostazioni. Ogni evento hook delle impostazioni, comeStop, SessionEnd o PostToolUse, è anche un evento denominato classic. seguito dal nome dell’evento hook delle impostazioni, come classic.Stop. e è il JSON che un hook delle impostazioni riceve su stdin, incluso transcript_path.
Questo hook usa Stop, che si attiva quando Claude finisce di rispondere, per registrare dove viene salvata la trascrizione della sessione:
next(e), quindi osserva l’evento e non cambia nulla su come il turno termina.
Eseguire insieme ad altri mod
Diversi mod possono agganciare lo stesso evento e uno qualsiasi di essi può fallire. Se il vostro mod blocca le chiamate di strumenti, controllate la sua posizione nella catena e cosa accade quando il suo hook fallisce.L’ordine in cui i mod vengono eseguiti
Gli hook sullo stesso evento formano una catena middleware. Ogninext di un mod chiama l’hook del mod seguente e l’ultimo next raggiunge il comportamento proprio di Claude Code. Il primo mod è il più esterno: vede l’evento prima degli altri e il risultato dopo di loro, e decide se gli altri vengono eseguiti. Un mod successivo non può impedire a uno precedente di vedere un evento.
Claude Code ordina la catena in base a dove proviene ogni mod:
- La guardia incorporata
sec-default@builtin, un mod incorporato in Claude Code che/pluginelenca comecc-plugin-sec-default, dove si carica, i mod che la vostra organizzazione elenca inprependPluginse quindi qualsiasi altro mod che conta come della vostra organizzazione e non è inappendPlugins - I mod che installate
- I mod che la vostra organizzazione elenca in
appendPlugins - Altri mod incorporati in Claude Code
dependencies nel suo manifesto. All’interno di un modulo, gli hook vengono eseguiti nell’ordine in cui register ha chiamato on.
Dove gli hook delle impostazioni vengono eseguiti nell’ordine
Gli hookPreToolUse configurati nei file delle impostazioni vengono anche eseguiti durante una chiamata di strumento, in punti fissi nella catena dei mod:
- Hook
PreToolUsedalle impostazioni gestite: vengono eseguiti prima dell’hooktool.calldel primo mod, e un blocco da uno di essi è definitivo, quindi nessun mod vede la chiamata. - Hook
PreToolUseda ogni altro file di impostazioni e dahooks/hooks.jsondei plugin: vengono eseguiti dopo che l’ultimo mod chiamanext, come parte del comportamento proprio di Claude Code. Un mod che risponde atool.callsenza chiamarenextli impedisce di eseguire e un mod che chiamanextvede la loro decisione nel risultato che restituisce.
tool.check è l’evento in cui Claude Code decide se una chiamata di strumento può essere eseguita. Si attiva dopo quegli hook e le regole di autorizzazione hanno deciso e next(e) si risolve nella loro decisione. Un hook su tool.check può restituire una decisione diversa, come { decision: 'allow' }, quindi può approvare una chiamata che un hook nel secondo gruppo ha bloccato. Estendere le autorizzazioni con gli hook elenca quali decisioni prevalgono su un mod.
Gestire un hook che fallisce
Un hook che fallisce non interrompe la sessione e potete decidere cosa accade invece. Quando un hook senza un gestore.catch genera un errore, scade o restituisce un risultato di forma sbagliata, ciò che accade dopo dipende dal fatto che abbia chiamato next:
- Ha fallito prima di chiamare
next: Claude Code lo salta e il gestore successivo viene eseguito al suo posto - Ha fallito dopo che
nextsi è risolto: quel risultato rimane e nulla viene eseguito una seconda volta
my-mod: tool.call hook skipped: threw Error: boom. Dove lo leggete dipende dalla sessione, come Scoprire perché un mod non fa nulla elenca. Un hook ui.render il cui disegno non convalida viene segnalato diversamente, come Costruire un albero da elementi descrive.
Per fare in modo che un hook che blocca le chiamate fallisca in modo sicuro, aggiungete un gestore di errore .catch che risponda al suo posto. Qui, guard è la vostra funzione hook:
guard funziona, il gestore non viene mai eseguito. Quando guard genera un errore o scade su una chiamata Bash, Claude Code chiama il gestore con lo stesso evento. Il gestore restituisce { deny }, quindi il comando non viene eseguito e Claude legge il testo con throw o timeout alla fine. Senza il gestore, Claude Code salterebbe guard ed eseguirebbe il comando. Il gestore ha un secondo per rispondere.
Passaggi successivi
- Usare l’API dei mods: aggiungere comandi e strumenti, chiamare un modello ed eseguire lavoro su un timer
- Disegnare nell’interfaccia: mostrare ciò che i vostri hook raccolgono in un riquadro o sopra il prompt
- Testare un mod: generare uno qualsiasi di questi eventi da un test
- Riferimento dei mods: ogni evento, ogni metodo dell’API dei mods e i limiti