Pular para o conteúdo principal
Hooks são comandos shell definidos pelo usuário. Claude Code os executa em pontos específicos do seu ciclo de vida, o que lhe dá controle determinístico: certas ações sempre acontecem em vez de depender do LLM para escolher executá-las. Use hooks para aplicar regras do projeto, automatizar tarefas repetitivas e integrar Claude Code com suas ferramentas existentes. Para decisões que exigem julgamento em vez de regras determinísticas, você também pode usar hooks baseados em prompt ou hooks baseados em agente que usam um modelo Claude para avaliar condições. Para outras formas de estender Claude Code, consulte skills para dar ao Claude instruções adicionais e comandos executáveis, subagents para executar tarefas em contextos isolados e plugins para empacotar extensões para compartilhar entre projetos.
Este guia cobre casos de uso comuns e como começar. Para esquemas de eventos completos, formatos de entrada/saída JSON e recursos avançados como hooks assíncronos e hooks de ferramentas MCP, consulte a referência de Hooks.

Configure seu primeiro hook

Para criar um hook, adicione um bloco hooks a um arquivo de configuração. Este passo a passo cria um hook de notificação de desktop, para que você seja alertado sempre que Claude estiver aguardando sua entrada em vez de observar o terminal.
1

Adicione o hook às suas configurações

Abra ~/.claude/settings.json e adicione um hook Notification. Se o arquivo não existir, crie-o. O exemplo abaixo usa osascript para macOS; consulte Receba notificações quando Claude precisa de entrada para comandos Linux e Windows.
Se seu arquivo de configuração já tem uma chave hooks, adicione Notification como um irmão das chaves de evento existentes em vez de substituir o objeto inteiro. Cada nome de evento é uma chave dentro do único objeto hooks:
Você também pode pedir ao Claude para escrever o hook para você descrevendo o que deseja na CLI.
2

Verifique a configuração

Digite /hooks no prompt do Claude Code para abrir o navegador de hooks. Seu novo hook aparece na lista em Notification.
3

Teste o hook

Pressione Esc para retornar à CLI. Pressione Shift+Tab até que a barra de status mostre ⏸ manual mode on, peça ao Claude para fazer algo que exija permissão, depois alterne do terminal para outra janela. Você deve receber uma notificação de desktop.

O que você pode automatizar

Hooks permitem executar código em pontos-chave do ciclo de vida do Claude Code: formatar arquivos após edições, bloquear comandos antes de executarem, enviar notificações quando Claude precisa de entrada, injetar contexto no início da sessão e muito mais. Para a lista completa de eventos de hook, consulte a referência de Hooks. Cada exemplo inclui um bloco de configuração pronto para usar que você adiciona a um arquivo de configuração. Para um exemplo de produção de hooks que executam uma revisão de modelo separada e alimentam as descobertas de volta à sessão, consulte como o plugin security-guidance se integra com Claude Code.

Receba notificações quando Claude precisa de entrada

Receba uma notificação de desktop sempre que Claude terminar de trabalhar e precisar de sua entrada, para que você possa mudar para outras tarefas sem verificar o terminal. Este hook usa o evento Notification, que Claude Code dispara quando Claude está aguardando entrada ou permissão. Consulte quando cada tipo de notificação dispara para o tempo exato. Cada aba abaixo usa o comando de notificação nativo da plataforma. Adicione isto a ~/.claude/settings.json:
osascript roteia notificações através do aplicativo Script Editor integrado. Se o Script Editor não tiver permissão de notificação, o comando falha silenciosamente e macOS não solicitará que você o conceda.Execute isto no Terminal uma vez para fazer o Script Editor aparecer em suas configurações de notificação:
Nada aparecerá ainda. Abra System Settings > Notifications, encontre Script Editor na lista e ative Allow Notifications. Execute o comando novamente para confirmar que a notificação de teste aparece.
O matcher vazio dispara em todos os tipos de notificação. Para disparar apenas em eventos específicos, defina-o como um tipo de notificação, como um destes: Claude Code cronometra permission_prompt de forma diferente em um terminal e no Claude Desktop, na extensão VS Code e em outros hosts que respondem a solicitações de permissão através do Agent SDK. Consulte quando cada tipo de notificação dispara para ambos os tempos. Os matchers quota_auto_resume_fired, quota_auto_resume_stale e quota_auto_resume_disabled exigem Claude Code v2.1.234 ou posterior. O matcher auth_storage_failure exige v2.1.288 ou posterior. Em sessões de terminal, permission_prompt para uma solicitação de rede de comando sandboxed exige Claude Code v2.1.246 ou posterior. agent_needs_input para uma pergunta de configuração de terminal de colega de equipe exige Claude Code v2.1.248 ou posterior. Digite /hooks no prompt do Claude Code e confirme que o hook aparece em Notification.

Formatar código automaticamente após edições

Execute automaticamente Prettier em cada arquivo que Claude edita, para que a formatação permaneça consistente sem intervenção manual. Este hook usa o evento PostToolUse com um matcher Edit|Write, para que execute apenas após ferramentas de edição de arquivo. O comando extrai o caminho do arquivo editado com jq e o passa para Prettier. Adicione isto a .claude/settings.json na raiz do seu projeto:
Para testar o hook, peça ao Claude para adicionar uma linha com strings entre aspas simples a um arquivo JavaScript, depois abra o arquivo: com as configurações padrão do Prettier, o hook as reescreve para aspas duplas. Quando o hook é bem-sucedido, Claude Code não mostra nada na conversa. Para confirmar que o hook foi executado, verifique se o arquivo editado foi reformatado, ou consulte Verificar o que um hook fez. Para reformatar um arquivo específico de qualquer forma que ele mude, incluindo quando um comando Bash o reescreve, use um hook FileChanged em vez disso.
Os exemplos Bash nesta página usam jq para análise JSON. Instale-o com brew install jq no macOS, apt-get install jq no Debian e Ubuntu, ou consulte downloads do jq.

Bloquear edições em arquivos protegidos

Impeça que as ferramentas Edit e Write do Claude modifiquem arquivos sensíveis como .env, package-lock.json ou qualquer coisa em .git/. Claude recebe feedback explicando por que a edição foi bloqueada, para que possa ajustar sua abordagem. Este exemplo usa um arquivo de script separado que o hook chama. O script verifica o caminho do arquivo de destino contra uma lista de padrões protegidos e sai com código 2 para bloquear a edição.
1

Crie o script do hook

Salve isto em .claude/hooks/protect-files.sh:
2

Torne o script executável no macOS e Linux

Scripts de hook devem ser executáveis para que Claude Code os execute:
3

Registre o hook

Adicione um hook PreToolUse a .claude/settings.json que execute o script antes de qualquer chamada de ferramenta Edit ou Write:
4

Teste o hook

Peça ao Claude para adicionar um comentário ao seu arquivo .env. Claude Code bloqueia a edição antes de executá-la e passa a mensagem Blocked: do script para Claude como feedback.
Claude ainda pode alterar os arquivos protegidos com comandos shell. Para bloquear alguns desses comandos, adicione uma regra de negação Edit por caminho em permissions.deny no .claude/settings.json, como Edit(/.env) para o .env da raiz do projeto. Mesmo com essas regras, Claude pode alterar o .env de outras formas. Para limitar em quais arquivos os comandos podem escrever, consulte Configurar sandboxing.

Re-injetar contexto após compactação

Quando a janela de contexto do Claude fica cheia, a compactação resume a conversa para liberar espaço. Isto pode perder detalhes importantes. Use um hook SessionStart com um matcher compact para re-injetar contexto crítico após cada compactação. Claude Code adiciona texto simples que seu comando escreve para stdout ao contexto do Claude. Este exemplo lembra ao Claude as convenções do projeto e trabalho recente. Adicione isto a .claude/settings.json na raiz do seu projeto:
Você pode substituir o echo por qualquer comando que produza saída dinâmica, como git log --oneline -5 para mostrar commits recentes. Para injetar contexto em cada início de sessão, considere usar CLAUDE.md em vez disso. Para variáveis de ambiente, consulte CLAUDE_ENV_FILE na referência.

Auditar mudanças de configuração

Rastreie quando arquivos de configuração ou skills mudam durante uma sessão. O evento ConfigChange dispara quando um processo externo ou editor modifica um arquivo de configuração, para que você possa registrar mudanças para conformidade ou bloquear modificações não autorizadas. Este exemplo anexa cada evento a um log de auditoria. Adicione isto a ~/.claude/settings.json:
O matcher filtra por tipo de configuração: user_settings, project_settings, local_settings, policy_settings ou skills. Para bloquear uma mudança de entrar em vigor, saia com código 2 ou retorne {"decision": "block"}. Consulte a referência de ConfigChange para o esquema de entrada completo. Para confirmar que o hook registra mudanças, edite um arquivo de configuração em outro editor enquanto uma sessão está em execução, depois abra ~/claude-config-audit.log: o hook anexa uma linha JSON por mudança com o timestamp, fonte e caminho do arquivo.

Recarregar ambiente quando diretório ou arquivos mudam

Alguns projetos definem variáveis de ambiente diferentes dependendo de qual diretório você está. Ferramentas como direnv fazem isto automaticamente no seu shell, mas a ferramenta Bash do Claude não pega essas mudanças por conta própria. Emparelhar um hook SessionStart com um hook CwdChanged corrige isto. SessionStart carrega as variáveis para o diretório em que você inicia, e CwdChanged as recarrega cada vez que Claude muda de diretório. Ambos escrevem para CLAUDE_ENV_FILE, que Claude Code executa como um preâmbulo de script antes de cada comando Bash. Adicione isto a ~/.claude/settings.json:
Execute direnv allow uma vez em cada diretório que tenha um .envrc para que direnv tenha permissão para carregá-lo. Se você usar devbox ou nix em vez de direnv, o mesmo padrão funciona com devbox shellenv ou devbox global shellenv no lugar de direnv export bash. Para reagir a arquivos específicos em vez de cada mudança de diretório, use FileChanged com um matcher listando os nomes de arquivo para observar, separados por |. Ao construir a lista de observação, Claude Code divide este valor em nomes de arquivo literais em vez de avaliá-lo como uma regex. Consulte FileChanged para como o mesmo valor também filtra quais grupos de hook executam quando um arquivo muda. Este exemplo observa .envrc e .env no diretório de trabalho:
Consulte as entradas de referência CwdChanged e FileChanged para esquemas de entrada, saída watchPaths e detalhes de CLAUDE_ENV_FILE.

Aprovar automaticamente prompts de permissão específicos

Pule o diálogo de aprovação para chamadas de ferramenta que você sempre permite. Este exemplo aprova automaticamente ExitPlanMode, a ferramenta que Claude chama quando termina de apresentar um plano e pede para prosseguir, para que você não seja solicitado toda vez que um plano estiver pronto. Diferentemente dos exemplos de código de saída acima, a aprovação automática exige que seu hook escreva uma decisão JSON para stdout. Claude Code executa hooks PermissionRequest quando está prestes a pedir permissão, e se seu hook retornar "behavior": "allow", Claude Code responde à requisição em seu nome. Para uma ferramenta que exige interação do usuário, como ExitPlanMode, a permissão também precisa de updatedInput, caso contrário Claude Code a ignora e ainda mostra o prompt. O matcher restringe o hook apenas a ExitPlanMode, para que nenhum outro prompt seja afetado. Adicione isto a ~/.claude/settings.json:
Quando o hook aprova, Claude Code sai do modo de plano e restaura qualquer modo de permissão que estava ativo antes de você entrar no modo de plano. A transcrição mostra “Allowed by PermissionRequest hook” onde o diálogo teria aparecido. O caminho do hook sempre mantém a conversa atual: ele não pode limpar contexto e iniciar uma sessão de implementação fresca da forma que o diálogo pode. Para definir um modo de permissão específico em vez disso, a saída do seu hook pode incluir um array updatedPermissions com uma entrada setMode. O valor mode é qualquer modo de permissão como default, acceptEdits ou bypassPermissions, e destination: "session" o aplica apenas para a sessão atual.
bypassPermissions só se aplica se a sessão foi iniciada com modo bypass já disponível: --dangerously-skip-permissions, --permission-mode bypassPermissions, --allow-dangerously-skip-permissions, ou permissions.defaultMode: "bypassPermissions" em configurações de usuário, --settings ou gerenciadas. Não se aplica se o modo bypass está desabilitado por permissions.disableBypassPermissionsMode, ou se você iniciou a sessão em modo restrito.Claude Code nunca o salva como defaultMode.
Para mudar a sessão para acceptEdits, substitua a linha command nesse hook por esta:
Mantenha o matcher o mais restrito possível. Corresponder a .* ou deixar o matcher vazio aprovaria automaticamente cada prompt de permissão, incluindo escritas de arquivo e comandos shell. Consulte a referência de PermissionRequest para o conjunto completo de campos de decisão.

Como hooks funcionam

Claude Code dispara eventos de hook em pontos específicos do seu ciclo de vida. Quando um evento dispara, Claude Code executa os hooks correspondentes em paralelo; consulte Campos do manipulador de hook para saber como manipuladores duplicados são tratados. A tabela abaixo mostra cada evento e quando dispara: Cada hook tem um type que determina como ele executa. A maioria dos hooks usa "type": "command", que executa um comando shell. Quatro outros tipos estão disponíveis:
  • "type": "http": POST dados de evento para uma URL. Consulte HTTP hooks.
  • "type": "mcp_tool": chamar uma ferramenta em um servidor MCP configurado. Consulte MCP tool hooks.
  • "type": "prompt": avaliação LLM de turno único. Consulte Prompt-based hooks.
  • "type": "agent": verificação multi-turno com acesso a ferramentas. Agent hooks são experimentais e podem mudar. Consulte Agent-based hooks.

Combinar resultados de múltiplos hooks

Quando múltiplos hooks correspondem ao mesmo evento, o comando de cada hook executa até a conclusão antes do Claude Code mesclar os resultados. Um hook retornando deny não impede que hooks irmãos executem. Não confie em um deny de um hook para suprimir efeitos colaterais em outro hook. Após todos os hooks correspondentes terminarem, Claude Code combina suas saídas. Para decisões de permissão PreToolUse, a resposta mais restritiva vence, na ordem deny, defer, ask, allow. Texto de additionalContext é mantido de cada hook e passado ao Claude junto. O exemplo abaixo registra dois hooks PreToolUse em Bash. O primeiro anexa cada comando a um arquivo de log e sai com 0. O segundo executa um script que sai com 2 para negar quando o comando contém rm -rf:
Quando Claude tenta executar rm -rf /tmp/build, ambos os hooks executam em paralelo. O hook de logging escreve o comando em ~/.claude/bash.log e sai com 0, o que não relata nenhuma decisão. O hook de proteção sai com 2, o que nega a chamada de ferramenta. O deny vence, então Claude Code bloqueia o comando e mostra ao Claude o stderr da proteção. A entrada de log ainda é escrita porque o hook de logging já executou.

Ler entrada e retornar saída

Hooks se comunicam com Claude Code através de stdin, stdout, stderr e códigos de saída. Quando um evento dispara, Claude Code passa dados específicos do evento como JSON para stdin do seu script. Seu script lê esses dados, faz seu trabalho e diz ao Claude Code o que fazer a seguir através do código de saída.

Entrada do hook

Cada evento inclui campos comuns como session_id, um ID único para a sessão, e cwd, o diretório de trabalho quando o evento disparou, mas cada tipo de evento adiciona dados diferentes. Quando Claude executa um comando Bash, um hook PreToolUse recebe estes campos em stdin:
  • hook_event_name: o evento que acionou o hook
  • tool_name: a ferramenta que Claude está prestes a usar
  • tool_input: os argumentos que Claude passou para a ferramenta. Para Bash, seu campo command contém o comando shell.
Por exemplo, a entrada do hook para um comando npm test se parece com isto:
Seu script pode analisar esse JSON e agir em qualquer um desses campos. Hooks UserPromptSubmit obtêm o texto prompt em vez disso, hooks SessionStart obtêm uma source de startup, resume, clear, compact, ou fork, e assim por diante. Consulte Campos de entrada comuns na referência para campos compartilhados, e a seção de cada evento para esquemas específicos do evento.

Saída do hook

Seu script diz ao Claude Code o que fazer a seguir escrevendo para stdout ou stderr e saindo com um código específico. O seguinte hook PreToolUse bloqueia um comando:
Com um código de saída diferente de 0 e 2 e sem saída JSON válida, a ação prossegue na maioria dos eventos, a menos que o hook seja um cuja falha bloqueia a ação. Um hook com onFailure definido como "block" é um exemplo. Saia com 0 para não relatar nenhuma objeção, ou saia com 2 para bloquear a ação:
  • Exit 0: se você sair com 0 de um hook PreToolUse, a chamada de ferramenta ainda passa pelo fluxo de permissão normal, porque exit 0 não a aprova. Para hooks UserPromptSubmit, UserPromptExpansion, SessionStart e PostModelSwitch, Claude Code adiciona stdout que trata como texto simples ao contexto do Claude.
  • Exit 2: escreva um motivo para stderr. Dependendo do evento, Claude o recebe como feedback para que possa se ajustar, o usuário o vê, ou nenhuma mensagem aparece, como com ConfigChange e Elicitation. Alguns eventos não podem ser bloqueados: para SessionStart e outros, exit 2 mostra stderr ao usuário e a execução continua. Consulte comportamento do código de saída 2 por evento para a lista completa.
  • Qualquer outro código de saída: para as exceções por evento, como WorktreeCreate falhando em qualquer saída diferente de zero, consulte Saída do código de saída. Em outros eventos, a menos que o hook seja um cuja falha bloqueia a ação, encontre seu caso pelo que seu hook imprimiu em stdout:
    • Um objeto analisado que passa na validação de esquema: Claude Code ignora o código de saída, apenas o JSON decide o resultado, e o hook não é relatado como um erro.
    • Um objeto analisado que falha na validação de esquema, ou stdout que Claude Code tenta analisar como JSON mas que não é JSON válido: a ação prossegue como um erro não bloqueador. Verifique o aviso <hook name> hook error para a mensagem de validação ou análise.
    • Stdout que Claude Code trata como texto simples, ou stdout vazio: a ação prossegue como um erro não bloqueador. A transcrição mostra um aviso <hook name> hook error, depois a primeira linha de stderr prefixada com Failed with non-blocking status code:. Para capturar o stderr completo, ative debug logging com claude --debug ou executando /debug no meio da sessão.

Saída JSON estruturada

Códigos de saída lhe dão apenas bloquear ou ficar em silêncio. Para mais controle, saia com 0 e imprima um objeto JSON para stdout em vez disso.
Use exit 2 para bloquear com uma mensagem stderr, ou exit 0 com JSON para controle estruturado. Escolha uma abordagem por hook. Para o que acontece quando você as mistura, consulte Saída do código de saída.
Por exemplo, um hook PreToolUse pode negar uma chamada de ferramenta e dizer ao Claude por quê, ou escalar para o usuário para aprovação:
Com "deny", Claude Code cancela a chamada de ferramenta e alimenta permissionDecisionReason de volta ao Claude. Em PreToolUse, você também pode retornar "ask" para mostrar ao usuário o prompt de permissão normal, ou "allow" para pular o prompt de permissão interativo. Com "allow", regras de negação e pedido, incluindo listas de negação gerenciadas por empresa, ainda se aplicam, assim como prompts para: Um quarto valor, "defer", está disponível em modo não interativo com a flag -p. Retorná-lo encerra o turno com a chamada de ferramenta preservada, para que um wrapper do Agent SDK possa coletar entrada e retomar. Consulte Adiar uma chamada de ferramenta para depois na referência. Um hook PreModelSwitch retorna o mesmo campo permissionDecision: "allow" deixa uma mudança de modelo prosseguir, e "deny" a cancela. "ask" faz você confirmar a mudança quando você executa /model em uma sessão interativa; em qualquer outro lugar, Claude Code trata "ask" como uma recusa. Consulte Controle de decisão PreModelSwitch. Outros eventos usam padrões de decisão diferentes. Por exemplo, hooks PostToolUse e Stop usam um campo decision: "block" de nível superior, enquanto PermissionRequest usa hookSpecificOutput.decision.behavior. Consulte a tabela de resumo na referência para uma análise completa por evento. Para hooks UserPromptSubmit, use hookSpecificOutput.additionalContext em vez disso para injetar texto no contexto do Claude. Aninhe additionalContext dentro de hookSpecificOutput; se você o colocar no nível superior do JSON, Claude Code o ignora silenciosamente. Por exemplo, esta saída adiciona o estado do branch atual a cada prompt:
Consulte Controle de decisão UserPromptSubmit para a forma de saída completa, incluindo bloqueio de prompts e definição do título da sessão. Hooks com type: "prompt" lidam com saída de forma diferente: consulte Prompt-based hooks.

Filtrar hooks com matchers

Sem um matcher, um hook dispara em cada ocorrência de seu evento. Matchers permitem restringir isso. Por exemplo, se você quer executar um formatador apenas após edições de arquivo, não após cada chamada de ferramenta, adicione um matcher ao seu hook PostToolUse:
O matcher "Edit|Write" dispara apenas quando Claude usa a ferramenta Edit ou Write, não quando usa Bash, Read ou qualquer outra ferramenta. Uma vírgula separa alternativas da mesma forma, então "Edit, Write" é equivalente. Consulte Padrões de matcher para como nomes simples e expressões regulares são avaliados.
Claude também pode criar ou modificar arquivos executando comandos shell. Se seu hook deve ver cada mudança de arquivo, como para varredura de conformidade ou registro de auditoria, adicione um hook Stop que varre a árvore de trabalho uma vez por turno. Para cobertura por chamada em vez disso, também corresponda Bash|PowerShell e tenha seu script listar arquivos modificados e não rastreados com git status --porcelain. A seção Entrada do hook PowerShell explica por que corresponder apenas Bash não é suficiente. Para executar um hook quando um arquivo específico muda no disco, seja qual for o que o escreveu, use um hook FileChanged.
Cada tipo de evento corresponde a um campo específico: As abas abaixo mostram alguns matchers adicionais em diferentes tipos de evento.
Corresponda apenas chamadas de ferramenta Bash e registre cada comando em um arquivo. O evento PostToolUse dispara após o comando ser concluído, então tool_input.command contém o que foi executado. O hook recebe os dados do evento como JSON em stdin, e jq -r '.tool_input.command' extrai apenas a string de comando, que >> anexa ao arquivo de log:

Filtrar por nome de ferramenta e argumentos com o campo if

O campo if usa sintaxe de regra de permissão para filtrar hooks por nome de ferramenta e argumentos juntos, para que o processo do hook apenas seja gerado quando a chamada de ferramenta corresponder. Isto vai além de matcher, que filtra no nível do grupo apenas por nome de ferramenta. Por exemplo, esta configuração executa um hook apenas quando Claude usa comandos git em vez de todos os comandos Bash:
Se seu hook deve executar depende da forma do seu padrão if e do comando Bash que Claude está invocando: Quando Claude Code não consegue determinar quais comandos a entrada Bash executa, ele executa seu hook independentemente do padrão. A tabela de correspondência Bash cobre as formas de comando que Claude Code consegue e não consegue restringir por subcomando. Como o filtro é melhor esforço, use o sistema de permissão em vez de um hook para impor um allow ou deny difícil. O campo if aceita os mesmos padrões que regras de permissão: "Bash(git *)", "Edit(*.ts)", e assim por diante. Para corresponder múltiplos nomes de ferramenta, use manipuladores separados cada um com seu próprio valor if, ou corresponda no nível matcher onde alternação de pipe é suportada. if funciona apenas em eventos de ferramenta: PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest e PermissionDenied. Adicioná-lo a qualquer outro evento impede o hook de executar.

Configurar local do hook

Onde você adiciona um hook determina seu escopo: Execute /hooks no Claude Code para navegar por todos os hooks configurados agrupados por evento. Para desabilitar hooks, defina "disableAllHooks": true no seu arquivo de configuração. Claude Code lê o valor deixado após precedência de configurações se aplicar, então o arquivo de configuração de um projeto pode sobrescrever o seu. Hooks configurados em configurações gerenciadas ainda executam a menos que disableAllHooks também esteja definido lá. Para o alcance completo de cada nível, consulte disableAllHooks. Se você editar arquivos de configuração diretamente enquanto Claude Code está em execução, o observador de arquivo normalmente pega mudanças de hook automaticamente.

Hooks baseados em prompt

Para decisões que exigem julgamento em vez de regras determinísticas, use hooks type: "prompt". Em vez de executar um comando shell, Claude Code envia seu prompt e os dados de entrada do hook para um modelo Claude para tomar a decisão. Você pode especificar um modelo diferente com o campo model se precisar de mais capacidade. O único trabalho do modelo é retornar sua decisão como JSON:
  • "ok": true: a ação prossegue
  • "ok": false: o que acontece depende do evento:
    • Stop e SubagentStop: o reason é alimentado de volta ao Claude para que ele continue trabalhando, a menos que a resposta também defina "impossible": true para marcar a condição como uma que nunca pode ser satisfeita, caso em que Claude Code permite a parada e o turno termina
    • PreToolUse: a chamada de ferramenta é negada; por padrão o turno termina e o reason de negação aparece no chat como uma linha de aviso. Defina continueOnBlock: true no hook para, em vez disso, retornar o reason ao Claude como o erro da ferramenta, para que ele possa se ajustar e continuar
    • PostToolUse: por padrão o turno termina e o reason aparece no chat como uma linha de aviso. Defina continueOnBlock: true para alimentar o reason de volta ao Claude e continuar o turno em vez disso
    • PostToolBatch, UserPromptSubmit e UserPromptExpansion: o turno termina e o reason aparece no chat como uma linha de aviso
Este exemplo usa um hook Stop para perguntar ao modelo se todas as tarefas solicitadas estão completas. Se o modelo retornar "ok": false porque a condição ainda não foi atendida, Claude continua trabalhando e usa o reason como sua próxima instrução:
Para opções de configuração completas, consulte Hooks baseados em prompt na referência.

Hooks baseados em agente

Hooks de agente são experimentais. Comportamento e configuração podem mudar em futuras versões. Para fluxos de trabalho de produção, prefira hooks de comando.
Quando a verificação exige inspecionar arquivos ou executar comandos, use hooks type: "agent". Diferentemente de hooks de prompt que fazem uma única chamada LLM, hooks de agente geram um subagente que pode ler arquivos, pesquisar código e usar outras ferramentas para verificar condições antes de retornar uma decisão. Hooks de agente usam o formato de resposta "ok" / "reason" com um timeout padrão mais longo de 60 segundos e até 50 turnos de uso de ferramenta. Eles não suportam o campo impossible de hooks de prompt. Em ok: false, Claude Code trata um hook de agente da mesma forma que trata um hook de prompt com continueOnBlock: true no mesmo evento, portanto em PreToolUse e PostToolUse o turno continua; hooks de agente não têm campo continueOnBlock. Consulte configuração de hook de agente para os campos, incluindo o placeholder $ARGUMENTS que Claude Code substitui pela entrada JSON do hook. Este exemplo verifica que os testes passam antes de permitir que Claude pare:
Use hooks de prompt quando os dados de entrada do hook sozinhos são suficientes para tomar uma decisão. Use hooks de agente quando você precisa verificar algo contra o estado real da base de código. Para opções de configuração completas, consulte Hooks baseados em agente na referência.

HTTP hooks

Use type: "http" hooks para fazer POST de dados de evento para um endpoint HTTP em vez de executar um comando shell. O endpoint recebe o mesmo JSON que um hook de comando receberia em stdin, e retorna resultados através do corpo da resposta HTTP usando o mesmo formato JSON. HTTP hooks são úteis quando você quer que um servidor web, função em nuvem ou serviço externo manipule a lógica do hook: por exemplo, um serviço de auditoria compartilhado que registra eventos de uso de ferramenta em toda uma equipe. Este exemplo faz POST de cada uso de ferramenta para um serviço de logging local:
Seu endpoint responde com um corpo JSON no mesmo formato de saída que hooks de comando, e o Claude Code também verifica o status da resposta:
  • Status 2xx: para bloquear uma chamada de ferramenta, retorne os campos hookSpecificOutput apropriados no corpo.
  • Qualquer outro status, ou se a requisição falhar: o Claude Code reporta um erro não bloqueante e permite que a ação continue, exceto quando o hook é um cuja falha bloqueia a ação. Para fazer com que um endpoint com falha bloqueie a ação, defina onFailure: "block" no hook.
Valores de header suportam interpolação de variável de ambiente usando sintaxe $VAR_NAME ou ${VAR_NAME}. Apenas variáveis listadas no array allowedEnvVars são resolvidas; todas as outras referências $VAR permanecem vazias. Para opções de configuração completas e manipulação de resposta, consulte HTTP hooks na referência.

Limitações e solução de problemas

Limitações

Tenha em mente estas restrições ao projetar hooks:
  • Hooks de comando se comunicam apenas através de stdout, stderr e códigos de saída. Eles não podem disparar comandos / ou chamadas de ferramenta. Texto retornado via additionalContext é injetado como um lembrete do sistema que Claude lê como texto simples. HTTP hooks se comunicam através do corpo da resposta em vez disso.
  • Os timeouts do hook variam por tipo. Substitua por hook com o campo timeout em segundos.
    • command, http, mcp_tool: 10 minutos. Claude Code reduz este padrão para 30 segundos para hooks UserPromptSubmit, PreModelSwitch e PostModelSwitch, e para 10 segundos para hooks MessageDisplay.
    • prompt: 30 segundos.
    • agent: 60 segundos.
    • Hooks SessionEnd de qualquer tipo compartilham um orçamento de 1,5 segundo. Se suas configurações definirem um timeout por hook mais longo, Claude Code aumenta o orçamento para corresponder, até 60 segundos.
  • Hooks PostToolUse não podem desfazer ações já que a ferramenta já foi executada.
  • Hooks PermissionRequest disparam quando Claude Code está prestes a pedir permissão a você, ou quando, caso contrário, negaria automaticamente uma chamada que não pode pedir confirmação. Em modo não interativo com a flag -p, eles ainda são executados fora do modo dontAsk, e uma chamada sobre a qual nenhum hook decide e que nada mais pode responder é negada.
  • Hooks Stop disparam sempre que Claude termina de responder, não apenas na conclusão de tarefas. Eles não disparam em interrupções do usuário. Erros de API disparam StopFailure em vez disso.
  • Quando múltiplos hooks PreToolUse retornam updatedInput para reescrever a entrada de uma ferramenta, Claude Code não mescla as reescritas nem garante com qual reescrita a ferramenta será executada. Evite ter mais de um hook reescrevendo a entrada da mesma ferramenta.

Hooks e modos de permissão

Com um hook em um arquivo de configuração ou no hooks/hooks.json de um plugin, você não pode afrouxar restrições além do que as regras de permissão permitem, e um "deny" de um hook prevalece em todo modo de permissão: Em modo de planejamento, se seu hook PreToolUse retornar "allow" para uma edição de arquivo, você recebe o mesmo prompt, bloqueio ou aprovação que a edição receberia sem nenhum hook. Para remover este limite nas aprovações de hooks, aprove o plano ou mude para outro modo de permissão.
  • "deny" em todo modo de permissão: um hook que retorna permissionDecision: "deny" bloqueia a ferramenta mesmo em modo bypassPermissions ou com --dangerously-skip-permissions. Hooks PreToolUse disparam antes de qualquer verificação de modo de permissão, em cada modo de permissão, incluindo dontAsk. Isto permite que você aplique política que usuários não podem contornar mudando seu modo de permissão.
Sua máquina pode não ter configurações gerenciadas nem um arquivo managed-mcp.json, e sua sessão pode não usar credenciais de /login para um plano Team ou Enterprise. Nesse cenário, um mod pode aprovar uma chamada que seu hook PreToolUse bloqueou. Uma sessão que é executada com uma chave de API ou um CLAUDE_CODE_OAUTH_TOKEN de longa duração em vez disso não está usando esse login, mesmo quando esse login está armazenado.Em modo de planejamento, um mod pode aprovar tal chamada bloqueada apenas quando ela é somente leitura, portanto não uma edição de arquivo. Para os casos em que a aprovação de um mod não passa pelas suas regras e hooks, veja Estender permissões com hooks.

Hook não dispara

O hook está configurado mas nunca executa.
  • Execute /hooks e confirme que o hook aparece sob o evento correto
  • Para um hook no frontmatter de uma skill, invoque a skill ou peça a Claude que o faça, depois execute /hooks novamente. /hooks não lista hooks de uma skill que não foi invocada na sessão. Se /hooks ainda não listar o hook, verifique outras causas, como frontmatter que não foi analisado ou um dos limites em hooks de skills
  • Verifique que o padrão do matcher corresponde ao nome da ferramenta exatamente. Matchers são sensíveis a maiúsculas
  • Verifique que você está acionando o tipo de evento correto: PreToolUse dispara antes da execução da ferramenta, PostToolUse dispara depois. Um hook PermissionRequest dispara quando Claude Code está prestes a pedir permissão a você; veja as limitações para os casos não-interativos

Erro de hook na saída

Você vê uma mensagem como “PreToolUse hook error: …” na transcrição.
  • Seu script saiu com um código não-zero inesperadamente. Teste-o manualmente canalizando JSON de amostra:
  • Se você vir “command not found”, use caminhos absolutos ou ${CLAUDE_PROJECT_DIR} para referenciar scripts. Para evitar quoting de shell completamente, adicione "args": [] para mudar para forma exec, que gera o script diretamente sem um shell
  • Se você vir “jq: command not found”, instale jq ou use Python/Node.js para análise JSON
  • Se a mensagem incluir blocking because Git Bash wasn't found, você está no Windows, Claude Code não encontrou o Git Bash, e o hook que falhou ou atingiu o timeout bloqueou a chamada de ferramenta. Veja Hooks com falha no Windows sem Git Bash para as correções
  • Se o aviso mostra uma mensagem de validação JSON, a stdout do seu hook foi analisada como JSON mas falhou na validação de esquema. Se mostra uma mensagem de análise JSON, a stdout parecia um objeto JSON mas não era JSON válido. Ambos acontecem mesmo em saída 0. Para corrigir uma falha de análise, construa o payload com um codificador JSON como jq em vez de concatenação de string, para que aspas e barras invertidas dentro de valores sejam escapadas. A seção Saída de código de saída da referência cobre as combinações de código de saída e JSON
  • Se o script não está executando em tudo, torne-o executável: chmod +x ./my-hook.sh

/hooks mostra nenhum hook configurado

Você editou um arquivo de configuração mas os hooks não aparecem no menu.
  • Edições de arquivo são normalmente capturadas automaticamente. Se não tiverem aparecido após alguns segundos, o observador de arquivo pode ter perdido a mudança: reinicie sua sessão para forçar um recarregamento.
  • Verifique que seu JSON é válido: vírgulas finais e comentários não são permitidos
  • Confirme que o arquivo de configuração está no local correto: .claude/settings.json para hooks de projeto, ~/.claude/settings.json para hooks globais
  • Se o menu mostrar Only hooks from managed settings run here, sua organização definiu allowManagedHooksOnly. Hooks nos seus arquivos de configuração de usuário, de projeto e locais não são executados e não são listados

Stop hook atinge o limite de bloqueio

Claude continua trabalhando em vez de parar, depois termina a rodada com um aviso de que o Stop hook bloqueou muitas vezes consecutivas sem progresso. Claude Code sobrescreve um Stop hook depois que ele bloqueia oito vezes seguidas sem nenhuma chamada de ferramenta de Claude entre elas. Seu script de hook precisa verificar se já acionou uma continuação. Analise o campo stop_hook_active da entrada JSON e saia cedo se for true:
Se seu hook legitimamente precisa de mais de oito iterações para convergir, aumente o limite com CLAUDE_CODE_STOP_HOOK_BLOCK_CAP.

Hook JSON não tem efeito

Seu hook imprime JSON válido, mas a decisão não entra em vigor e nenhum erro aparece na transcrição. Verifique qual causa se aplica:
  • Saída extra antes do JSON: algo mais escreve para stdout primeiro, geralmente um echo incondicional no seu perfil de shell, então a saída não começa mais com {. Veja Saída do perfil de shell antes do JSON.
  • Um campo no nível errado: compare a colocação de cada campo contra o formato saída JSON. Por exemplo, permissionDecision pertence dentro de hookSpecificOutput, não no nível superior. Veja Campos no nível errado.

Saída do perfil de shell antes do JSON

Hooks executam em shells não interativos, mas Git Bash e algumas configurações, como BASH_ENV apontando para ~/.bashrc, ainda carregam seu perfil, e qualquer coisa que o perfil imprima chega à stdout antes do JSON do seu hook:
A menos que o hook seja assíncrono, Claude Code lê saída que não começa com { como texto simples, então seu JSON é ignorado. Como o hook saiu com 0, a transcrição também não mostra nenhum erro. Para verificar esta causa, inicie Claude Code com claude --debug, acione o hook e procure no log de debug por Hook output does not start with {. Para corrigir isto, envolva as instruções echo no seu perfil para que executem apenas em shells interativos:
A variável $- contém flags de shell, e i significa interativo. Hooks executam em shells não-interativos, então o echo é pulado.

Campos no nível errado

Quando seu hook retorna permissionDecision ou additionalContext no nível superior em vez de dentro de hookSpecificOutput, o JSON ainda analisa, e Claude Code ignora os campos deslocados sem reportar um erro. Para ver quais campos foram ignorados, inicie Claude Code com claude --debug e procure no log de debug por Hook JSON output had unrecognized keys.

Verificar o que um hook fez

Pressione Ctrl+O para abrir a visualização de transcrição e procure o resultado do hook:
  • Sucesso: você não vê nada, a menos que o JSON do hook exiba algo, como systemMessage ou feedback de Stop hook.
    • Para confirmar que o hook executou, verifique seu efeito, como um arquivo reformatado
  • Erro de bloqueio: na maioria dos eventos você vê a mensagem que acompanhou o bloqueio, por exemplo Blocked: rm commands are not allowed. Em alguns eventos, como ConfigChange e Elicitation, você não vê nenhuma mensagem. Código de saída 2 explica de onde vem a mensagem.
  • Erro de não-bloqueio: você vê um aviso <hook name> hook error com uma explicação breve, como a primeira linha de stderr após Failed with non-blocking status code:, ou uma mensagem de validação ou análise JSON. A ação prosseguiu.
Para consultar o resultado de um código de saída e stdout específicos, incluindo as exceções por evento, veja Saída de código de saída na referência. Para detalhes de execução completos incluindo códigos de saída, stdout e stderr dos hooks, leia o log de debug. Inicie Claude Code com claude --debug-file /tmp/claude.log para escrever em um caminho conhecido, depois tail -f /tmp/claude.log em outro terminal. Se você iniciou sem essa flag, execute /debug no meio da sessão para habilitar logging e encontrar o caminho do log.

Saiba mais