- Bloquear operações perigosas antes de serem executadas, como comandos shell destrutivos ou acesso a arquivos não autorizado
- Registrar e auditar cada chamada de ferramenta para conformidade, depuração ou análise
- Transformar entradas e saídas para sanitizar dados, injetar credenciais ou redirecionar caminhos de arquivo
- Exigir aprovação humana para ações sensíveis como gravações em banco de dados ou chamadas de API
- Rastrear ciclo de vida da sessão para gerenciar estado, limpar recursos ou enviar notificações
Como hooks funcionam
1
Um evento é disparado
Algo acontece durante a execução do agente e o SDK dispara um evento: uma ferramenta está prestes a ser chamada (
PreToolUse), uma ferramenta retornou um resultado (PostToolUse), um subagente iniciou ou parou, o agente está ocioso ou a execução terminou. Veja a lista completa de eventos.2
O SDK coleta hooks registrados
O SDK verifica se há hooks registrados para esse tipo de evento. Isso inclui hooks de callback que você passa em
options.hooks e hooks de comando shell de arquivos de configuração quando a entrada settingSources ou setting_sources correspondente está habilitada, o que é o padrão para opções query().3
Matchers filtram quais hooks são executados
Se um hook tem um padrão
matcher (como "Write|Edit"), o SDK o testa contra o alvo do evento (por exemplo, o nome da ferramenta). Hooks sem um matcher são executados para cada evento desse tipo.4
Funções de callback são executadas
Cada função de callback do hook correspondente recebe informações sobre o que está acontecendo: o nome da ferramenta, seus argumentos, o ID da sessão e outros detalhes específicos do evento.
5
Seu callback retorna uma decisão
Após realizar qualquer operação (registro, chamadas de API, validação), seu callback retorna um objeto de saída que diz ao agente o que fazer: permitir a operação, bloqueá-la, modificar a entrada ou injetar contexto na conversa.
PreToolUse (etapa 1) com um matcher "Write|Edit" (etapa 3) para que o callback seja acionado apenas para ferramentas de escrita de arquivo. Quando acionado, o callback recebe a entrada da ferramenta (etapa 4), verifica se o caminho do arquivo tem como alvo um arquivo .env e retorna permissionDecision: "deny" para bloquear a operação (etapa 5):
.env e o hook nega a chamada de ferramenta.
Hooks disponíveis
O SDK fornece hooks para diferentes estágios de execução do agente. Alguns hooks estão disponíveis em ambos os SDKs, enquanto outros são apenas para TypeScript.Configurar hooks
Para configurar um hook, passe-o no campohooks de suas opções de agente (ClaudeAgentOptions em Python, o objeto options em TypeScript). Este trecho assume que você já definiu um callback de hook, como protect_env_files em Python ou protectEnvFiles em TypeScript do exemplo acima:
hooks é um dicionário em Python ou um objeto em TypeScript, onde:
- Chaves: nomes de eventos de hook como
'PreToolUse','PostToolUse'e'Stop' - Valores: arrays de matchers, cada um contendo um padrão de filtro opcional e suas funções de callback
Matchers
Use matchers para filtrar quando seus callbacks são acionados. O campomatcher corresponde a um valor diferente dependendo do tipo de evento de hook. Por exemplo, hooks baseados em ferramentas correspondem ao nome da ferramenta, enquanto hooks Notification correspondem ao tipo de notificação.
Os matchers do SDK seguem as mesmas regras que matchers em arquivos de configuração. Essa seção documenta os caminhos de avaliação de string exata e expressão regular, seus requisitos de versão e os valores de matcher para cada tipo de evento.
Use o padrão
matcher para direcionar ferramentas específicas sempre que possível. Um matcher com 'Bash' é executado apenas para comandos Bash, enquanto omitir o padrão executa seus callbacks para cada ocorrência do evento. Omita-o propositalmente para registrar cada chamada de ferramenta que sua sessão faz.
Funções de callback
Entradas
Cada callback de hook recebe três argumentos:- Dados de entrada: um objeto tipado contendo detalhes do evento. Cada tipo de hook tem sua própria forma de entrada. Por exemplo,
PreToolUseHookInputincluitool_nameetool_input, enquantoNotificationHookInputincluimessage. Veja as definições de tipo completas nas referências do SDK TypeScript e Python.- Todas as entradas de hook compartilham
session_id,cwdehook_event_name. agent_ideagent_typesão preenchidos quando o hook é acionado dentro de um subagente. Em TypeScript, estes estão na entrada de hook base e disponíveis para todos os tipos de hook. Em Python, eles são campos opcionais emPreToolUse,PostToolUse,PostToolUseFailureePermissionRequest, e campos obrigatórios emSubagentStarteSubagentStop.
- Todas as entradas de hook compartilham
- ID de uso de ferramenta (
str | None/string | undefined): correlaciona eventosPreToolUseePostToolUsepara a mesma chamada de ferramenta. - Contexto: em TypeScript, contém uma propriedade
signal(AbortSignal) para cancelamento. Em Python, este argumento é reservado para uso futuro.
Saídas
Seu callback retorna um objeto com duas categorias de campos:- Campos de nível superior são aceitos em cada evento:
systemMessagemostra uma mensagem ao usuário, econtinue(continue_em Python) determina se o agente continua executando após este hook. Alguns eventos descartam-nos ou os entregam em outro lugar. A seção de cada evento na página de hooks diz onde eles chegam. hookSpecificOutputcontrola a operação atual. Os campos que você define dentro dependem do tipo de evento de hook:- Para hooks
PreToolUse, é aqui que você definepermissionDecision("allow","deny","ask"ou"defer"),permissionDecisionReasoneupdatedInput. Se você retornar"defer", o turno termina com uma mensagem de resultado cujostop_reasoné"tool_deferred", para que você possa retomar a chamada depois. - Para hooks
PostToolUse, você pode definiradditionalContextpara anexar informações ao resultado da ferramenta. Para substituir a saída da ferramenta antes de Claude vê-la, definaupdatedToolOutput, que funciona para qualquer ferramenta em ambos os SDKs. O campo mais antigoupdatedMCPToolOutputsubstitui apenas a saída de ferramentas MCP. - No SDK TypeScript, um callback
PostToolUsetambém pode retornarclassifierContext, uma nota breve sobre o resultado da chamada de ferramenta para o classificador de permissão do modo auto. Como seu callback é executado no próprio processo de sua aplicação, o classificador pode pesar uma declaração de usuário que você transmite na nota como intenção do usuário. O campo requer Agent SDK TypeScript v0.3.236 ou posterior. Anotar um resultado para o classificador do modo auto cobre o limite de comprimento, a regra somente síncrona e o que não colocar na nota.
- Para hooks
{} para permitir a operação sem alterações. Hooks de callback do SDK usam o mesmo formato de saída JSON que hooks de comando shell do Claude Code, que documenta cada campo e opção específica do evento. Para as definições de tipo do SDK, veja as referências do SDK TypeScript e Python.
Quando múltiplos hooks ou regras de permissão se aplicam,
deny tem prioridade sobre defer, que tem prioridade sobre ask, que tem prioridade sobre allow. Se qualquer hook retornar deny, a operação é bloqueada independentemente de outros hooks.Saída assíncrona
Por padrão, o agente aguarda seu hook retornar antes de prosseguir. Se seu hook realiza um efeito colateral, como registro ou envio de webhook, e não precisa influenciar o comportamento do agente, você pode retornar uma saída assíncrona. Isso diz ao agente para continuar imediatamente sem aguardar o hook terminar. Neste trecho,send_to_logging_service em Python e sendToLoggingService em TypeScript representam qualquer função de registro que você defina:
Saídas assíncronas não podem bloquear, modificar ou injetar contexto na operação, pois o agente já avançou. Use-as apenas para efeitos colaterais como registro, métricas ou notificações.
Exemplos
Vários exemplos nesta seção mostram apenas a função de callback. Para executar um, registre o callback sob o evento correspondente no campohooks de suas opções, conforme mostrado em Configurar hooks.
Modificar entrada de ferramenta
Este exemplo intercepta chamadas de ferramenta Write e reescreve o argumentofile_path para prepender /sandbox, redirecionando todas as gravações de arquivo para um diretório em sandbox. O callback retorna updatedInput com o caminho modificado e permissionDecision: 'allow' para aprovar automaticamente a operação reescrita:
Combine
updatedInput com permissionDecision: 'allow' para aprovar automaticamente a entrada modificada, ou permissionDecision: 'ask' para mostrá-la ao usuário. Se você omitir permissionDecision, a entrada modificada ainda se aplica e flui pela avaliação de permissão normal. Com 'defer', updatedInput é ignorado. Sempre retorne um novo objeto em vez de mutar o tool_input original../sandbox ou /tmp/sandbox (macOS não permite criar um diretório /sandbox no nível raiz), depois peça ao agente para escrever um arquivo: o resultado da ferramenta Write no fluxo de mensagens nomeia o caminho com seu prefixo de sandbox em vez do que Claude solicitou.
Adicionar contexto e bloquear uma ferramenta
Este exemplo bloqueia gravações no diretório/etc e explica o motivo tanto para o modelo quanto para o usuário:
permissionDecision: 'deny'interrompe a chamada de ferramenta.permissionDecisionReasoninforma ao modelo por que, para que ele evite tentar novamente.systemMessagemostra ao usuário o que aconteceu.
PreToolUse com um matcher Write|Edit e peça ao agente para criar um arquivo em /etc: o resultado da ferramenta Write no fluxo de mensagens contém Writing to /etc is not allowed, e nenhum arquivo é criado.
Aprovar automaticamente ferramentas específicas
Por padrão, o agente pode solicitar permissão antes de usar certas ferramentas. Este exemplo aprova automaticamente ferramentas de sistema de arquivos somente leitura (Read, Glob, Grep) retornandopermissionDecision: 'allow', permitindo que sejam executadas sem confirmação do usuário, exceto leituras de caminhos de rede, enquanto deixa todas as outras ferramentas sujeitas a verificações de permissão normais:
Registrar múltiplos hooks
Quando um evento é disparado, todos os hooks correspondentes são executados em paralelo. Para decisões de permissão, o resultado mais restritivo vence: um únicodeny bloqueia a chamada de ferramenta independentemente do que os outros hooks retornam. Como a ordem de conclusão é não-determinística, escreva cada hook para agir independentemente em vez de depender de outro hook ter sido executado primeiro.
O exemplo abaixo registra três verificações independentes para cada chamada de ferramenta. Os nomes de hook nele, como audit_logger em Python ou auditLogger em TypeScript, representam callbacks que você define:
Filtrar com matchers de múltiplas ferramentas
Use matchers de múltiplas ferramentas para compartilhar um callback entre ferramentas relacionadas. Este exemplo registra três matchers com escopos diferentes, e cada hook que ele nomeia representa um callback que você define:- Uma lista exata separada por pipe (
Write|Edit|NotebookEdit) disparafile_security_hookapenas para ferramentas de modificação de arquivo. - Uma regex (
^mcp__) disparamcp_audit_hookpara qualquer ferramenta MCP cujo nome começa commcp__. - Um matcher omitido dispara
global_loggerpara cada chamada de ferramenta independentemente do nome.
Rastrear atividade de subagente
Use hooksSubagentStop para monitorar quando subagentes terminam seu trabalho. Veja o tipo de entrada completo nas referências do SDK TypeScript e Python. Este exemplo registra um resumo cada vez que um subagente é concluído:
[SUBAGENT] Completed: com o ID do subagente e o caminho da transcrição.
Fazer requisições HTTP a partir de hooks
Hooks podem realizar operações assíncronas como requisições HTTP. Capture erros dentro de seu hook em vez de deixá-los se propagar. Este exemplo envia um webhook após cada ferramenta ser concluída, registrando qual ferramenta foi executada e quando. O hook captura erros de um webhook falhado:Encaminhar notificações para Slack
Use hooksNotification para receber notificações do sistema do agente e encaminhá-las para serviços externos. Em sessões do SDK, Claude Code executa este hook para os seguintes tipos de notificação:
permission_promptuma vez que uma solicitação de permissão aguardou cerca de seis segundos em seu callbackcanUseTool. Requer Agent SDK TypeScript v0.3.233 ou posterior, ou Agent SDK Python v0.2.139 ou posteriorelicitation_completeeelicitation_responsepara fluxos de elicitação de entrada do usuário
idle_prompt, auth_success e elicitation_dialog, a partir da interface interativa que sessões do SDK não executam.
Cada notificação inclui um campo message com uma descrição legível por humanos e opcionalmente um title.
Este exemplo encaminha cada notificação para um canal Slack. Requer uma URL de webhook de entrada do Slack, que você cria adicionando um app ao seu espaço de trabalho Slack e habilitando webhooks de entrada:
Notification é disparado, o hook publica a message da notificação, prefixada com Agent status:, para o canal que seu webhook aponta.
Corrigir problemas comuns
Hook não é disparado
- Verifique se o nome do evento de hook está correto e sensível a maiúsculas/minúsculas (
PreToolUse, nãopreToolUse) - Verifique se seu padrão de matcher corresponde exatamente ao nome da ferramenta
- Certifique-se de que o hook está sob o tipo de evento correto em
options.hooks - Para hooks não baseados em ferramentas que suportam matchers, como
NotificationeSubagentStop, matchers correspondem a campos diferentes, eStopignora matchers completamente (veja padrões de matcher) - Hooks podem não ser disparados quando o agente atinge o limite
max_turnsporque a sessão termina antes que hooks possam ser executados
Matcher não filtra como esperado
Matchers apenas correspondem a nomes de ferramentas, não a caminhos de arquivo ou outros argumentos. Para filtrar por caminho de arquivo, verifiquetool_input.file_path dentro de seu hook:
Timeout de hook
Claude Code executa cada callback com um timeout, que você define em segundos com o campotimeout em seu HookMatcher. Quando você não define um, Claude Code usa o padrão do evento: 600 segundos para a maioria dos eventos, 30 segundos para UserPromptSubmit, PreModelSwitch e PostModelSwitch, e 10 segundos para MessageDisplay. Claude Code executa callbacks SessionEnd durante o desligamento sob o orçamento de timeout mais curto de SessionEnd, 1,5 segundos por padrão.
Quando um callback excede seu timeout, Claude Code o cancela e descarta sua saída, e a sessão continua em vez de travar. O que acontece a seguir depende do evento:
PreToolUse: Claude Code não executa a chamada de ferramenta, Claude recebe um resultado de ferramenta informando que o hook não respondeu antes de seu timeout, e o turno continua. Se outro hookPreToolUseretornou uma negação explícita, Claude recebe essa negação em vez do erro de timeout. Antes da v2.1.210, Claude Code relatava o timeout a Claude como uma rejeição do usuário, o que fazia sessões autônomas pararem e aguardarem entrada.PostToolUseePostToolUseFailure: Claude Code mantém o resultado da ferramenta e o turno continua.UserPromptSubmiteUserPromptExpansion: Claude Code bloqueia o prompt com uma mensagem nomeando o hook e o timeout, e a sessão continua. Como um callback nesses eventos pode atuar como uma porta de política, Claude Code nunca deixa um prompt com timeout passar sem ser verificado. Antes da v2.1.208, Claude Code terminava a consulta comerror_during_executionquando um callback nesses eventos expirava.StopeSubagentStop: o callback com timeout conta como retornando nenhuma decisão. O agente ou subagente para como se esse callback o tivesse permitido, e uma decisão de seus outros hooks no evento ainda se aplica. Antes do Claude Code v2.1.273, um callbackStopouSubagentStopcom timeout contava como uma execução de hook falhada, e Claude Code descartava as decisões de seus outros hooks no evento.SessionStart: o callback com timeout conta como retornando nenhuma saída, e a sessão continua com a saída de seus outros hooksSessionStart.PreModelSwitch: Claude Code bloqueia a mudança de modelo. Um hook que não responde não aprovou a mudança.- Outros eventos, como
Notification,PreCompactePostModelSwitch: Claude Code registra a falha e continua.
Stop ou SessionStart expira na sessão principal, Claude Code também adiciona uma SDKInformationalMessage ao fluxo de mensagens dizendo que o aplicativo que dirige a sessão não respondeu. Timeouts posteriores não repetem essa mensagem enquanto seu aplicativo permanecer sem resposta.
Se você interromper a consulta enquanto um callback está pendente, Claude Code cancela a chamada de ferramenta pendente. Antes da v2.1.208, a chamada de ferramenta ainda poderia prosseguir se você interrompesse durante um callback PreToolUse pendente.
Se seu callback precisar de mais tempo, defina um timeout mais alto em seu HookMatcher. Em TypeScript, use o AbortSignal do terceiro argumento de callback para lidar com cancelamento graciosamente quando o timeout dispara.
Ferramenta bloqueada inesperadamente
- Verifique todos os hooks
PreToolUsepara retornospermissionDecision: 'deny' - Adicione logs aos seus hooks para ver qual
permissionDecisionReasoneles estão retornando - Verifique se padrões de matcher não são muito amplos: um matcher vazio corresponde a todas as ferramentas
Entrada modificada não aplicada
-
Certifique-se de que
updatedInputestá dentro dehookSpecificOutput, não no nível superior: -
Não emparelhe
updatedInputcompermissionDecision: 'defer', que descarta a entrada modificada. OmitirpermissionDecisioné aceitável: a entrada modificada ainda se aplica através da avaliação de permissão normal. Você também pode retornar'allow'para aprovar automaticamente a entrada modificada ou'ask'para mostrá-la ao usuário para aprovação -
Inclua
hookEventNameemhookSpecificOutputpara identificar qual tipo de hook a saída é
Hooks de sessão não disponíveis em Python
SessionStart e SessionEnd podem ser registrados como hooks de callback do SDK em TypeScript, mas não estão disponíveis no SDK Python porque seu tipo HookEvent os omite. Em Python, eles estão disponíveis apenas como hooks de comando shell definidos em arquivos de configuração como .claude/settings.json. Quais arquivos de configuração sua aplicação SDK carrega depende de setting_sources ou settingSources. Se você definir essa opção, inclua a fonte que contém os hooks:
client.receive_response() como seu gatilho.
Prompts de permissão de subagente se multiplicando
Ao gerar múltiplos subagentes, cada um pode solicitar permissões separadamente para suas próprias chamadas de ferramenta. Para evitar prompts repetidos, use hooksPreToolUse para aprovar automaticamente ferramentas específicas, ou configure regras de permissão, que subagentes herdam da conversa pai.
Loops recursivos de hook com subagentes
Um hookUserPromptSubmit que gera subagentes pode criar loops infinitos se esses subagentes acionarem o mesmo hook. Para evitar isso:
- Use uma variável compartilhada ou estado de sessão para rastrear se você já está dentro de um subagente
- Restrinja os hooks para executar apenas na sessão de agente de nível superior
systemMessage não aparecendo na saída
O camposystemMessage mostra uma mensagem ao usuário, não ao modelo. No Claude Code v2.1.227 ou posterior, o systemMessage de um hook pode aparecer no fluxo de mensagens como uma SDKInformationalMessage. Se aparece ou não depende do evento. Cada seção de evento na página de hooks diz como a saída aparece. Para passar contexto ao modelo em vez disso, retorne additionalContext.
Antes da v2.1.227, o SDK expunha a saída de hook no fluxo de mensagens apenas para hooks SessionStart e Setup. Para qualquer outro evento, a saída aparecia apenas nos eventos de ciclo de vida que includeHookEvents (include_hook_events em Python) adiciona. A entrada dessa opção cobre quais eventos de ciclo de vida cada evento de hook produz.
Se você precisar expor decisões de hook para sua aplicação de forma confiável, registre-as separadamente ou use um canal de saída dedicado.
Recursos relacionados
- Referência de hooks do Claude Code: esquemas JSON de entrada/saída completos, documentação de eventos e padrões de matcher
- Guia de hooks do Claude Code: exemplos de hooks de comando shell e passo a passo
- Referência do SDK TypeScript: tipos de hook, definições de entrada/saída e opções de configuração
- Referência do SDK Python: tipos de hook, definições de entrada/saída e opções de configuração
- Permissões: controlar o que seu agente pode fazer
- Ferramentas personalizadas: construir ferramentas para estender capacidades do agente