Ciclo de vida do hook
Claude Code executa hooks em pontos específicos durante uma sessão. Quando um evento dispara e um matcher corresponde, Claude Code passa contexto JSON sobre o evento para seu manipulador de hook. Para hooks de comando, a entrada chega em stdin. Para hooks HTTP, chega como corpo da solicitação POST. Seu manipulador pode então inspecionar a entrada, tomar ação e opcionalmente retornar uma decisão. Os eventos caem em três cadências:- por sessão:
SessionStarteSessionEnd - por turno:
UserPromptSubmit,StopeStopFailure - em cada chamada de ferramenta dentro do loop agentic:
PreToolUseePostToolUse, exceto chamadasEndConversation, que pulam ambas
Como um hook é resolvido
Para ver como o evento, o matcher e o manipulador se encaixam, considere este hookPreToolUse que bloqueia comandos shell destrutivos.
- macOS/Linux
- Windows (PowerShell)
O O script lê a entrada JSON de stdin, extrai o comando e retorna uma Este script, como os outros exemplos Bash nesta página que analisam entrada JSON, usa
matcher se restringe a chamadas de ferramenta Bash e a comandos Monitor, e a condição if se restringe ainda mais a subcomandos Bash correspondendo a rm *, então block-rm.sh apenas é gerado quando ambos os filtros correspondem:permissionDecision de "deny" se contiver rm -rf. Salve-o em .claude/hooks/block-rm.sh em seu projeto e torne-o executável com chmod +x .claude/hooks/block-rm.sh para que Claude Code possa executá-lo:jq, então instale jq e certifique-se de que está em seu PATH antes de tentar executá-los.Bash "rm -rf /tmp/build" contra a configuração macOS/Linux. Aqui está o que acontece:
1
Evento dispara
O evento
PreToolUse dispara. Claude Code envia a entrada da ferramenta como JSON em stdin para o hook:2
Matcher verifica
O matcher
"Bash" corresponde ao nome da ferramenta, então este grupo de hook é ativado. Se você omitir o matcher ou usar "*", o grupo é ativado em cada ocorrência do evento.3
Condição if verifica
A condição
if "Bash(rm *)" corresponde porque rm -rf /tmp/build é um subcomando correspondendo a rm *, então este manipulador é gerado. Se o comando tivesse sido npm test, a verificação if falharia e block-rm.sh nunca seria executado, evitando a sobrecarga de geração de processo. O campo if é opcional; sem ele, cada manipulador no grupo correspondido é executado.4
Manipulador de hook executa
O script inspeciona o comando completo e encontra Se o comando tivesse sido uma variante mais segura de
rm -rf, então imprime uma decisão em stdout:rm como rm file.txt, o script teria atingido exit 0 em vez disso. Código de saída 0 sem saída significa que o hook não tem decisão a relatar, então a chamada da ferramenta continua através do fluxo de permissão normal. O hook pode negar a chamada, mas ficar em silêncio não a aprova.5
Claude Code age sobre o resultado
Claude Code lê a decisão JSON, bloqueia a chamada da ferramenta e mostra a razão ao Claude.
Configuração
Hooks são definidos em arquivos de configurações JSON. A configuração tem três níveis de aninhamento:- Escolha um evento de hook para responder, como
PreToolUseouStop - Adicione um grupo de matcher para filtrar quando ele é acionado, como “para a ferramenta Bash”
- Defina um ou mais manipuladores de hook para executar quando correspondido
Esta página usa termos específicos para cada nível: evento de hook para o ponto do ciclo de vida, grupo de matcher para o filtro e manipulador de hook para o comando shell, endpoint HTTP, ferramenta MCP, prompt ou agente que executa. “Hook” por si só refere-se ao recurso geral.
Locais de hooks
Onde você define um hook determina seu escopo:
Sessões na nuvem não leem seu
~/.claude/settings.json local. Em um ambiente auto-hospedado, Claude Code também executa os hooks que o operador propagou do ~/.claude/ do host do runner, e executa os hooks no arquivo de configurações gerenciadas da imagem do runner quando esse arquivo está entre as fontes gerenciadas que Claude Code aplica, o que por padrão significa apenas quando nem configurações gerenciadas pelo servidor nem uma política Claude Code entregue por MDM fornece o nível gerenciado. Consulte o que é transferido da sua configuração para saber quais arquivos de configurações e plugins, e portanto quais hooks, chegam a uma sessão na nuvem.
Para detalhes sobre resolução de arquivo de configurações, consulte settings.
Hooks de arquivos de configurações, configurações de política gerenciada e plugins também executam dentro de subagentes. Quando um subagente chama uma ferramenta, eventos de ferramenta como PreToolUse e PostToolUse disparam os mesmos hooks configurados que na conversa principal, e a entrada carrega os campos de entrada comuns agent_id e agent_type que identificam o subagente.
Administradores podem usar allowManagedHooksOnly em configurações gerenciadas para restringir quais hooks executam:
- Seus hooks de usuário, projeto, local e plugin são bloqueados. Hooks de plugins forçadamente ativados em configurações gerenciadas
enabledPluginssão isentos - Claude Code também restringe suas configurações
statusLineefileSuggestionàs configurações gerenciadas - Claude Code também desabilita plugins com uma fonte
command, incluindo plugins forçadamente ativados em configurações gerenciadasenabledPlugins, a menos quedisableCommandPluginSourcesseja explicitamente definido comofalse. Fontescommandrequerem Claude Code v2.1.229 ou posterior - Claude Code também bloqueia comandos
headersHelperdo marketplace a menos quedisableCommandPluginSourcesseja explicitamente definido comofalse, exceto para um marketplace que as próprias configurações gerenciadas declarem
allowManagedHooksOnly.
Entradas de hook se mesclam entre níveis de configurações em vez de se substituírem: configurações de usuário, projeto e local adicionam seus próprios hooks sem remover os gerenciados, e a configuração disableAllHooks não pode desabilitar hooks gerenciados de fora das configurações gerenciadas.
As listas de permissões de hook HTTP se aplicam a hooks de todas as fontes, incluindo configurações de política gerenciada:
allowedHttpHookUrls: quando definido em qualquer nível de configurações, Claude Code executa um manipulador de hook HTTP apenas se sua URL corresponder à lista de permissões mescladahttpHookAllowedEnvVars: quando definido, Claude Code interpola apenas as variáveis de ambiente nessa lista em cabeçalhos de hook
Padrões de matcher
O campomatcher filtra quando hooks disparam. Como um matcher é avaliado depende dos caracteres que contém:
Um matcher no caminho de expressão regular é testado com
RegExp.prototype.test do JavaScript, que sucede em uma correspondência em qualquer lugar no valor. Edit.* corresponde tanto a Edit quanto a NotebookEdit; envolva o padrão em ^ e $, como em ^Edit$, quando você precisa de uma correspondência de string inteira.
FileChanged e StopFailure usam um conjunto de correspondência exata mais estreito de apenas letras, dígitos, _ e |. Um hífen, espaço ou vírgula em um matcher para esses dois eventos o mantém no caminho de expressão regular, e apenas | separa alternativas. Todos os outros eventos com suporte a matcher na tabela a seguir aceitam | ou ,.
O evento FileChanged não segue essas regras ao construir sua lista de monitoramento. Consulte FileChanged.
Cada tipo de evento corresponde em um campo diferente:
Corresponder
StopFailure em cloud_credential_error requer Claude Code v2.1.267 ou posterior, a primeira versão que relata falhas de carregamento de credenciais sob esse valor em vez de server_error ou unknown.
Para a maioria dos eventos, Claude Code avalia o matcher contra um campo da entrada JSON que envia para seu hook em stdin. Para eventos de ferramenta, esse campo é tool_name. Para PreModelSwitch e PostModelSwitch, Claude Code avalia o matcher contra o nome canônico que deriva de to_model, conforme descrito em PreModelSwitch. Cada seção evento de hook lista o conjunto completo de valores de matcher e o esquema de entrada para esse evento.
Este exemplo executa um script de linting apenas quando Claude escreve ou edita um arquivo:
matcher a um evento sem suporte a matcher, ele é silenciosamente ignorado.
Para eventos de ferramenta, você pode filtrar mais estreitamente definindo o campo if em manipuladores de hook individuais. if usa sintaxe de regra de permissão para corresponder contra o nome da ferramenta e argumentos juntos, então "Bash(git *)" executa quando qualquer subcomando da entrada Bash corresponde a git * e "Edit(*.ts)" executa apenas para arquivos TypeScript.
Corresponder ferramentas MCP
Ferramentas de servidor MCP aparecem como ferramentas regulares em eventos de ferramenta (PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, PermissionDenied), então você pode corresponder a elas da mesma forma que corresponde a qualquer outro nome de ferramenta.
Ferramentas MCP seguem o padrão de nomenclatura mcp__<server>__<tool>, por exemplo:
mcp__memory__create_entities: ferramenta create entities do servidor Memorymcp__filesystem__read_file: ferramenta read file do servidor Filesystemmcp__github__search_repositories: ferramenta search do servidor GitHub
.* ao prefixo do servidor. O .* é obrigatório: um matcher como mcp__memory ou mcp__brave-search contém apenas caracteres de correspondência exata, então é comparado como uma string exata e não corresponde a nenhuma ferramenta.
mcp__memory__.*corresponde a todas as ferramentas do servidormemorymcp__brave-search__.*corresponde a todas as ferramentas de um servidor cujo nome contém um hífenmcp__.*__write.*corresponde a qualquer ferramenta cujo nome começa comwritede qualquer servidor
mcp__plugin_<plugin-name>_<server-name>__<tool>. Um matcher escrito contra a chave do servidor simples nunca dispara para essas ferramentas. Para um plugin nomeado my-plugin que agrupa um servidor sob a chave db, uma ferramenta query aparece como mcp__plugin_my-plugin_db__query, então o matcher para cada ferramenta daquele servidor é mcp__plugin_my-plugin_db__.*. Use o mesmo nome de ferramenta com escopo no campo if de um manipulador. Consulte Servidores MCP fornecidos por plugin para saber como o nome com escopo é construído.
Este exemplo registra todas as operações do servidor memory e valida operações de escrita de qualquer servidor MCP:
Corresponder comandos Monitor
Um hookPreToolUse ou PermissionRequest com um matcher Bash também executa em comandos shell que Claude inicia com a ferramenta Monitor, mas seu allow e seu updatedInput não têm efeito sobre eles. Requer Claude Code v2.1.314 ou posterior. Matchers como Bash|PowerShell, ^Bash$ e Bash.* também são matchers Bash. Um hook com um matcher Bash não executa para um WebSocket watch, e um hook PostToolUse com esse matcher não executa para Monitor.
Um hook que executa para um comando Monitor pode negá-lo ou fazer com que Claude Code pergunte a você sobre ele. Para permitir ou reescrever o comando, troque o matcher Bash por um que inclua Monitor:
- Matcher que inclui Monitor: com um matcher como
Bash|Monitorou.*, ou sem matcher, o hook recebe a própria entrada da chamada Monitor, ealloweupdatedInputse aplicam. Emif, nomeie Monitor, como emMonitor(tail *), que corresponde pelas regras queBash(tail *)segue. Se o seuifnomear Bash, o hook ainda recebe a entrada da chamada Monitor, masalloweupdatedInputnão têm efeito - Matcher
Bash: o hook recebe uma chamada Bash. Emif, nomeie Bash, como emBash(tail *). O hook não executa se o seuifnomear Monitor
Campos do manipulador de hook
Cada objeto no arrayhooks interno é um manipulador de hook: o comando shell, endpoint HTTP, ferramenta MCP, prompt LLM ou agente que executa quando o matcher corresponde. Existem cinco tipos:
- Hooks de comando (
type: "command"): executam um comando shell. Seu script recebe a entrada JSON do evento em stdin e comunica resultados através de códigos de saída e stdout. - Hooks HTTP (
type: "http"): enviam a entrada JSON do evento como uma solicitação HTTP POST para uma URL. O endpoint comunica resultados através do corpo da resposta usando o mesmo formato de saída JSON que hooks de comando. - Hooks de ferramenta MCP (
type: "mcp_tool"): chamam uma ferramenta em um servidor MCP configurado. A saída de texto da ferramenta é tratada como stdout de hook de comando. - Hooks de prompt (
type: "prompt"): enviam um prompt para um modelo Claude para avaliação de turno único. O modelo retorna sua decisão como JSON. Consulte Hooks baseados em prompt. - Hooks de agente (
type: "agent"): geram um subagente que pode usar ferramentas como Read, Grep e Glob para verificar condições antes de retornar uma decisão. Hooks de agente são experimentais e podem mudar. Consulte Hooks baseados em agente.
timeout de cada hook em espera começa a contar quando esse hook inicia.
Se você definir o mesmo manipulador em mais de um arquivo de configurações, ele executa uma vez. Uma cópia do mesmo manipulador de um plugin ou skill permanece separada.
Manipuladores executam no diretório atual com o ambiente do Claude Code. Se o diretório atual não existir mais, por exemplo um worktree ou diretório temporário que outro shell deletou no meio da sessão, Claude Code executa hooks de comando a partir do primeiro destes que ainda existe: o diretório em que a sessão começou, a raiz do projeto, seu diretório home ou o diretório temporário do sistema. Claude Code registra um aviso nomeando o diretório de fallback no log de debug. Para uma sessão de worktree que você inicia a partir do aplicativo desktop, consulte O que os worktrees compartilham com o checkout principal.
A variável de ambiente $CLAUDE_CODE_REMOTE é "true" em ambientes web remotos e não é definida na CLI local. Claude Code v2.1.199 e posterior define $CLAUDE_CODE_BRIDGE_SESSION_ID para o ID de sessão Remote Control enquanto a sessão local tem uma conexão Remote Control ativa.
Campos comuns
Esses campos se aplicam a todos os tipos de hook:
O campo
if contém exatamente uma regra de permissão. Não há sintaxe &&, || ou lista para combinar regras; para aplicar múltiplas condições, defina um manipulador de hook separado para cada.
Em uma condição if para uma ferramenta de arquivo, um padrão de diretório de segmento único como "Edit(src/**)" corresponde apenas ao diretório src no diretório de trabalho e aos arquivos sob ele. Para corresponder a um diretório nomeado src em qualquer profundidade, escreva "Edit(**/src/**)".
Como padrões if correspondem a comandos Bash
Para padrões Bash no campo if, se seu comando de hook executa depende da forma do padrão e do comando Bash que Claude está invocando. Atribuições VAR=value iniciais são removidas antes da correspondência.
Quando Claude Code não pode determinar quais comandos a entrada Bash executa, ele executa seu hook independentemente do padrão. Como o filtro
if é melhor esforço, use o sistema de permissão em vez de um hook para impor um allow ou deny duro.
Campos de hook de comando
Além dos campos comuns, hooks de comando aceitam esses campos:Forma exec e forma shell
Um hook de comando executa como forma exec quandoargs é definido, e forma shell quando args é omitido. Defina args sempre que o hook referenciar um placeholder de caminho, já que cada elemento é passado como um argumento sem aspas. Omita args quando você precisar de recursos de shell como pipes ou &&, ou quando nenhuma preocupação se aplica.
Forma exec executa quando args está presente. Claude Code resolve command como um executável em PATH e o gera diretamente com args como o vetor de argumentos. Não há shell, então cada elemento args é um argumento exatamente como escrito, e placeholders de caminho como ${CLAUDE_PLUGIN_ROOT} são substituídos em command e em cada elemento args como strings simples. Caracteres especiais como apóstrofos, $ e backticks passam verbatim porque não há shell para interpretá-los. Nenhuma tokenização de shell acontece em nenhuma plataforma.
Forma shell executa quando args está ausente. A string command é passada para um shell: sh -c em macOS e Linux, Git Bash no Windows, ou PowerShell quando Git Bash não está instalado. Defina o campo shell para escolher explicitamente. O shell tokeniza a string, expande variáveis e interpreta pipes, &&, redirecionamentos e globs.
No Windows, a forma exec requer que
command seja resolvido para um executável real como .exe. Os shims .cmd e .bat que npm, npx, eslint e outras ferramentas instalam em node_modules/.bin não são executáveis e não podem ser gerados sem um shell. Para executá-los em forma exec, invoque o script subjacente com node diretamente, por exemplo "command": "node", "args": ["${CLAUDE_PLUGIN_ROOT}/node_modules/eslint/bin/eslint.js"]. O padrão node mais caminho-de-script funciona em todas as plataformas porque node.exe é um binário real. Para executar um shim .cmd ou .bat por nome, use forma shell.CLAUDE_PROJECT_DIR, CLAUDE_PLUGIN_ROOT e CLAUDE_PLUGIN_DATA no processo gerado, então um script pode ler process.env.CLAUDE_PLUGIN_ROOT independentemente de como foi lançado.
Hooks de plugin adicionalmente substituem valores ${user_config.*}, apenas em forma exec: o valor é substituído em command e em cada elemento args como uma string simples, então nenhum shell o re-analisa.
Um hook de plugin em forma shell cujo command referencia ${user_config.*} falha com um erro em vez de executar. Para usar um valor de opção de um hook em forma shell, leia a variável de ambiente $CLAUDE_PLUGIN_OPTION_<KEY>, como $CLAUDE_PLUGIN_OPTION_WEBHOOK_URL para uma opção webhook_url, ou defina args para mudar o hook para forma exec. Antes de v2.1.207, comandos de hook de plugin em forma shell também substituíam ${user_config.*}.
Em forma exec,
command é apenas o nome ou caminho do executável. Se command é um nome simples sem separador de caminho e contém espaço em branco junto com args, Claude Code registra um aviso porque o spawn falhará: não há executável nomeado node script.js. Mova os tokens extras para args. Caminhos absolutos com espaços, como C:\Program Files\nodejs\node.exe, são um executável válido único e não disparam o aviso.Campos de hook HTTP
Além dos campos comuns, hooks HTTP aceitam esses campos:
Claude Code envia a entrada JSON do hook como corpo da solicitação POST com
Content-Type: application/json. O corpo da resposta usa o mesmo formato de saída JSON que hooks de comando.
O tratamento de erros difere dos hooks de comando; consulte Tratamento de resposta HTTP.
Este exemplo envia eventos PreToolUse para um serviço de validação local, autenticando com um token da variável de ambiente MY_TOKEN:
Campos de hook de ferramenta MCP
Além dos campos comuns, hooks de ferramenta MCP aceitam esses campos:
Este exemplo chama a ferramenta
security_scan no servidor MCP my_server após cada Write ou Edit, passando o caminho do arquivo editado:
Como o resultado da ferramenta é lido
Claude Code lê o conteúdo de texto da ferramenta da mesma forma que lê stdout de hook de comando, seguindo a regra de análise sob código de saída 0. Se a ferramenta retornarisError: true, o hook produz um erro não-bloqueador e a execução continua.
Se um erro de hook contiver uma destas mensagens, Claude Code não conseguiu ler a resposta da ferramenta, então o hook não deu nenhum veredito:
PreToolUse, Claude Code recusa a chamada de ferramenta que o hook estava verificando. Em outros eventos, como UserPromptSubmit, PostToolUse e Stop, o erro é não-bloqueador.
Se o erro continuar aparecendo, retorne menos dados da ferramenta ou altere o tool ou input do hook para que a resposta seja menor.
Quando o servidor ainda está se conectando
Em eventos onde um hook pode bloquear ou mudar o resultado, comoPreToolUse ou Stop, Claude Code aguarda um servidor em conexão antes de chamar a ferramenta, por no máximo MCP_TIMEOUT e dentro do timeout do próprio hook. Em eventos observacionais, como Notification ou SessionEnd, ele não aguarda.
Um servidor mostrando o status cached se conecta quando o hook chama sua ferramenta. Se o servidor não estiver conectado naquele ponto, o hook produz um erro não-bloqueador e a execução continua. O hook nunca inicia um fluxo OAuth, então autentique o servidor de /mcp primeiro.
Eventos que disparam antes dos servidores MCP estarem disponíveis
SessionStart no lançamento, incluindo com --continue ou --resume, e cada evento Setup disparam antes dos servidores MCP da sessão estarem disponíveis para hooks. Claude Code pula seus hooks mcp_tool sem chamar a ferramenta, e o log de debug registra mcp_tool hooks are not available for the 'SessionStart' hook event (no MCP client context), ou a mesma mensagem nomeando Setup. Quando SessionStart dispara novamente mais tarde na sessão, após /clear ou uma compactação, seus hooks mcp_tool executam. Para qualquer coisa que a sessão precise no lançamento, use um hook type: "command" em SessionStart em vez disso.
Campos de hook de prompt e agente
Além dos campos comuns, hooks de prompt e agente aceitam esses campos:Referenciar scripts por caminho
Use esses placeholders para referenciar scripts de hook relativos à raiz do projeto ou plugin, independentemente do diretório de trabalho quando o hook executa:${CLAUDE_PROJECT_DIR}: a raiz do projeto onde a sessão começou. Claude Code também define essa variável no ambiente de servidores MCP stdio e servidores LSP de plugin.${CLAUDE_PLUGIN_ROOT}: o diretório de instalação do plugin, para scripts agrupados com um plugin. Consulte variáveis de ambiente de plugin para saber como o caminho se comporta entre atualizações.${CLAUDE_PLUGIN_DATA}: o diretório de dados persistentes do plugin, para dependências e estado que devem sobreviver a atualizações de plugin.
Worktrees são diferentes. Se Claude entra em uma worktree durante a sessão, Claude Code mantém
${CLAUDE_PROJECT_DIR} onde estava e passa o caminho da worktree para seus hooks de uma forma diferente:${CLAUDE_PROJECT_DIR}fica no lugar: ainda aponta para a raiz do projeto onde a sessão começou, então um comando como${CLAUDE_PROJECT_DIR}/.claude/hooks/check-style.shainda executa o script no checkout principal.cwdsegue Claude: o campocwdna entrada JSON do hook é a raiz do worktree após Claude entrar em um worktree, e o novo diretório após Claude executarcd. Leia-o quando um hook precisa saber em qual diretório Claude está trabalhando.
${CLAUDE_PROJECT_DIR} aponta.- Scripts de projeto
- Scripts de plugin
Este exemplo usa
${CLAUDE_PROJECT_DIR} para executar um verificador de estilo do diretório .claude/hooks/ do projeto após qualquer chamada de ferramenta Write ou Edit:Hooks em skills e agentes
Além de arquivos de configurações e plugins, hooks podem ser definidos diretamente em skills e subagentes usando frontmatter, no mesmo formato de configuração que hooks baseados em configurações. Por quanto tempo Claude Code os mantém registrados depende do componente:- Hooks de subagente: Claude Code os executa apenas enquanto esse subagente está em execução e os remove quando termina. Claude Code converte um hook
Stopaqui paraSubagentStop, o evento que dispara quando um subagente completa. - Hooks de skill: Claude Code os registra quando você ou Claude invoca a skill e continua executando-os pelo resto da sessão, em turnos após o próprio turno da skill também. Para fazer Claude Code remover um hook após sua primeira execução bem-sucedida em vez disso, defina
once: truenele.
PreToolUse que executa um script de validação de segurança antes de cada comando Bash:
-p em uma pasta que você não confiou.
Hooks de frontmatter em um subagente de projeto executam apenas após você aceitar o diálogo de confiança de workspace para a pasta de onde o arquivo do agente veio. Uma sessão -p não conta como aceitá-lo. O que executa antes de você confiar em uma pasta compara isso com a regra de arquivo de configurações, e a página de subagentes lista quais escopos estão isentos.
Limites de hooks de skill
Quando os hooks de frontmatter de uma skill não disparam depois que você ou Claude invoca a skill, execute/hooks nessa sessão. Se ele os listar, consulte Hook não dispara. Se ele não listar nenhum deles, a skill pode estar sob um bloqueio exclusivo para plugins ou ter ultrapassado um limite de hooks, e executa sem nenhum de seus hooks de frontmatter. Verifique cada caso:
- Bloqueio exclusivo para plugins: o administrador da sua organização pode restringir hooks a plugins e configurações gerenciadas com a configuração gerenciada
strictPluginOnlyCustomization. Uma skill mantém seus hooks de frontmatter sob esse bloqueio apenas se for uma skill de plugin, uma skill incluída ou uma skill no diretório de configurações gerenciadas. Os hooks nos seus próprios arquivos de configurações também não executam.- Verificar: digite
/statusem uma sessão do Claude Code. Se a linhaSetting sourcesincluirEnterprise managed settings, pergunte ao seu administrador sestrictPluginOnlyCustomizationbloqueia hooks. - Corrigir: mova a skill para um plugin, porque skills de plugin mantêm seus hooks de frontmatter. Liste o plugin em um marketplace e depois instale-o a partir dele. Se Claude Code recusar o marketplace com
is blocked by enterprise policy, peça ao seu administrador para permitir esse marketplace.
- Verificar: digite
- Limite de hooks: no Claude Code v2.1.304 ou posterior, cada fonte de skills tem seu próprio limite por sessão. Seu projeto, sua pasta de skills pessoais e cada plugin contam como fontes separadas. As skills de uma fonte podem registrar no máximo 1.024 hooks. Os matchers desses hooks podem totalizar no máximo 16.384 caracteres. Um matcher com vários hooks sob ele conta uma vez para cada hook.
- Verificar: repita a sessão em que o hook não disparou, com o log de debug ativado:
- Inicie uma nova sessão a partir do seu shell com
claude --debug. Se você não inicia sessões a partir de um shell, digite/debugprimeiro na nova sessão. - Invoque as mesmas skills na mesma ordem, incluindo as que Claude invocou, porque ambos os totais se acumulam skill por skill. Peça ao Claude para invocar qualquer skill que você não possa digitar como comando.
- Procure
registers none of its hooksno log de debug. Uma linha contendo esse texto nomeia a skill que ultrapassou o limite.
- Inicie uma nova sessão a partir do seu shell com
- Corrigir: declare menos hooks ou matchers mais curtos nessa skill ou nas outras skills da mesma fonte e, em seguida, inicie uma nova sessão. Se essas skills não forem suas para editar, peça essa mudança ao autor delas. Até lá, inicie uma nova sessão e invoque a skill de que você precisa antes de qualquer outra skill da mesma fonte.
- Verificar: repita a sessão em que o hook não disparou, com o log de debug ativado:
O menu /hooks
Digite /hooks no Claude Code para abrir um navegador somente leitura para seus hooks configurados. A lista rotula cada hook com sua origem, como configurações de usuário, configurações de projeto, configurações locais, um plugin ou a sessão atual.
Selecione um hook para ver o texto completo do que ele executa e onde está definido, como o caminho do seu arquivo de configurações ou o nome do seu plugin.
Para navegar por todos os eventos de hook, incluindo aqueles sem hooks configurados, selecione All events no final da lista.
Desabilitar ou remover hooks
Para remover um hook definido em um arquivo de configurações, delete sua entrada desse arquivo. Para desabilitar temporariamente todos os hooks sem removê-los, defina"disableAllHooks": true em seu arquivo de configurações. Claude Code lê o valor deixado após precedência de configurações se aplicar, então um "disableAllHooks": false no .claude/settings.json de um projeto substitui um true em suas configurações de usuário. Para desabilitar hooks para uma execução qualquer que as configurações do projeto digam, passe --settings '{"disableAllHooks": true}', que tem precedência sobre configurações de projeto e local. Não há forma de desabilitar um hook individual mantendo-o na configuração.
A configuração disableAllHooks respeita a hierarquia de configurações gerenciadas. Se um administrador configurou hooks através de configurações de política gerenciada, disableAllHooks definido em configurações de usuário, projeto ou local não pode desabilitar esses hooks gerenciados. Apenas disableAllHooks definido no nível de configurações gerenciadas pode desabilitar hooks gerenciados. Para o alcance completo de cada nível, consulte disableAllHooks.
Edições diretas a hooks em arquivos de configurações são normalmente capturadas automaticamente pelo observador de arquivo.
Entrada e saída de hook
Hooks de comando recebem dados JSON via stdin e comunicam resultados através de códigos de saída, stdout e stderr. Hooks HTTP recebem o mesmo JSON como corpo da requisição POST e comunicam resultados através do corpo da resposta HTTP. Esta seção cobre campos e comportamento comuns a todos os eventos. Cada seção de evento sob Eventos de hook inclui seu esquema de entrada específico e opções de controle de decisão. No macOS e Linux, hooks de comando executam em sua própria sessão sem um terminal controlador. O processo de hook e qualquer processo filho não podem abrir/dev/tty ou enviar sequências de escape diretamente para a interface do Claude Code. Windows não tem /dev/tty.
Para exibir uma mensagem ao usuário em qualquer plataforma, retorne systemMessage na saída JSON. Alguns eventos descartam isso ou o entregam em outro lugar, e cada seção de evento diz assim. Para disparar uma notificação de desktop, definir um título de janela ou tocar o sino, retorne terminalSequence em vez disso.
Campos de entrada comuns
Eventos de hook recebem esses campos como JSON, além de campos específicos do evento documentados em cada seção evento de hook. Para hooks de comando, este JSON chega via stdin. Para hooks HTTP, chega como corpo da requisição POST.agent_id e agent_type dizem ao seu script em qual agente um hook disparou, como um subagente, um colega de equipe em processo ou o agente que você escolheu com --agent:
Apenas hooks
SessionStart podem receber um campo model, e Claude Code nem sempre o inclui. Hooks PreModelSwitch e PostModelSwitch recebem from_model e to_model em vez disso, portanto use um hook PostModelSwitch para acompanhar o modelo conforme ele muda durante uma sessão.
Não há variável de ambiente $CLAUDE_MODEL. O hook pode ler $ANTHROPIC_MODEL se você defini-lo em seu shell, mas esse valor não muda quando você alterna modelos com /model durante uma sessão.
Um processo de hook herda o ambiente pai, exceto pelas variáveis exportadoras OTEL_* que Claude Code remove de cada subprocesso que spawna e, quando CLAUDE_CODE_SUBPROCESS_ENV_SCRUB é definido como 1, pelas variáveis que ele remove. Em uma sessão que recebe a configuração HIPAA, Claude Code também remove as credenciais da Anthropic do ambiente do hook.
Por exemplo, um hook PreToolUse para um comando Bash recebe isso em stdin:
tool_name, tool_input e tool_use_id são específicos do evento. Cada seção evento de hook documenta os campos adicionais para esse evento.
Saída de código de saída
Quando a execução do seu hook termina, Claude Code usa o código de saída dele para decidir se continua com a ação que o disparou, como uma chamada de ferramenta ou um prompt:- Sucesso: seu hook sai com 0. Claude Code aplica quaisquer campos de saída JSON que seu hook imprimiu, e a ação prossegue, a menos que esses campos a bloqueiem ou neguem. Hooks que iniciam um processo em segundo plano cobre a exceção.
- Erro bloqueador: seu hook sai com 2. Em eventos que podem bloquear, Claude Code interrompe a ação.
- Erro não-bloqueador: seu hook sai com qualquer outro código, ou falha de alguma outra forma, como não iniciar ou imprimir JSON inválido. A ação prossegue, exceto para hooks cuja falha bloqueia a ação, por exemplo um hook com
onFailuredefinido como"block". Em eventos comoPreToolUse, você vê um aviso<hook name> hook errorna transcrição.
PreToolUse sai com 1 mas imprime JSON que passa na validação, esse JSON ainda pode decidir o que acontece. Para encontrar o resultado do seu hook em um evento como PreToolUse, combine o que ele imprimiu em stdout na primeira coluna com seu código de saída no topo:
Alguns eventos têm suas próprias regras:
WorktreeCreate: qualquer código de saída diferente de zero faz a criação de worktree falhar, não importa o que seu JSON diga.WorktreeRemove: qualquer código de saída diferente de zero faz a remoção de worktree falhar se o diretório ainda existir depois.Stop,SubagentStop,TaskCompletede o hookUserPromptSubmitde um plugin: quando seu hook sai com 2 sem nada em stdout e seu stderr diz que um arquivo está ausente, comoNo such file or directory, Claude Code trata a execução como um erro não-bloqueador.ElicitationeElicitationResult: Claude Code aplica seuhookSpecificOutputquando seu hook sai com 0, e o ignora em qualquer outro código de saída.- Eventos que descartam a saída do hook, como
StopFailure: Claude Code ignora seu JSON em qualquer código de saída, exceto campos de efeito colateral comoterminalSequence, que ainda disparam.
Código de saída 0
Saída 0 significa sucesso, e é o código de saída pretendido quando você imprime JSON para controle estruturado. Quando seu hook sai com 0 mas imprime JSON que não pode ser analisado ou falha na validação de esquema, a ação prossegue, a menos que o hook seja um cuja falha bloqueia a ação. Em vez de um sucesso com seus campos aplicados, a execução é um erro não-bloqueador. Para corrigir sua saída, use a mensagem de análise ou validação que o aviso<hook name> hook error carrega. Para um hook que não é async, seu stdout conta como saída JSON apenas quando você imprime um único objeto JSON, em uma linha ou em várias, sem nada ao redor além de espaço em branco. Claude Code lê qualquer outro stdout como texto simples ou uma falha de análise:
- Saída que não começa com
{, ou que começa com{e não termina com}: texto simples. Um array JSON e uma string JSON entre aspas são texto simples por esta regra. - Duas ou mais linhas que cada uma analisa como JSON por conta própria, a primeira começando com
{e a última terminando com}: texto simples quando nenhuma linha é um objeto de saída JSON que define um campo. Quando uma linha é, a saída é uma falha de análise, portanto imprima esse objeto sem mais nada em stdout. - Qualquer outra coisa que começa com
{e termina com}mas não é JSON válido: uma falha de análise.
UserPromptSubmit,UserPromptExpansion,SessionStartePostModelSwitch: Claude Code adiciona stdout em texto simples como contexto que Claude pode ver e agir. Ele não adiciona stdout que não conseguiu analisar.PreCompact: seu stdout se torna instruções para o resumo de compactação
PreToolUse, ative debug logging. Para exibir um aviso para Claude de um hook PostToolUse ou PostToolUseFailure, saia com 2 em vez disso para que Claude veja o stderr mesmo que a ferramenta já tenha executado.
Código de saída 2
Saia com código 2 para bloquear a ação. Em eventos que podem bloquear, Claude Code interrompe a ação: um hookPreToolUse bloqueia a chamada de ferramenta, por exemplo, e um hook UserPromptSubmit rejeita o prompt.
A mensagem que acompanha o bloqueio é o stderr do seu hook. Se seu hook também imprimiu JSON que toma uma decisão de bloqueio, Claude Code usa a razão dessa decisão em vez disso.
A saída 2 bloqueia mesmo quando seu hook imprime JSON:
- JSON que passa na validação de esquema: Claude Code ainda lê os campos de saída JSON, mas eles não podem sobrescrever o bloqueio. Nem mesmo um
permissionDecisionde"allow"deixa a ação passar. EmElicitationeElicitationResult, ohookSpecificOutputde um hook exit-2 é ignorado. - JSON que falha na validação de esquema: o hook ainda bloqueia. Claude Code usa seu stderr como a razão de bloqueio e registra a falha de validação no log de debug.
rm saindo 2 e deixa cada outro comando para o fluxo de permissão normal:
PreToolUse em Bash, um comando que começa com rm é bloqueado, e Claude recebe o stderr do hook como o erro da ferramenta, prefixado com o nome do evento, o nome da ferramenta e o comando do hook:
Outros códigos de saída
Um aviso<hook name> hook error com Failed with non-blocking status code: significa que o código de saída do seu hook não foi 0 nem 2 e seu stdout era texto simples ou estava vazio. A menos que o hook seja um cuja falha bloqueia a ação, isso é um erro não-bloqueador, portanto seu hook não interrompeu a ação. Para capturar o stderr completo do seu hook em vez da primeira linha que o aviso mostra, ative debug logging.
Por exemplo, quando um hook PreToolUse em Bash imprime something broke em stderr e sai com 1, o aviso PreToolUse:Bash hook error carrega esta linha:
No such file or directory do shell, como na linha a seguir, o hook nunca foi executado, por exemplo porque o caminho do script não existe:
settings.json significa que o hook nunca executa. Para bloquear a ação quando o hook não consegue iniciar, defina onFailure: "block".
Timeouts
Exceto por um hook de comando que você executa comasync: true, Claude Code cancela um hook command, http ou mcp_tool que atinge seu timeout, descartando a saída do hook, portanto na maioria dos eventos um hook expirado não renderiza decisão. Em PreModelSwitch, um hook cancelado em seu timeout bloqueia a mudança de modelo.
Em PreToolUse, um hook command, http ou mcp_tool expirado não bloqueia a chamada da ferramenta, exceto para hooks cuja falha bloqueia a ação. A chamada continua através do fluxo de permissão normal, portanto não conte com um hook travado para agir como um portão. Para bloquear a chamada quando um hook command ou http atinge o timeout, defina onFailure: "block". Um hook de callback do Agent SDK que excede seu timeout bloqueia a chamada da ferramenta.
Se você usa o Code Mode, os timeouts em
PreToolUse funcionam de forma diferente. Consulte Chamada de ferramenta recusada por um hook.Hooks que iniciam um processo em segundo plano
Um hook pode iniciar um programa de longa duração, como um servidor de desenvolvimento, e deixá-lo em execução enquanto a sessão continua. No script do hook ou no comando em forma shell:- Execute o programa em segundo plano
- Redirecione o stdout e o stderr dele. Por exemplo, o comando Bash
npm run dev > dev-server.log 2>&1 &envia ambos para um arquivo. Se você não os redirecionar, um hook que não é async leva até 10 segundos para terminar depois que o próprio processo do hook sai.
stdio went quiet e refusing to honor the suspect capture.
Este script de hook PreToolUse imprime a decisão com policy-check.sh e depois envia métricas em segundo plano:
|| exit $?: torna o código de saída da verificação o código do próprio hook, para que uma verificação que sai com 2 para negar ainda bloqueie. Caso contrário, o hook sai com o código da última linha, que é 0.>/dev/null 2>&1 &: executaupload-metrics.shem segundo plano com sua saída redirecionada, para que ele não mantenha a saída do hook aberta.
policy-check.sh sair com 2 e então dispare uma chamada de ferramenta correspondida pelo hook. A chamada de ferramenta é bloqueada.
Bloquear a ação quando um hook falha
Na maioria dos eventos, quando um hook falha ou atinge o timeout, Claude Code ainda executa a ação. Um hook de política com um caminho errado ou um script que trava então deixa tudo passar. Para bloquear a ação em vez disso, defina"onFailure": "block" em um hook command ou http. Requer Claude Code v2.1.295 ou posterior. Para hooks de callback do Agent SDK, consulte Bloquear a ação quando um callback falha.
No Windows sem Git Bash, um hook de comando
PreToolUse ou PermissionRequest em forma shell que falha com onFailure não definido pode, em vez disso, bloquear a chamada de ferramenta.PreToolUse em .claude/settings.json executa um script do projeto antes de cada comando Bash, e bloqueia o comando se o script falhar:
check-command.js ausente e peça a Claude para executar um comando Bash como ls. Claude Code bloqueia a chamada, e o erro inclui failed; blocking because onFailure is "block" seguido pela própria saída de erro do node, reduzida aqui a uma linha:
timed out em vez de failed. Sem onFailure definido, o mesmo script ausente é um erro não-bloqueador e ls é executado.
Cada um destes conta como uma falha:
- Não consegue iniciar: um hook de comando falha ao iniciar, por exemplo porque o script ou executável não existe
- Código de saída diferente de 0 ou 2: conta para um hook de comando mesmo que ele tenha impresso JSON que permite a ação, como
permissionDecision: "allow". Para retornar uma decisão JSON, saia com 0 - Erro HTTP: a conexão de um hook HTTP falha, ou o status da resposta não é 2xx
- Timeout: o hook atinge seu
timeout - Saída inválida: a saída JSON não pode ser analisada ou falha na validação de esquema. Para um hook HTTP, um corpo 2xx que não é vazio nem um objeto JSON também conta. Stdout em texto simples de um hook de comando não é uma falha
"block" definido, uma falha faz o que o código de saída 2 faz nesse evento, exceto em PermissionRequest, onde ela nega a solicitação. Por exemplo, uma falha em PreToolUse bloqueia a chamada de ferramenta e uma falha em UserPromptSubmit bloqueia o prompt.
O campo não tem efeito nestes hooks:
- Hooks
Stop,SubagentStop,TaskCompletedeTeammateIdle: o código de saída 2 nesses eventos manda Claude de volta para continuar trabalhando, e Claude não consegue reparar um hook que não executa - Hooks de comando em segundo plano: hooks de comando que definem
asyncouasyncRewake
Se você usa o Code Mode, as falhas em
PreToolUse funcionam de forma diferente. Consulte Chamada de ferramenta recusada por um hook.Hooks com falha no Windows sem Git Bash
Se o erro de uma chamada de ferramenta bloqueada incluir este texto, um hook de comandoPreToolUse ou PermissionRequest falhou ou atingiu o timeout e bloqueou a chamada:
PowerShell started no program, comece pelas correções para um command composto apenas de strings entre aspas, que o PowerShell imprime em vez de executar.
Sem Git Bash, qualquer código de saída diferente de 0 ou 2 desse hook conta como uma falha, mesmo quando ele imprime JSON que não nega a chamada. Para descobrir por que o hook falhou, verifique o log de debug. Então escolha a correção que corresponde ao seu hook:
- A chamada deve prosseguir quando o hook falha: adicione
"onFailure": "continue"ao hook - O hook sai com 1 para avisar, mas deve bloquear quando trava: com
"onFailure": "continue", a chamada prossegue com o código de saída 1, seja um aviso ou uma falha. Adicione"onFailure": "block"em vez disso, e faça o script sair com 0 onde ele avisa, para que essas chamadas prossigam. Para ainda mostrar o aviso emPreToolUse, imprima-o em stdout no camposystemMessagede um único objeto JSON. - O hook é escrito para Bash: sem Git Bash, um hook em forma shell sem
shelldefinido é executado no PowerShell, onde pode falhar. Instale o Git for Windows, ou definaCLAUDE_CODE_GIT_BASH_PATHse o Git Bash estiver instalado em um local onde o Claude Code não o encontra. Então inicie uma nova sessão. - O hook executa um único
.exe, não um arquivo.cmdou.bat: coloque o programa emcommande seus argumentos emargspara usar a forma exec, e adicione"onFailure": "block". Claude Code então inicia o programa sem shell. Sem"onFailure": "block", a chamada pode prosseguir quando o programa falha, está ausente ou atinge o timeout - Um hook de proteção em PowerShell que deve bloquear em caso de falha: com
onFailurenão definido, ele deixa de fazer isso assim que o Git for Windows é instalado e o Claude Code encontra o Git Bash. Adicione"onFailure": "block"para que uma falha ou um timeout bloqueie a chamada com ou sem Git Bash. Defina também"shell": "powershell"para que o hook continue sendo executado no PowerShell a partir de então, em vez de no Git Bash
blocking because Git Bash wasn't found and this hook doesn't set "shell" to "powershell", so only exit code 0 or 2 counts as its verdict.
PowerShell started no program
Um hook com este erro foi executado no PowerShell, que imprime umcommand composto apenas de strings entre aspas, como "command": "\"C:\\Tools\\guard.exe\"", em vez de executá-lo.
- Para imprimir texto, como JSON: defina
"shell": "powershell", e o hook sai com 0 - Para executar um arquivo
.ps1,.cmdou.bat, ou um.execujo caminho contém uma variável: defina"shell": "powershell"e coloque&antes do caminho entre aspas. Deixe$HOMEcomo está escrito, e escreva variáveis de ambiente da mesma forma que o exemplocheck.ps1escreve$env:CLAUDE_PROJECT_DIR - Para executar um único
.exeem um caminho sem$: remova as aspas internas decommande então aplique a correção para um hook que executa um único.exe, escrevendo"args": []se o programa não receber argumentos - Para executar um script escrito para Bash: aplique a correção para um hook escrito para Bash
Comportamento de código de saída 2 por evento
Código de saída 2 é a forma de um hook sinalizar “pare, não faça isso”. O efeito depende do evento, porque alguns eventos representam ações que podem ser bloqueadas (como uma chamada de ferramenta que ainda não aconteceu) e outros representam coisas que já aconteceram ou não podem ser prevenidas.
Para
SessionStart, SubagentStart e PostModelSwitch, Claude Code renderiza o stderr de código de saída 2 na transcrição como um aviso <hook name> hook error, da mesma forma que renderiza um erro não-bloqueador. Claude não vê, e a sessão ou subagente prossegue. Para SubagentStart, o aviso aparece na própria transcrição do subagente, não na conversa pai.
Tratamento de resposta HTTP
Hooks HTTP usam códigos de status HTTP e corpos de resposta em vez de códigos de saída e stdout. Para bloquear a ação quando a requisição falha ou retorna um status não-2xx, definaonFailure: "block". Para bloquear uma chamada de ferramenta ou negar uma permissão, retorne uma resposta 2xx com um corpo JSON contendo os campos de decisão apropriados.
Após um erro não-bloqueador, a ação prossegue, a menos que o hook seja um cuja falha bloqueia a ação. Exceto em eventos com seu próprio contrato de falha na tabela por evento, como WorktreeCreate, você obtém estes resultados para cada resposta ou falha:
- 2xx com corpo vazio: sucesso, equivalente a código de saída 0 sem saída
- 2xx com corpo de objeto JSON: analisado usando o mesmo esquema saída JSON que hooks de comando. Um corpo que falha na validação de esquema é um erro não-bloqueador
- 2xx com qualquer outro corpo, como texto simples: erro não-bloqueador, tratado da mesma forma que um status não-2xx. Claude Code não adiciona o texto ao contexto de Claude
- Status não-2xx: erro não-bloqueador
- Falha de conexão: erro não-bloqueador
- Timeout: o hook é cancelado, conforme descrito em Timeouts
Saída JSON
Códigos de saída permitem você bloquear ou ficar em silêncio, mas saída JSON oferece controle mais granular. Em vez de sair com código 2 para bloquear, saia 0 e imprima um objeto JSON em stdout. Claude Code lê campos específicos desse JSON para controlar comportamento, incluindo controle de decisão para bloquear, permitir ou escalar para o usuário.Escolha uma abordagem por hook: ou use códigos de saída sozinhos para sinalizar, ou saia 0 e imprima JSON para controle estruturado. Se você misturar, saída 2 mantém seu efeito de bloqueio, e Claude Code ainda lê os campos JSON, com a exceção de elicitação única anotada em Código de saída 2.
additionalContext, systemMessage e initialUserMessage, e seu stdout simples, são limitadas a 10.000 caracteres:
- Escopo: Claude Code mede cada string por conta própria, mesmo quando vários hooks executam para o mesmo evento. Para saída JSON, cada campo é medido separadamente; stdout simples é medido como um todo.
- Acima do limite: exceto para o stdout de PreCompact, Claude Code salva a saída em um arquivo no diretório de sessão. Ele substitui a saída pelo caminho do arquivo e uma visualização de até os primeiros 2.000 caracteres. Um resultado Bash grande válido é tratado da mesma forma, descrito em Limites de saída. Diferentemente desse teto Bash, este limite não tem configuração ou variável de ambiente para aumentá-lo.
- Lendo o arquivo: Claude Code não pede a Claude para ler o arquivo, portanto mantenha qualquer coisa que Claude sempre deva ver dentro do limite.
- Campos universais como
continuesão listados na tabela abaixo. Cada evento os aceita, mas alguns eventos os descartam ou entregamsystemMessageem outro lugar que não a transcrição. Cada seção de evento diz assim.terminalSequencefunciona nesses eventos também, com as exceções listadas em Emitir notificações de terminal. decisionereasonde nível superior são usados por alguns eventos para bloquear ou fornecer feedback.hookSpecificOutputé um objeto aninhado para eventos que precisam de controle mais rico. Requer um campohookEventNamedefinido para o nome do evento.
Para parar Claude inteiramente:
PreToolUse e PostToolUse, a parada se aplica mesmo quando a chamada da ferramenta falha ou é concluída enquanto Claude ainda está transmitindo uma resposta.
Emitir notificações de terminal
Hooks executam sem um terminal controlador, portanto escrever sequências de escape diretamente para/dev/tty falha. Em vez disso, retorne a sequência de escape no campo terminalSequence e Claude Code a emite para você através de seu próprio caminho de escrita de terminal. Isso é livre de corrida e funciona no Windows onde não há /dev/tty.
O campo aceita uma string de uma ou mais sequências de escape da allowlist:
- OSC
0,1,2: títulos de janela e ícone - OSC
9: notificações iTerm2, ConEmu, Windows Terminal e WezTerm, incluindo progresso de barra de tarefas9;4 - OSC
99: notificações Kitty - OSC
777: notificações urxvt, Ghostty e Warp - BEL simples
systemMessage e continue, como Notification e StopFailure. Tem alguns limites:
- Claude Code escreve a sequência apenas em uma sessão interativa, e apenas enquanto sua interface está aberta. Em modo não interativo com a flag
-pe no Agent SDK, ignora o campo. - O campo funciona apenas a partir de um hook que não é executado em segundo plano, portanto deixe
asynceasyncRewakedesativados. - Um hook de comando
WorktreeCreatenão pode retornar JSON, porque Claude Code lê seu stdout como o caminho de worktree. Um hook HTTPWorktreeCreateretorna JSON e pode incluir o campo.
Notification em um terminal que lê OSC 777, como Ghostty ou Warp. A chamada jq -nc --arg do script constrói a saída JSON e escapa quaisquer aspas, barras invertidas e quebras de linha na mensagem de notificação:
{ "terminalSequence": "..." } é a mesma de qualquer shell ou linguagem.
Receber notificações de terminal dentro de tmux ou GNU screen
Quando Claude Code é executado dentro de tmux ou GNU screen, as sequências OSC precisam do seguinte para chegar ao seu aplicativo de terminal:- tmux 3.3 ou posterior: adicione
set -g allow-passthrough ona~/.tmux.confe então executetmux source-file ~/.tmux.confa partir de um shell. A opção se aplica a todos os programas nesses painéis, não apenas ao Claude Code. Comon, apenas os painéis que o tmux está mostrando podem enviá-las. Para permitir que outros painéis em uma sessão à qual você está conectado também as enviem, useallno lugar deon, no tmux 3.4 ou posterior. - GNU screen: mantenha a janela do Claude Code visível no screen, porque sequências de uma janela em segundo plano não chegam ao seu aplicativo de terminal
Adicionar contexto para Claude
O campoadditionalContext passa uma string do seu hook para a janela de contexto do Claude. Claude Code envolve a string em um lembrete do sistema e a insere na conversa no ponto onde o hook disparou. Claude lê o lembrete na próxima requisição ao modelo, mas não aparece como uma mensagem de chat na interface.
Retorne additionalContext dentro de hookSpecificOutput ao lado do nome do evento:
- SessionStart e SubagentStart: no início da conversa, antes do primeiro prompt
- UserPromptSubmit e UserPromptExpansion: ao lado do prompt enviado
- PreToolUse, PostToolUse, PostToolUseFailure e PostToolBatch: ao lado do resultado da ferramenta
- Stop e SubagentStop: no final do turno. A conversa continua para que Claude possa agir sobre o feedback. Consulte Controle de decisão Stop
- PostModelSwitch: com a próxima requisição após a mudança. Consulte Controle de decisão PostModelSwitch para timing
additionalContext para o mesmo evento, Claude recebe todos os valores.
Se sua string contiver uma tag <system-reminder> ou </system-reminder>, Claude recebe a string com o < dessa tag substituído por <.
Se um valor exceder 10.000 caracteres, Claude Code escreve o texto em um arquivo no diretório de sessão e passa Claude o caminho do arquivo com uma visualização de até os primeiros 2.000 caracteres em vez disso. Claude pode ler o arquivo, mas Claude Code não pede a Claude para.
Use additionalContext para informações que Claude deve saber sobre o estado atual do seu ambiente ou a operação que acabou de executar:
- Estado do ambiente: o branch atual, alvo de implantação ou sinalizadores de recurso ativos
- Regras de projeto condicional: qual comando de teste se aplica ao arquivo que acabou de ser editado, quais diretórios são somente leitura neste worktree
- Dados externos: problemas abertos atribuídos a você, resultados recentes de CI, conteúdo obtido de um serviço interno
bun test” lê como informação de projeto. Texto enquadrado como comandos de sistema fora de banda pode disparar as defesas de injeção de prompt do Claude, o que faz com que Claude superficialize o texto para você em vez de tratá-lo como contexto.
Claude Code salva o texto injetado na transcrição de sessão. Para eventos de mid-sessão como PostToolUse ou UserPromptSubmit, quando você retoma com --continue ou --resume, Claude Code reproduz o texto salvo em vez de re-executar o hook para turnos anteriores, portanto valores como timestamps ou SHAs de commit ficam obsoletos. Hooks SessionStart executam novamente na retomada com source definido como "resume", ou "fork" se você adicionou --fork-session, para que possam atualizar seu contexto.
Controle de decisão
Nem todo evento suporta bloqueio ou controle de comportamento através de JSON. Os eventos que fazem cada um usam um conjunto diferente de campos para expressar essa decisão. Use esta tabela como referência rápida antes de escrever um hook:
Alguns eventos também podem reescrever conteúdo em vez de apenas permitir ou bloquear:
PreToolUse:updatedInputdiretamente sobhookSpecificOutputsubstitui os argumentos de uma ferramenta antes de executar. Consulte Controle de decisão PreToolUsePermissionRequest:updatedInputdentro do objetodecision. Consulte Controle de decisão PermissionRequestPostToolUse:updatedToolOutputsubstitui o resultado da ferramenta. Em uma sessão na nuvem do Cowork, Claude Code ignoraupdatedToolOutputquando a ferramenta éAskUserQuestionouExitPlanMode, e Claude lê a resposta ou o plano original. Consulte Controle de decisão PostToolUseUserPromptSubmit: não pode substituir o prompt; apenas injetaadditionalContextao lado dele
PreToolUse para entradas de ferramenta de saída e PostToolUse para resultados de ferramenta de entrada.
Aqui estão exemplos de cada padrão em ação:
- Decisão de nível superior
- PreToolUse
- PermissionRequest
O único valor para
decision é "block". Para permitir que a ação prossiga, omita decision do seu JSON, ou saia 0 sem qualquer JSON:Eventos de hook
Cada evento corresponde a um ponto no ciclo de vida do Claude Code em que hooks podem ser executados. As seções abaixo estão ordenadas de acordo com o ciclo de vida: da configuração da sessão, passando pelo loop agêntico, até o fim da sessão. Cada seção descreve quando o evento é disparado, quais matchers ele suporta, a entrada JSON que recebe e como controlar o comportamento por meio da saída.SessionStart
É executado quando o Claude Code inicia uma nova sessão ou retoma uma sessão existente. Útil para carregar contexto de desenvolvimento, como issues existentes ou alterações recentes na sua base de código, ou para configurar variáveis de ambiente. Para contexto estático que não requer um script, use o CLAUDE.md. O SessionStart é executado em todas as sessões, portanto mantenha esses hooks rápidos. Somente hookstype: "command" e type: "mcp_tool" são suportados. Consulte Campos de hook de ferramenta MCP para saber quando hooks mcp_tool são executados.
O valor do matcher corresponde a como a sessão foi iniciada:
Quando você inicia uma sessão interativa, retoma uma conversa na inicialização com
--continue ou --resume, ou executa /clear, os hooks SessionStart são executados em segundo plano. Você pode digitar imediatamente, e uma conversa que você retomou aparece sem esperar pelos hooks. A primeira resposta do Claude ainda espera os hooks terminarem, para que o contexto deles chegue ao Claude.
Quando você troca de conversa com /resume dentro de uma sessão, a troca espera os hooks terminarem. Se você executar /clear ou trocar para outra conversa enquanto hooks em segundo plano ainda estiverem em execução, nada do que eles retornarem se aplica à sessão.
A mesma espera se aplica na inicialização, incluindo uma sessão retomada: um prompt que você envia enquanto os hooks SessionStart ainda estão em execução não chega ao Claude até que eles terminem.
Durante qualquer uma dessas esperas, pressione Esc para trazer o prompt de volta à entrada sem enviá-lo. Os hooks continuam em execução.
Entrada do SessionStart
Além dos campos de entrada comuns, os hooks SessionStart recebemsource e, opcionalmente, model, agent_type e session_title:
Uma sessão que você não nomeou ainda pode ter um título gerado. Esse título não é um título personalizado e não aparece em
session_title.
Quando source é "resume" ou "fork" e a transcrição contém pelo menos uma resposta do Claude, os hooks SessionStart também recebem os quatro campos abaixo. Seu hook pode usá-los para informar quanto custa retomar uma conversa antiga antes da primeira requisição, por exemplo em um systemMessage. Esses campos requerem o Claude Code v2.1.251 ou posterior.
Este exemplo mostra a entrada para uma sessão retomada 90 minutos após sua última resposta:
Controle de decisão do SessionStart
Um hook SessionStart pode adicionar contexto para o Claude, fornecer a primeira mensagem do usuário, definir o título da sessão, observar arquivos e recarregar skills. Retorne o campo correspondente a cada um, além dos campos de saída JSON disponíveis para todos os hooks:
Esta saída adiciona contexto e nomeia a sessão:
initialUserMessage ou sessionTitle, instale o plugin antes do início da sessão. O Claude Code ignora ambos os campos de um plugin cuja instalação termina depois que os hooks SessionStart foram executados.
Recarregar skills que um hook instala
Para disponibilizar na mesma sessão as skills que um hook SessionStart instala, retornereloadSkills. A descoberta de skills normalmente é executada antes de os hooks SessionStart terminarem; portanto, sem isso, arquivos que um hook grava em ~/.claude/skills/ ou .claude/skills/ podem estar ausentes quando o primeiro prompt for executado.
Este exemplo sincroniza um repositório compartilhado de skills e solicita a nova verificação:
Persistir variáveis de ambiente
Os hooks SessionStart têm acesso à variável de ambienteCLAUDE_ENV_FILE, que fornece um caminho de arquivo onde você pode persistir variáveis de ambiente para os comandos de shell que o Claude executa mais adiante na sessão.
Para definir variáveis de ambiente individuais, escreva instruções export em CLAUDE_ENV_FILE. Use anexação (>>) para preservar variáveis definidas por outros hooks:
$PATH em export PATH="$PATH:./node_modules/.bin".
Variáveis persistidas em comandos PowerShell
Comandos PowerShell também recebem as variáveis deCLAUDE_ENV_FILE, no Claude Code v2.1.296 ou posterior, mas o PowerShell nunca executa o arquivo. Em vez disso, o Claude Code lê as atribuições do arquivo e as copia para o ambiente do comando PowerShell. Ele faz isso somente quando cada linha é de um dos tipos a seguir, considerando tudo o que cada hook nesta sessão gravou e qualquer script para o qual você definiu CLAUDE_ENV_FILE antes da inicialização:
- Uma linha em branco ou um comentário
# - Uma atribuição no início da linha, escrita como
export NAME=value,declare -x NAME=valueouNAME=value, com um valor que o Bash usaria exatamente como escrito, composto por qualquer combinação destas partes: texto sem aspas que use apenas letras, dígitos e os caracteres_ @ % + = : , . / -, texto entre aspas simples e texto entre aspas duplas em que qualquer$, acento grave ou"interno esteja escapado com uma barra invertida
export PATH="$PATH:./node_modules/.bin" com seu $PATH sem escape, um comando source ou as strings $'...' que direnv export bash imprime, os comandos PowerShell não recebem nenhuma das variáveis, e claude --debug registra Session environment is not all plain assignments. Os comandos Bash ainda recebem todas elas. No Windows, os comandos PowerShell também não recebem uma variável cujo valor contenha / ou \, porque o Git Bash e o Windows escrevem caminhos de forma diferente. Um comando PowerShell em sandbox não recebe nenhuma das variáveis.
CLAUDE_ENV_FILE está disponível para hooks SessionStart, Setup, CwdChanged e FileChanged. Outros eventos de hook não têm acesso a essa variável, nem um hook executado no PowerShell, seja por meio de "shell": "powershell" ou por padrão no Windows sem Git Bash.Setup
É disparado somente quando você inicia o Claude Code com--init-only, ou com --init ou --maintenance no modo não interativo com a flag -p. Ele não é disparado na inicialização normal. Use-o para instalação única de dependências ou limpeza agendada que você aciona explicitamente a partir de CI ou scripts, separadamente da inicialização normal da sessão. Para inicialização por sessão, use o SessionStart.
O valor do matcher corresponde à flag da CLI que acionou o hook:
Quando você executa
claude --init-only, o Claude Code executa os hooks Setup e os hooks SessionStart com o matcher startup e, em seguida, sai sem iniciar uma conversa.
Quando você inicia ou continua uma conversa com -p, também precisa fornecer um prompt, como argumento ou via stdin. Você pode omitir o prompt quando um hook SessionStart fornece initialUserMessage ou quando você retoma uma sessão com uma chamada de ferramenta adiada.
Em caso de sucesso, --init-only não imprime nada no terminal. Para confirmar que os hooks foram executados, inicie com claude --debug-file <path> --init-only, substituindo <path> por um local de arquivo de log, e verifique no log as entradas dos hooks Setup e SessionStart.
Como o Setup não é disparado em toda inicialização, um plugin que precisa de uma dependência instalada não pode depender apenas do Setup. O padrão prático é verificar a dependência no primeiro uso e instalá-la caso esteja ausente, por exemplo, um hook ou skill que testa ${CLAUDE_PLUGIN_DATA}/node_modules e executa npm install se não existir. Consulte o diretório de dados persistentes para saber onde armazenar as dependências instaladas. Se você distribui seu plugin por meio de um marketplace, talvez não precise desse padrão: o Claude Code instala automaticamente as dependências de pacotes Node.js elegíveis quando armazena o plugin em cache.
Entrada do Setup
Além dos campos de entrada comuns, os hooks Setup recebem um campotrigger definido como "init" ou "maintenance":
Controle de decisão do Setup
Os hooks Setup não podem bloquear; a execução continua com qualquer código de saída. Em todos os códigos de saída, o Claude Code descarta os campos de saída JSON de um hook Setup, comosystemMessage, continue e hookSpecificOutput.additionalContext. Com -p, o stdout, o stderr e o código de saída de um hook Setup aparecem na saída da execução somente como eventos hook_response quando você inicia com --output-format stream-json --verbose.
Os hooks Setup têm acesso a CLAUDE_ENV_FILE. Se o seu hook gravar variáveis nesse arquivo, elas persistem nos comandos Bash subsequentes da sessão, como nos hooks SessionStart. Somente hooks type: "command" são executados no Setup. Um hook type: "mcp_tool" no Setup é sempre ignorado, conforme descrito em Campos de hook de ferramenta MCP.
InstructionsLoaded
É disparado quando um arquivoCLAUDE.md ou .claude/rules/*.md é carregado no contexto. Esse evento é disparado no início da sessão para arquivos carregados antecipadamente e novamente mais tarde quando arquivos são carregados sob demanda, por exemplo, quando o Claude acessa um subdiretório que contém um CLAUDE.md aninhado ou quando regras condicionais com frontmatter paths: correspondem. O hook não suporta bloqueio nem controle de decisão. Ele é executado de forma assíncrona para fins de observabilidade.
Esse evento não é disparado quando o Claude lê o AGENTS.md diretamente por meio da configuração Project instructions. Ele é disparado quando um CLAUDE.md importa seu AGENTS.md, com load_reason definido como include como para qualquer outro arquivo importado, e quando o CLAUDE.md é um link simbólico para ele, como um carregamento normal de CLAUDE.md.
O matcher é aplicado a load_reason. Por exemplo, use "matcher": "session_start" para disparar somente para arquivos carregados no início da sessão, ou "matcher": "path_glob_match|nested_traversal" para disparar somente para carregamentos sob demanda.
Entrada do InstructionsLoaded
Além dos campos de entrada comuns, os hooks InstructionsLoaded recebem estes campos:Controle de decisão do InstructionsLoaded
Os hooks InstructionsLoaded não têm controle de decisão. Eles não podem bloquear nem modificar o carregamento de instruções. O Claude Code descarta seus campos de saída JSON, comosystemMessage e continue. Use esse evento para logs de auditoria, rastreamento de conformidade ou observabilidade.
UserPromptSubmit
É executado quando um prompt é enviado, antes que o Claude o processe. Isso permite adicionar contexto extra com base no prompt/conversa, validar prompts ou bloquear certos tipos de prompts. Os hooksUserPromptSubmit não são disparados apenas em prompts que você digita. O Claude Code também os executa quando:
- Uma tarefa agendada com escopo de sessão é disparada, incluindo uma iteração de
/loop - Um subagente em segundo plano reporta de volta à sessão que o iniciou
- Uma mensagem que outra sessão envia chega à sua conversa principal
- A saída do código do Claude em uma sessão de Code Mode, para hooks
command,httpemcp_tool, quando o código pode ser executado em segundo plano
UserPromptSubmit têm um timeout padrão de 30 segundos para os tipos command, http e mcp_tool, menor que o padrão de 600 segundos para esses tipos na maioria dos outros eventos. Como esse hook é executado antes de cada prompt e bloqueia o processamento do modelo até terminar, um hook travado paralisa a sessão. Se o seu hook precisar de mais tempo, defina o campo timeout na entrada do hook.
Exceto por um hook de comando que você executa com async: true, um hook de comando, HTTP ou de ferramenta MCP em UserPromptSubmit que atinge seu timeout é cancelado, e sua saída, incluindo qualquer additionalContext, é descartada. O prompt ainda chega ao Claude sem esse contexto. Para bloquear o prompt em vez disso, defina onFailure: "block" em um hook de comando ou HTTP. A transcrição mostra um aviso nomeando o hook, o timeout que foi atingido e que a saída foi descartada.
Um hook de callback do Agent SDK em UserPromptSubmit que atinge seu timeout bloqueia o prompt com uma mensagem indicando o hook e o timeout, porque um callback ali pode estar atuando como um controle de política que não deve falhar de forma permissiva. A sessão continua.
Esc durante uma verificação de prompt
Se você pressionar Esc ou interromper a sessão enquanto os hooks ainda estão verificando um prompt, a verificação para e o prompt não chega ao Claude. O texto que você digitou no terminal retorna à entrada do prompt, e os hooks o verificam novamente quando você o reenviar.
Um hook pode bloquear o prompt no mesmo momento em que você interrompe. O prompt então permanece bloqueado: você vê a mensagem de bloqueio desse hook, e o texto não retorna à entrada.
Entrada do UserPromptSubmit
Além dos campos de entrada comuns, os hooks UserPromptSubmit recebem o campoprompt contendo o texto enviado. Conteúdo colado que foi recolhido em um marcador [Pasted text #N] chega expandido no lugar. Em sessões em que o Claude Code marca texto colado para o Claude, esse conteúdo expandido fica entre uma linha <pasted_content id="…"> e uma linha </pasted_content id="…">, portanto leve essas linhas em conta se o seu hook analisar o prompt.
Os hooks UserPromptSubmit também recebem session_title quando a sessão tem um título personalizado, com o mesmo significado do campo session_title do SessionStart.
/deploy staging, o hook recebe essa linha como você a digitou, em vez do conteúdo expandido da skill. Se o hook bloquear o prompt, o comando não é executado, portanto os comandos de shell que a skill injeta com !`<command>` também não são executados. Para fazer a correspondência pelo nome ou pelos argumentos do comando, use UserPromptExpansion.
Controle de decisão do UserPromptSubmit
Os hooksUserPromptSubmit podem controlar se um prompt enviado é processado e adicionar contexto. Todos os campos de saída JSON estão disponíveis.
Há duas maneiras de adicionar contexto à conversa com o código de saída 0:
- Stdout em texto simples: o Claude Code adiciona ao contexto do Claude o stdout que ele trata como texto simples
- JSON com
additionalContext: use o formato JSON abaixo para ter mais controle. O campoadditionalContexté adicionado como contexto
additionalContext são injetados, cada um, como um lembrete do sistema que começa com o nome do hook; o Claude lê ambos. Para confirmar a entrega, verifique o log de depuração.
Para bloquear um prompt, retorne um objeto JSON com decision definido como "block":
Se o seu hook bloquear saindo com código 2, o texto do stderr é tratado da mesma forma que
reason.
O que um prompt bloqueado deixa para trás
Um prompt bloqueado nunca chega ao Claude, mas seu texto não é removido de todos os lugares. Por padrão, a mensagem de bloqueio mostrada ao usuário termina comOriginal prompt: seguido do texto enviado, e o Claude Code grava essa mensagem no arquivo de transcrição da sessão no disco. Para deixar o texto fora da mensagem, imprima JSON com "suppressOriginalPrompt": true dentro de hookSpecificOutput. Isso funciona tanto se o hook bloquear com decision: "block" quanto saindo com 2.
suppressOriginalPrompt altera apenas a mensagem de bloqueio. O texto enviado ainda pode aparecer em arquivos locais, como a transcrição da sessão e seu histórico de prompts, portanto um hook de bloqueio não é uma maneira de manter um segredo fora do disco. Para limitar ou remover esses arquivos, consulte Armazenamento em texto simples e Limpar dados locais.
UserPromptExpansion
É executado quando um comando digitado pelo usuário se expande em um prompt antes de chegar ao Claude. Use-o para impedir a invocação direta de comandos específicos, injetar contexto para uma skill específica ou registrar quais comandos os usuários invocam. Por exemplo, um hook que corresponde adeploy pode bloquear /deploy a menos que um arquivo de aprovação esteja presente, ou um hook que corresponde a uma skill de revisão pode anexar a checklist de revisão da equipe como additionalContext.
Esse evento cobre o caminho que o PreToolUse não cobre: um hook PreToolUse que corresponde à ferramenta Skill é disparado somente quando o Claude chama a ferramenta, mas digitar /skillname diretamente ignora o PreToolUse. O UserPromptExpansion é disparado nesse caminho direto.
Faz a correspondência em command_name. Deixe o matcher vazio para disparar em todo comando do tipo prompt.
Entrada do UserPromptExpansion
Além dos campos de entrada comuns, os hooks UserPromptExpansion recebemexpansion_type, command_name, command_args, command_source e a string prompt original. O campo expansion_type é slash_command para skills e comandos personalizados, ou mcp_prompt para prompts de servidores MCP.
Controle de decisão do UserPromptExpansion
Os hooksUserPromptExpansion podem bloquear a expansão ou adicionar contexto. Todos os campos de saída JSON estão disponíveis.
Um hook que bloqueia saindo com 2 é encaminhado da mesma forma que
reason: a mensagem de bloqueio mostra o texto do stderr ao usuário.
MessageDisplay
É executado enquanto uma mensagem do assistente é transmitida para a tela. O Claude Code exibe a mensagem em incrementos: cada vez que um lote de linhas recém-concluídas está pronto para ser renderizado, o hook é executado uma vez com essas linhas, e o Claude Code renderiza o texto de substituição do hook no lugar delas. Uma mensagem longa produz várias chamadas; uma mensagem curta pode produzir apenas uma. Use o MessageDisplay para:- remover markdown para uma exibição minimalista
- transformar o texto que um aplicativo do Agent SDK mostra aos seus usuários
- ocultar chaves de API ou nomes de host internos das respostas do Claude
timeout na entrada do hook.
O MessageDisplay serve apenas para exibição: o texto de substituição altera somente o que é renderizado na tela. A transcrição e o que o Claude vê mantêm o texto original, portanto o Claude nunca vê a substituição, e o modo verbose mostra o original. O hook recebe apenas o texto das mensagens do assistente, portanto resultados de ferramentas e o texto que você digita são renderizados sem alteração.
O MessageDisplay não suporta matchers e é disparado para toda mensagem do assistente que transmite texto; mensagens sem texto, como respostas que contêm apenas chamadas de ferramenta, não o acionam.
Em execuções não interativas, incluindo consultas do Agent SDK e claude -p, o MessageDisplay é executado uma vez por mensagem do assistente, em vez de uma vez por lote de linhas. A chamada única chega após a conclusão da mensagem e carrega o texto completo da mensagem: index é 0, final é true e delta contém a mensagem inteira. Um hook que coleta o texto de delta de cada mensagem recebe o mesmo texto total em ambos os modos.
Entrada do MessageDisplay
Além dos campos de entrada comuns, os hooks MessageDisplay recebem identificadores do turno e da mensagem, a posição dessa chamada dentro da mensagem e o novo texto emdelta. Os limites dos lotes dependem de como o texto é transmitido, portanto use index e final para acompanhar o progresso pela mensagem, em vez de esperar que as linhas sejam agrupadas de uma forma específica.
Saída do MessageDisplay
Além dos campos de saída JSON disponíveis para todos os hooks, os hooks MessageDisplay podem retornardisplayContent para substituir o delta na tela:
Os hooks MessageDisplay não têm controle de decisão. Eles não podem bloquear a mensagem nem alterar o que é armazenado na transcrição ou enviado ao Claude. O Claude Code age sobre o
displayContent da saída JSON deles e descarta systemMessage e continue.
Este exemplo remove a formatação markdown das respostas do Claude para uma exibição em texto simples. O script lê cada lote do stdin, remove os marcadores de negrito e os acentos graves de código inline de delta e retorna o resultado como displayContent.
- macOS/Linux
- Windows (PowerShell)
Registre um hook de comando para o evento no seu arquivo de configurações:Salve este script em
.claude/hooks/plain-display.sh no seu projeto e torne-o executável com chmod +x:jq não está instalado, o Claude Code exibe o texto original e registra a falha apenas na saída de depuração, não na sessão.
PreToolUse
É executado depois que o Claude cria os parâmetros da ferramenta e antes de processar a chamada de ferramenta. Faz a correspondência com qualquer nome de ferramenta, excetoEndConversation: ferramentas integradas como Bash, PowerShell, Edit, Write, Read, Glob, Grep, Agent, Workflow, WebFetch, WebSearch, AskUserQuestion e ExitPlanMode, e quaisquer nomes de ferramentas MCP.
Para executar um hook quando um arquivo específico muda no disco, independentemente de quem o gravou, use o FileChanged em vez de fazer a correspondência de ferramentas de edição de arquivos pelo nome. Diferentemente do PreToolUse, o Claude Code executa os hooks FileChanged após a alteração, e eles não têm controle de decisão, portanto não podem bloquear a gravação.
Use o controle de decisão do PreToolUse para permitir, negar, perguntar ou adiar a chamada de ferramenta.
Um hook de callback do Agent SDK em PreToolUse que excede seu timeout bloqueia a chamada de ferramenta.
Entrada do PreToolUse
Além dos campos de entrada comuns, os hooks PreToolUse recebemtool_name, tool_input e tool_use_id.
Para uma ferramenta MCP, a entrada também carrega mcp_server, um objeto com o name do servidor e um source que indica de onde veio a definição do servidor. Os valores de source incluem plugin, sdk e escopos de configuração como user e project. McpServerProvenance na referência do Agent SDK lista todos eles e explica como tratar um que você não reconheça. Baseie decisões de confiança em source, e não em name ou no prefixo de nome de ferramenta mcp__<server>__. O campo mcp_server requer o Claude Code v2.1.274 ou posterior.
Para as ferramentas de arquivo Write, Edit e Read, tool_input.file_path é sempre absoluto:
- O Claude Code expande
~e caminhos relativos antes de os hooks serem executados, portanto um hook que faz a correspondência de caminhos não pode ser contornado por meio de~ou de uma grafia relativa do mesmo caminho - No Windows, o caminho chega com separadores de barra invertida, mesmo quando seu hook é executado no Git Bash, onde
$PWDse parece com/c/project - Uma comparação escrita com barras normais, como uma verificação de
/src/, nunca corresponde a um caminho com barras invertidas, e a chamada de ferramenta prossegue como se o hook não tivesse nada a bloquear - Normalize os separadores antes de comparar:
FILE_PATH="${FILE_PATH//\\//}"no Bash, oufile_path.replace("\\", "/")no Python, e então faça a correspondência de um segmento de caminho como/src/em vez de ancorar com^, já que o caminho é absoluto
Write no Windows entrega:
tool_input dependem da ferramenta:
Bash
Executa comandos de shell.
Quando um comando Bash altera arquivos em um repositório Git, o Claude Code pode registrar o que mudou. Ele registra as alterações em todos os modos de permissão quando a configuração
bashEditDiffEnabled ativa o registro; a entrada dessa configuração indica quais arquivos podem defini-la. Caso contrário, ele as registra somente no modo auto e no modo bypassPermissions, e somente quando o Claude Code orienta o Claude a editar arquivos por meio do Bash. Defina bashEditDiffEnabled como false para desativar o registro. Comandos em segundo plano e comandos somente leitura não carregam diff.
Seu hook PostToolUse então recebe os arquivos alterados em tool_response.bashEditDiff. A lista abrange o que mudou no repositório enquanto o comando era executado. Arquivos que o Git ignora e arquivos em submódulos não são listados. Requer o Claude Code v2.1.269 ou posterior.
A lista é de melhor esforço e está em beta público. O Claude Code pode deixar de capturar uma alteração, incluir um arquivo que outro processo alterou ao mesmo tempo ou parar em seus limites de tamanho. O formato do campo pode mudar. Use a lista para encontrar o que revisar, não para impor uma política.
changedFiles e files listam o que o comando alterou; os campos restantes indicam quão completa e quão confiável é essa lista.
PowerShell
Executa comandos PowerShell. Consulte a ferramenta PowerShell para ver a disponibilidade por plataforma. Os campos correspondem aos da ferramenta Bash, com a string do comando emcommand:
Use
Bash|PowerShell como matcher em hooks que inspecionam comandos de shell, para que cubram ambas as ferramentas:
- No Windows, onde quer que a ferramenta PowerShell esteja habilitada, o Claude trata o PowerShell como o shell principal e encaminha os comandos de shell por meio dele.
- No Windows sem Git Bash, a ferramenta é habilitada automaticamente e o Claude Code não registra a ferramenta Bash.
- Um hook que corresponde apenas a
Bashnunca é disparado nesse caso.
Write
Cria ou sobrescreve um arquivo.Edit
Substitui uma string em um arquivo existente.Read
Lê o conteúdo de arquivos.Glob
Encontra arquivos que correspondem a um padrão glob.Grep
Pesquisa o conteúdo de arquivos com expressões regulares.WebFetch
Busca e processa conteúdo da web.WebSearch
Pesquisa na web.Agent
Inicia um subagente.
Quando uma chamada Agent em primeiro plano é concluída, seu hook PostToolUse recebe o resultado do subagente e a telemetria da execução em
tool_response. Leia esses campos para inspecionar a execução; para totais de tokens e custos entre subagentes, use os contadores de tokens e custos filtrados por query_source "subagent", já que totalTokens e usage cobrem apenas a requisição final:
No Claude Code v2.1.271 ou posterior, um subagente executado com a ferramenta
SubagentHandback, que o Claude Code fornece no modo auto, entrega seu relatório por meio dessa ferramenta em vez de retorná-lo como texto. O campo content de seu resultado completed então carrega uma nota curta sobre essa entrega em vez do próprio relatório. Para ler o relatório, faça a correspondência de um hook PreToolUse ou PostToolUse com SubagentHandback e leia tool_input.message.
Para subagentes em segundo plano, a ferramenta retorna quando a tarefa passa para o segundo plano, portanto tool_response não carrega campos de uso: um lançamento em segundo plano retorna imediatamente, e uma tarefa em primeiro plano que o Claude Code move para o segundo plano no meio da execução retorna nessa transição. Ele tem status: "async_launched", agentId, description, prompt, outputFile e resolvedModel.
Em uma resposta completed, resolvedModel indica o modelo com o qual o subagente começou, que pode diferir do valor de model em tool_input, como quando availableModels ou outra substituição se aplica. Em uma resposta async_launched, resolvedModel indica o modelo em uso quando o agente passou para o segundo plano, então uma troca que aconteceu antes da passagem para o segundo plano se reflete ali.
AskUserQuestion
Faz ao usuário de uma a quatro perguntas de múltipla escolha.ExitPlanMode
Apresenta um plano e pede ao usuário que o aprove antes de o Claude sair do modo de planejamento. O Claude grava o plano em um arquivo no disco antes de chamar a ferramenta, portanto otool_input literal do modelo normalmente está vazio. O Claude Code injeta o conteúdo do plano e o caminho do arquivo antes de passar a entrada para os hooks.
No
PostToolUse, tool_response é um objeto com os campos plan e filePath contendo o plano aprovado, além de flags de status internas. Leia tool_response.plan para obter o conteúdo do plano em vez de ler novamente o arquivo do disco.
Controle de decisão do PreToolUse
Os hooksPreToolUse podem controlar se uma chamada de ferramenta prossegue. Ao contrário de outros hooks que usam um campo decision de nível superior, o PreToolUse retorna sua decisão dentro de um objeto hookSpecificOutput. Isso lhe dá um controle mais rico: quatro resultados (allow, deny, ask ou defer), além da capacidade de modificar a entrada da ferramenta antes da execução. Para permitir ou reescrever um comando Monitor, consulte Corresponder a comandos Monitor.
Quando vários hooks PreToolUse retornam decisões diferentes, a precedência é
deny > defer > ask > allow.
Um hook que bloqueia saindo com 2 é encaminhado da mesma forma que "deny": o Claude vê a mensagem do stderr como o motivo da negação.
Quando um hook retorna "ask", o prompt de permissão exibido ao usuário inclui um rótulo que identifica de onde o hook veio: [settings] para um hook de qualquer arquivo de configurações ou do frontmatter de um agente, [plugin:<name>] para o hook de um plugin, ou [skill] para um hook do frontmatter de uma skill. Isso ajuda os usuários a entender qual fonte de configuração está solicitando a confirmação.
O PreToolUse usava anteriormente os campos de nível superior
decision e reason, mas eles estão descontinuados para esse evento. Use hookSpecificOutput.permissionDecision e hookSpecificOutput.permissionDecisionReason. Os valores descontinuados "approve" e "block" correspondem a "allow" e "deny", respectivamente. Outros eventos, como PostToolUse e Stop, continuam a usar decision e reason de nível superior como seu formato atual.updatedInput do PreToolUse no modo auto
Quando o seu hook retorna updatedInput sem permissionDecision no modo auto, o Claude Code pode negar a chamada alterada. O servidor revisou a entrada que o Claude escreveu, não a entrada que o seu hook retornou. Em sessões interativas no terminal e sessões do VS Code com conexão direta à API da Anthropic, a negação inclui este texto:
- Ele pode negar a chamada ou enviá-la para o prompt de permissão
- Qualquer
updatedInputque ele retornar é descartado, portanto o que é executado é o que o servidor revisou
command nas configurações ou no arquivo de hooks de um plugin pode alterar chamadas de Bash, PowerShell, Monitor, Edit, Write e NotebookEdit sem essa negação. A negação ainda pode aparecer, como quando algum hook alterou uma chamada anterior na mesma resposta do Claude ou quando um comando Bash pede para ser executado fora do sandbox.
Decisões ask do PreToolUse no modo auto
No modo auto, o "ask" de um hook PreToolUse normalmente envia a chamada de ferramenta para o prompt de permissão, e o classificador não decide sobre ela. Algumas chamadas seguem um caminho diferente:
- Chamadas que as próprias verificações do Claude Code também sinalizam: incluem gravações em caminhos protegidos e comandos que pedem para ser executados fora do sandbox. O classificador pode negar uma dessas chamadas antes que qualquer prompt apareça. Se ele aprovar, a chamada normalmente ainda vai para o prompt.
- Chamadas
SubagentHandback: esta ferramenta entrega o relatório de um subagente. Nenhum prompt aparece para ela, e a chamada é executada mesmo que o classificador se oponha.
SubagentHandback, retorne "deny". O Claude Code então informa ao subagente, até três vezes, que seu relatório não foi entregue e que ele deve chamar a ferramenta novamente. Se seu hook continuar negando, o subagente termina sem entregar um relatório por meio dessa ferramenta, e a conversa que aguarda por ele recebe uma nota informando isso.
Ferramentas que exigem interação do usuário
AskUserQuestion e ExitPlanMode exigem interação do usuário. No modo não interativo com a flag -p, o Claude Code as oferece somente quando a execução tem um host de permissão para receber o prompt, como um callback canUseTool do Agent SDK.
Um hook PreToolUse satisfaz esse requisito quando faz o seguinte:
- Lê a entrada da ferramenta do stdin
- Coleta a resposta por meio da sua própria interface
- Retorna
permissionDecision: "allow"junto com umupdatedInputque contém a resposta, para que a ferramenta seja executada sem solicitar confirmação
"allow" não é suficiente para essas ferramentas.
Para AskUserQuestion, devolva o array questions original e adicione um objeto answers que mapeia o texto de cada pergunta para a resposta escolhida. Esta saída responde a uma pergunta com React:
_meta["anthropic/requiresUserInteraction"] é mais restrita: um hook não pode ignorar seu prompt de aprovação com "allow", com ou sem updatedInput, porque o Claude Code não pode confirmar que o hook coletou a interação de que a ferramenta precisa.
Adiar uma chamada de ferramenta para mais tarde
"defer" é para integrações que executam claude -p como um subprocesso e leem sua saída JSON, como um aplicativo do Agent SDK ou uma UI personalizada construída sobre o Claude Code. Ele permite que esse processo chamador pause o Claude em uma chamada de ferramenta, colete entrada por meio de sua própria interface e retome de onde parou.
O Claude Code respeita "defer" apenas no modo não interativo com a flag -p, e apenas quando o Claude faz uma única chamada de ferramenta no turno:
- Em sessões interativas: ele registra um aviso no log e ignora o resultado do hook
- Várias chamadas de ferramenta de uma vez:
"defer"é ignorado com um aviso e a ferramenta prossegue pelo fluxo normal de permissão
AskUserQuestion é o caso típico: o Claude quer perguntar algo ao usuário, mas não há terminal para responder. Uma execução -p oferece AskUserQuestion somente quando tem um host de permissão, como uma ferramenta MCP que você passa com --permission-prompt-tool, portanto inicie a execução com um. O ciclo funciona assim:
- O Claude chama
AskUserQuestion. O hookPreToolUseé disparado. - O hook retorna
permissionDecision: "defer". A ferramenta não é executada. O turno termina com um resultado que carregastop_reason: "tool_deferred", e a chamada de ferramenta pendente permanece na transcrição. - O processo chamador lê
deferred_tool_usedo resultado do SDK, exibe a pergunta em sua própria interface e aguarda uma resposta. - O processo chamador executa
claude -p --resume <session-id>com o mesmo host de permissão. A mesma chamada de ferramenta dispara oPreToolUsenovamente. - O hook retorna
permissionDecision: "allow"com a resposta emupdatedInput. A ferramenta é executada e o Claude continua.
deferred_tool_use contém o id, o name e o input da ferramenta:
cleanupPeriodDays a exclua, após 30 dias por padrão.
Se a resposta não estiver pronta quando você retomar, o hook pode retornar "defer" novamente. Se você enviou um prompt com essa retomada, o Claude o responde sem o resultado da ferramenta e não executa a chamada. Retome sem um prompt até que o hook retorne "allow" ou "deny".
Para retomar uma sessão adiada no modo de planejamento, passe
--permission-prompt-tool junto com --resume para que o Claude Code possa apresentar o plano para aprovação. Para as demais condições, consulte Retomar no modo de planejamento com -p. Requer o Claude Code v2.1.246 ou posterior.Quando você retoma com -p, o Claude Code não restaura nenhum outro modo de permissão armazenado. Ele inicia a execução no modo de permissão em que uma nova execução claude -p iniciaria, então passe --permission-mode ou --dangerously-skip-permissions novamente se a sessão adiada usava um deles.Retomar quando uma ferramenta adiada não está disponível
Um resultado comstop_reason: "tool_deferred_unavailable" significa que a ferramenta de uma chamada adiada não está disponível na sessão retomada, por exemplo porque seu servidor MCP não está conectado. Seu hook PreToolUse não é disparado, e o campo deferred_tool_use do resultado nomeia a ferramenta.
Enquanto a chamada estiver pendente, qualquer prompt que você enviar não chega ao Claude e a execução termina com código 1. O campo result começa com <tool> isn't available, so its deferred call didn't run. Execute a chamada ou descarte-a para que ela não seja executada:
- Para executar a chamada: torne a ferramenta disponível e retome novamente.
- Para descartar a chamada: retome com um prompt e com
CLAUDE_CODE_DROP_UNAVAILABLE_DEFERRED_TOOLdefinida como1. O Claude recebe um erro como resultado da chamada e responde ao seu prompt. Quando você retomar depois, nenhuma chamada estará pendente.
tool_deferred_unavailable com um campo result vazio e, em seguida, a resposta do Claude em um segundo resultado. Ela termina com código 0, a menos que essa resposta seja um erro. Se você definir a variável e não enviar nenhum prompt, a execução ainda descarta a chamada e termina com código 1.
Antes da v2.1.319, o Claude Code respondia a um prompt sem o resultado da ferramenta e descartava a chamada. Nessas versões, envie um novo prompt assim que a ferramenta estiver disponível.
PermissionRequest
É executado quando o Claude Code está prestes a pedir sua permissão para usar uma ferramenta. Em sessões que não podem mostrar um prompt, como subagentes em segundo plano no modo não interativo, o Claude Code ainda executa esses hooks e, se nenhum hook retornar uma decisão, nega a chamada de ferramenta. Para uma chamada que chega a um--permission-prompt-tool ou ao callback canUseTool do Agent SDK, os hooks são executados junto com o seu host, e vale a decisão de quem decidir primeiro.
Use o controle de decisão do PermissionRequest para permitir ou negar em nome do usuário.
Use esse evento quando precisar de um sinal no momento em que o Claude pede permissão para usar uma ferramenta. O Claude Code executa um hook Notification com o tipo permission_prompt somente depois que o prompt fica aguardando por cerca de seis segundos.
O Claude Code não executa hooks PermissionRequest para a requisição de rede de um comando em sandbox. Para obter um sinal para esse prompt, use o tipo de notificação permission_prompt.
Faz a correspondência com o nome da ferramenta, com os mesmos valores do PreToolUse.
Entrada do PermissionRequest
Os hooks PermissionRequest recebem os campostool_name e tool_input como os hooks PreToolUse, mas sem tool_use_id. Para uma ferramenta MCP, eles também recebem o objeto mcp_server. Um array opcional permission_suggestions contém as atualizações de permissão que o Claude Code sugere para essa requisição, como adicionar uma regra de permissão allow ou alterar o modo de permissão.
O array permission_suggestions não é uma lista exata das opções que você vê, porque cada diálogo de permissão monta as próprias opções. Alguns diálogos, como o de edições de arquivo, não leem o array e derivam suas opções da própria requisição. Um diálogo que o lê ainda pode omitir uma opção cuja sugestão permanece no array, por exemplo quando allowManagedPermissionRulesOnly oculta opções de salvar regras. Ele também pode oferecer opções que não têm entrada de sugestão, como Yes, and switch to auto mode, que altera o modo de permissão diretamente em vez de por meio de uma atualização de permissão.
Os hooks PreToolUse são executados antes de cada chamada de ferramenta, precise ela de permissão ou não. Os hooks PermissionRequest são executados apenas quando o Claude Code está prestes a pedir sua permissão, ou quando, de outra forma, negaria automaticamente uma chamada que não pode solicitar confirmação. Nenhum dos dois eventos é disparado para EndConversation.
Controle de decisão do PermissionRequest
Os hooksPermissionRequest podem permitir ou negar requisições de permissão. Além dos campos de saída JSON disponíveis para todos os hooks, seu script de hook pode retornar um objeto decision com estes campos específicos do evento:
Para permitir ou reescrever um comando Monitor, consulte Corresponder comandos Monitor.
Um hook que sai com código 2 sem um objeto
decision deixa o fluxo de permissão inalterado, e seu stderr é descartado. Para conceder ou negar a requisição, retorne o objeto decision.
Entradas de atualização de permissão
O campo de saídaupdatedPermissions e o campo de entrada permission_suggestions usam o mesmo array de objetos de entrada. Cada entrada tem um type que determina seus outros campos, e um destination que controla onde a alteração é gravada.
Em
rules, para uma regra de permissão escrita como Tool(specifier), toolName é o nome da ferramenta e ruleContent é o especificador:
Bash(npm test):{ "toolName": "Bash", "ruleContent": "npm test" }BashouBash(*):{ "toolName": "Bash" }, porque ambos correspondem à ferramenta inteiramcp__github__get_issue:{ "toolName": "mcp__github__get_issue" }
ruleContent de fora de uma regra allow para uma ferramenta MCP. Se você o adicionar, a regra não corresponde a nenhuma chamada.
setMode com bypassPermissions só tem efeito se você iniciou a sessão com o modo bypass já disponível: --dangerously-skip-permissions, --permission-mode bypassPermissions, --allow-dangerously-skip-permissions ou permissions.defaultMode: "bypassPermissions" nas configurações de usuário, de --settings ou gerenciadas. Caso contrário, a atualização não tem efeito. A atualização também não tem efeito quando permissions.disableBypassPermissionsMode desativa o modo, ou quando a sessão é iniciada em modo restrito.bypassPermissions nunca é persistido como defaultMode, independentemente do destination.destination em cada entrada determina se a alteração permanece na memória ou é persistida em um arquivo de configurações.
Um hook pode repetir uma das
permission_suggestions que recebeu como sua própria saída updatedPermissions.
PostToolUse
É executado imediatamente após uma ferramenta ser concluída com sucesso. Corresponde ao nome da ferramenta, com os mesmos valores do PreToolUse. Use uma correspondência mais ampla quando o nome da ferramenta não for o filtro certo:- Para executar um hook depois que qualquer ferramenta for concluída com sucesso, omita o
matcherou defina-o como"*". Seu hook pode então descobrir por conta própria o que mudou, por exemplo executandogit status --porcelain, que também lista arquivos não rastreados quegit diffnão mostra. Para chamadas de ferramenta que falham, adicione o mesmo hook em PostToolUseFailure. - Para executar um hook quando um arquivo específico muda no disco, independentemente de quem o gravou, use FileChanged. O Claude Code não executa um hook
PostToolUsecom matcherEdit|Writequando um comandoBashou um processo fora do Claude Code reescreve o mesmo arquivo.
PostToolUse após uma interrupção
Se um hookPostToolUse parar antes do tempo depois que você envia uma mensagem ou interrompe durante uma chamada de ferramenta, verifique se você pressionou Ctrl+Enter, Enter ou Esc:
Ctrl+Enter: se pressioná-lo encerra o turno enquanto uma ferramenta está em execução e a ferramenta termina, seus hooksPostToolUsesão executados sobre o resultado dela e têm 10 segundos para terminar. A tecla age comoEscse você enfileirou um comando!antes das suas mensagens ou se as tarefas em segundo plano estão desativadas, por exemplo comCLAUDE_CODE_DISABLE_BACKGROUND_TASKS.Enter: uma mensagem que você enfileira comEnternão interrompe o turno, então os hooks mantêm seutimeouthabitual.Esc: você cancela os hooks imediatamente, então envie a mensagem comEnterouCtrl+Enterquando os hooks precisarem ser executados.
timeout. Para permitir que um hook de comando mais longo termine, execute-o com async: true, o que significa que o hook não pode bloquear nem reescrever o resultado.
Antes da v2.1.319, os hooks não eram iniciados depois que você interrompia o turno com uma mensagem, e um hook em execução era interrompido.
Entrada do PostToolUse
Os hooksPostToolUse são disparados depois que uma ferramenta já foi executada com sucesso. A entrada inclui tanto tool_input, os argumentos enviados à ferramenta, quanto tool_response, o resultado que ela retornou. O esquema exato de ambos depende da ferramenta. Os caminhos em tool_input de ferramentas de arquivo chegam no mesmo formato que no PreToolUse: sempre absolutos, com os separadores nativos da plataforma, ou seja, barras invertidas no Windows. Para uma ferramenta MCP, a entrada também traz o objeto mcp_server.
Controle de decisão do PostToolUse
Os hooksPostToolUse podem fornecer feedback ao Claude após a execução da ferramenta. Além dos campos de saída JSON disponíveis para todos os hooks, seu script de hook pode retornar estes campos específicos do evento:
O exemplo abaixo substitui a saída de uma chamada
Bash. O valor de substituição corresponde ao formato de saída da ferramenta Bash:
Anotar um resultado para o classificador do modo auto
RetorneclassifierContext para enviar uma nota curta sobre o resultado da chamada de ferramenta ao classificador do modo auto em vez de ao Claude. A nota serve para a revisão de ações posteriores pelo classificador. O campo requer Claude Code v2.1.236 ou posterior.
O exemplo abaixo informa ao classificador de onde veio a saída de uma consulta:
- Hooks configurados no Claude Code: para hooks de arquivos de configurações, plugins, skills e frontmatter de agentes, o classificador trata a nota como contexto não verificado fornecido pela aplicação. A nota nunca estabelece a intenção do usuário e, se afirmar que você aprovou ou solicitou algo, o classificador confere essa afirmação com suas próprias mensagens na conversa
- Callbacks do Agent SDK em processo: quando uma aplicação que incorpora o Claude Code registra o hook como um callback do TypeScript SDK e retorna a nota durante a sessão ativa, o classificador pode considerar uma declaração do usuário transmitida na nota como intenção do usuário. Essa declaração pode satisfazer um requisito de consentimento que o classificador aceitaria de uma mensagem enviada por você, mas nunca suspende um bloqueio que sua própria mensagem também não conseguiria suspender. Depois que uma sessão é retomada, o Claude Code trata as notas restauradas como contexto não verificado. Quando hooks dos dois grupos anotam a mesma chamada, o classificador trata a nota combinada como não verificada
- Tamanho: o Claude Code limita as notas de uma chamada de ferramenta a 2.000 caracteres e trunca o restante. O limite é compartilhado entre todos os hooks que respondem a essa chamada
- Somente respostas síncronas: o Claude Code ignora o campo na resposta de um hook que é executado em segundo plano, porque essa resposta chega depois que o Claude Code registra o resultado da ferramenta
- Chamadas que o classificador não registra: a transcrição do classificador omite consultas somente leitura, como leituras de arquivos e buscas. O Claude Code descarta uma nota anexada a uma dessas chamadas
- Interação com reescritas: quando a nota descreve uma saída que você está substituindo com
updatedToolOutput, retorne os dois campos na mesma resposta do hook. O Claude Code descarta a nota se essa reescrita for rejeitada ou se a reescrita de outro hook a substituir. O Claude Code entrega uma nota que você retorna sem reescrita mesmo quando outro hook reescreve a saída
PostToolUseFailure
É executado quando uma ferramenta que começou a ser executada falha: a ferramenta lançou um erro, ou uma ferramenta MCP retornou um resultado de erro. Use-o para registrar falhas em log, enviar alertas ou fornecer feedback corretivo ao Claude. Corresponde ao nome da ferramenta, com os mesmos valores do PreToolUse.Este evento não é disparado para chamadas de ferramenta rejeitadas antes da execução: um nome de ferramenta desconhecido, uma entrada que falha na validação de esquema ou na validação específica da ferramenta, ou uma negação de permissão. As rejeições de validação são retornadas como resultados
tool_use_error e acontecem antes da execução dos hooks, portanto não disparam nem PreToolUse nem PostToolUseFailure. As negações de permissão disparam PreToolUse, mas não este evento; consulte PermissionDenied.Entrada do PostToolUseFailure
Os hooks PostToolUseFailure recebem os mesmos campostool_name e tool_input que o PostToolUse, junto com informações de erro como campos de nível superior. Para uma ferramenta MCP, eles também recebem o objeto mcp_server. Por exemplo, um comando npm test que falhou pode entregar:
A string
error geralmente é o mesmo texto que o Claude recebe como resultado da ferramenta que falhou. Seu formato varia conforme a ferramenta e a falha. Baseie seu hook em tool_name, is_interrupt e na primeira linha Exit code N; trate o restante da string como texto de exibição, e não como um formato estável.
- Para Bash e PowerShell, um comando que foi executado e encerrado produz uma primeira linha
Exit code N, seguida de qualquer saída que o comando produziu como um único bloco com stdout e stderr intercalados - Um payload também pode trazer uma mensagem de falha simples, sem a linha de código de saída, quando o Claude Code não conseguiu iniciar o próprio processo do shell
- O Claude Code trunca strings longas no meio em torno de um marcador
... [N characters truncated] ...e pode inserir linhas próprias, comoCommand timed out after 2m 0s
Controle de decisão do PostToolUseFailure
Os hooksPostToolUseFailure podem fornecer contexto ao Claude após a falha de uma ferramenta. Além dos campos de saída JSON disponíveis para todos os hooks, seu script de hook pode retornar estes campos específicos do evento:
PostToolBatch
É executado uma vez depois que todas as chamadas de ferramenta de um lote foram resolvidas, antes de o Claude Code enviar a próxima requisição ao modelo.PostToolUse é disparado uma vez por ferramenta, o que significa que é disparado de forma concorrente quando o Claude faz chamadas de ferramenta em paralelo. PostToolBatch é disparado exatamente uma vez com o lote completo, então é o lugar certo para injetar contexto que depende do conjunto de ferramentas executadas, e não de uma ferramenta isolada. Não há matcher para este evento.
Entrada do PostToolBatch
Além dos campos de entrada comuns, os hooks PostToolBatch recebemtool_calls, um array que descreve cada chamada de ferramenta do lote:
tool_response contém o mesmo conteúdo que o modelo recebe no bloco tool_result correspondente. O valor é uma string serializada ou um array de blocos de conteúdo, exatamente como a ferramenta o emitiu. Para Read, isso significa texto prefixado com números de linha, e não o conteúdo bruto do arquivo. As respostas podem ser grandes, então analise apenas os campos de que você precisa.
O formato de
tool_response difere do de PostToolUse. PostToolUse repassa o objeto Output estruturado da ferramenta, como {filePath: "...", type: "create"} para Write; PostToolBatch repassa o conteúdo serializado de tool_result que o modelo vê.Controle de decisão do PostToolBatch
Os hooksPostToolBatch podem injetar contexto para o Claude. Além dos campos de saída JSON disponíveis para todos os hooks, seu script de hook pode retornar estes campos específicos do evento:
decision: "block" ou continue: false interrompe o loop agêntico antes da próxima chamada ao modelo. A mensagem de bloqueio vem do reason ou stopReason do JSON, ou do stderr na saída com código 2. Você a vê como um aviso na transcrição, e ela permanece na conversa, então o Claude a vê quando a conversa continua.
PermissionDenied
É executado quando o modo auto nega uma chamada de ferramenta, inclusive quando nega sem um veredito do classificador porque uma verificação de segurança separada do modo auto recusou a própria requisição do classificador ou sua resposta não pôde ser analisada. Este hook só é disparado no modo auto: ele não é executado quando você nega manualmente um diálogo de permissão, quando um hookPreToolUse bloqueia uma chamada ou quando uma regra deny corresponde. Use-o para registrar negações em log, ajustar a configuração ou informar ao modelo que ele pode tentar novamente a chamada de ferramenta.
Corresponde ao nome da ferramenta, com os mesmos valores do PreToolUse.
Entrada do PermissionDenied
Além dos campos de entrada comuns, os hooks PermissionDenied recebemtool_name, tool_input, tool_use_id e reason. Para uma ferramenta MCP, eles também recebem o objeto mcp_server.
Controle de decisão do PermissionDenied
Os hooks PermissionDenied podem informar ao modelo que ele pode tentar novamente a chamada de ferramenta negada. Retorne um objeto JSON comhookSpecificOutput.retry definido como true:
retry é true, o Claude Code adiciona uma mensagem à conversa informando ao modelo que ele pode tentar novamente a chamada de ferramenta. O próprio Claude Code não reverte a negação. Se o seu hook não retornar JSON, ou retornar retry: false, a negação se mantém e o modelo recebe a mensagem de rejeição original.
O Claude Code ignora retry: true quando o classificador não produziu nenhum veredito sobre a ação: sua resposta não pôde ser analisada, ou uma verificação de segurança separada do modo auto recusou a própria requisição do classificador. Para essas negações, o Claude Code já informa ao modelo, na mensagem de rejeição, se deve tentar novamente mais tarde ou seguir adiante.
Notification
É executado quando o Claude Code envia notificações. Corresponde ao tipo de notificação. Omita o matcher para executar hooks para todos os tipos de notificação. Você recebe esses eventos de hook mesmo com as notificações da área de trabalho desativadas: a configuraçãopreferredNotifChannel, incluindo notifications_disabled, altera apenas como você é alertado, e não se o seu hook é executado.
Os tipos
quota_auto_resume_fired, quota_auto_resume_stale e quota_auto_resume_disabled requerem Claude Code v2.1.234 ou posterior. O tipo auth_storage_failure requer v2.1.288 ou posterior.
Em sessões de terminal, permission_prompt para a requisição de rede de um comando em sandbox requer Claude Code v2.1.246 ou posterior.
agent_needs_input para a pergunta de configuração do terminal de um colega de equipe requer Claude Code v2.1.248 ou posterior.
Os tipos
permission_prompt, idle_prompt, elicitation_dialog e elicitation_url_dialog compartilham o mesmo timing das notificações da área de trabalho, então, em sessões de terminal, você só os vê quando parece estar longe do terminal:- Espere
permission_promptdepois que você ficar cerca de seis segundos sem digitar. O cronômetro começa quando o prompt de permissão aparece, e cada tecla pressionada o adia. Para executar um hook imediatamente quando o Claude pedir permissão para usar uma ferramenta, use PermissionRequest. - Espere
idle_promptcerca de 60 segundos depois que o Claude terminar de responder, e apenas se você não tiver digitado nada desde então e nenhum agente em segundo plano, como um subagente em segundo plano, ainda estiver em execução. O Claude Code não enviaidle_promptenquanto aguarda a redefinição de um limite de uso do claude.ai. Quando a espera termina por conta própria, um dos tiposquota_auto_resume_*é disparado em seu lugar. - Espere
elicitation_dialogpara um formulário de elicitação, ouelicitation_url_dialogpara uma requisição de URL no navegador, depois que você ficar cerca de seis segundos sem digitar. Ambos compartilham o mesmo limite de seis segundos dopermission_prompt: o cronômetro começa quando o diálogo aparece, e cada tecla pressionada o adia.
permission_prompt de forma diferente em sessões em que envia requisições de permissão ao callback canUseTool do Agent SDK, que é como o Claude Desktop e a extensão do VS Code hospedam o Claude Code:
- Espere
permission_promptcerca de seis segundos depois que o Claude pedir permissão. O Claude Code não o adia enquanto você digita. - Se você ou um hook PermissionRequest responderem antes, o Claude Code não executa
permission_prompt. - Defina
CLAUDE_CODE_DISABLE_PERMISSION_PROMPT_NOTIFY_HOOKScomo1para desativarpermission_promptnessas sessões.
permission_prompt não era disparado nessas sessões.
Use matchers separados para executar handlers diferentes dependendo do tipo de notificação. Esta configuração aciona um script de alerta específico de permissão quando o Claude precisa de aprovação de permissão e uma notificação diferente quando o Claude está ocioso:
Entrada do Notification
Além dos campos de entrada comuns, os hooks Notification recebemmessage com o texto da notificação, um title opcional e notification_type, que indica qual tipo foi disparado.
systemMessage e continue, mas ainda emite terminalSequence, que é do que o exemplo de notificação da área de trabalho depende. Os hooks Notification são destinados a efeitos colaterais, como encaminhar a notificação para um serviço externo.
SubagentStart
É executado quando o Claude inicia um subagente com a ferramenta Agent, quando o Claude retoma um subagente e cada vez que um colega de uma equipe de agentes em processo lida com uma nova mensagem. Suporta matchers para filtrar pelo nome do tipo de agente. Para agentes integrados, é o nome do agente, comogeneral-purpose, Explore ou Plan. Para subagentes personalizados, é o campo name do frontmatter do agente, e não o nome do arquivo.
Para subagentes fornecidos por um plugin, o tipo de agente é o identificador com escopo de plugin, como my-plugin:reviewer, e não o nome simples do frontmatter. Os dois-pontos colocam um nome com escopo de plugin no caminho de expressão regular, então ancore o matcher com ^ e $ para uma correspondência exata: ^my-plugin:reviewer$.
Entrada do SubagentStart
Além dos campos de entrada comuns, os hooks SubagentStart recebemagent_id com o identificador único do subagente e agent_type com o nome do agente usado pelo filtro do matcher.
SubagentStop
É executado quando um subagente do Claude Code termina de responder. Corresponde ao tipo de agente, com os mesmos valores do SubagentStart.Entrada do SubagentStop
Além dos campos de entrada comuns, os hooks SubagentStop recebemstop_hook_active, agent_id, agent_type, agent_transcript_path e last_assistant_message. O campo agent_type é o valor usado para a filtragem do matcher. O transcript_path é a transcrição da sessão principal, enquanto agent_transcript_path é a transcrição do próprio subagente, armazenada em uma pasta aninhada subagents/. O campo last_assistant_message contém o conteúdo de texto da resposta final do subagente, para que os hooks possam acessá-lo sem analisar o arquivo de transcrição.
Nem todo evento SubagentStop vem de um subagente iniciado pelo Claude. O Claude Code também executa agentes internos para alguns de seus próprios recursos, como sugestões de prompt e perguntas paralelas com /btw, e o SubagentStop também é disparado quando um deles termina. Para esses eventos, agent_type é o nome do agente com que a própria sessão é executada, como um definido com --agent ou com a configuração agent, e uma string vazia quando a sessão é executada sem um.
Um matcher que nomeia tipos de agente não corresponde a um agent_type vazio. Um hook cujo matcher é omitido, "" ou "*", ou é uma expressão regular que corresponde a uma string vazia, também é executado para eventos com agent_type vazio.
No Claude Code v2.1.271 ou posterior, um subagente que é executado com a ferramenta SubagentHandback entrega seu relatório por meio dessa ferramenta antes de parar. O campo last_assistant_message então contém o texto final do subagente, se houver, que não é o relatório entregue. O relatório é a entrada message dessa chamada, que um hook PreToolUse ou PostToolUse com matcher em SubagentHandback recebe como tool_input.message.
Os hooks SubagentStop também recebem os arrays background_tasks e session_crons descritos em Entrada do Stop. Ambos os arrays têm como escopo a sessão pai, e não o subagente.
hookSpecificOutput.additionalContext com hookEventName definido como "SubagentStop", para feedback sem erro que mantém o subagente em execução. Retornar decision: "block" com um reason mantém o subagente em execução e entrega reason ao subagente como sua próxima instrução. Um hook que bloqueia saindo com código 2 entrega sua mensagem de stderr da mesma forma. Para injetar contexto na sessão pai depois que um subagente retorna, use um hook PostToolUse na ferramenta Agent.
TaskCreated
É executado quando uma tarefa está sendo criada por meio da ferramentaTaskCreate. Use-o para impor convenções de nomenclatura, exigir descrições de tarefas ou impedir que certas tarefas sejam criadas. Em uma sessão sem as ferramentas Task, este evento não é disparado.
Os hooks TaskCreated não suportam matchers e são disparados em todas as ocorrências.
Entrada do TaskCreated
Além dos campos de entrada comuns, os hooks TaskCreated recebemtask_id, task_subject e, opcionalmente, task_description, teammate_name e team_name.
Controle de decisão do TaskCreated
Um hook TaskCreated pode bloquear a criação com o código de saída 2 ou com uma decisão JSON. Em ambos os casos, o Claude Code exclui a tarefa e retorna sua mensagem ao Claude como o erro da ferramenta. O Claude Code ignoracontinue: false deste evento e o Claude continua trabalhando.
- Código de saída 2: o Claude Code retorna o texto do stderr como a mensagem.
- JSON
{"decision": "block", "reason": "..."}: o Claude Code retornareasoncomo a mensagem.
TaskCompleted
É executado quando uma tarefa está sendo marcada como concluída. Isso é disparado em duas situações: quando qualquer agente marca explicitamente uma tarefa como concluída por meio da ferramenta TaskUpdate, ou quando um colega de uma equipe de agentes termina seu turno com tarefas em andamento. Use-o para impor critérios de conclusão, como testes aprovados ou verificações de lint, antes que uma tarefa possa ser encerrada. Os hooks TaskCompleted não suportam matchers e são disparados em todas as ocorrências.Entrada do TaskCompleted
Além dos campos de entrada comuns, os hooks TaskCompleted recebemtask_id, task_subject e, opcionalmente, task_description, teammate_name e team_name.
Controle de decisão do TaskCompleted
Os hooks TaskCompleted suportam duas formas de controlar a conclusão de tarefas:- Código de saída 2: a tarefa não é marcada como concluída e a mensagem do stderr é enviada de volta ao modelo como feedback.
- JSON
{"continue": false, "stopReason": "..."}: quando um colega de equipe terminando seu turno acionou o evento, interrompe o colega de equipe por completo, correspondendo ao comportamento do hookStop. OstopReasoné mostrado ao usuário. Quando a ferramentaTaskUpdateacionou o evento, o Claude Code ignoracontinue: false; o código de saída 2 ainda bloqueia a conclusão.
Stop
É executado quando o agente principal do Claude Code termina de responder. Não é executado se a parada ocorreu devido a uma interrupção do usuário. Erros de API disparam StopFailure em seu lugar.Entrada do Stop
Além dos campos de entrada comuns, os hooks Stop recebemstop_hook_active, last_assistant_message, background_tasks e session_crons. O campo stop_hook_active é true quando o Claude Code já está continuando como resultado de um hook Stop. Verifique esse valor ou processe a transcrição para evitar bloquear em uma condição que nunca será resolvida.
O Claude Code aplica um limite de 8 continuações consecutivas: depois que os hooks Stop continuaram o turno oito vezes seguidas, o Claude Code sobrescreve o próximo bloqueio e encerra o turno. A contagem de continuações consecutivas é redefinida cada vez que o Claude chama uma ferramenta. Para aumentar o limite, defina CLAUDE_CODE_STOP_HOOK_BLOCK_CAP.
O campo last_assistant_message contém o conteúdo de texto da resposta final do Claude, para que os hooks possam acessá-lo sem analisar o arquivo de transcrição. Para hooks que atuam sobre o turno recém-concluído, como hooks de leitura em voz alta ou de notificação, use este campo em vez de ler transcript_path: não há garantia de que o arquivo de transcrição inclua a mensagem final no momento do Stop em todas as versões.
Os arrays background_tasks e session_crons permitem que os hooks diferenciem “a sessão terminou” de “a sessão está pausada aguardando que um trabalho em segundo plano a desperte novamente”. Ambos os arrays estão presentes quando o registro de tarefas está acessível e ficam vazios quando nada está em andamento ou agendado.
Cada entrada em background_tasks descreve uma tarefa em andamento e usa estes campos:
Cada entrada em
session_crons descreve um despertar agendado com escopo de sessão, proveniente de CronCreate, ScheduleWakeup e /loop:
Este exemplo mostra uma entrada do Stop com uma tarefa de shell em andamento e um cron recorrente:
Controle de decisão do Stop
Os hooksStop e SubagentStop podem controlar se o Claude continua. Além dos campos de saída JSON disponíveis para todos os hooks, seu script de hook pode retornar estes campos específicos do evento:
Um hook que bloqueia saindo com código 2 é encaminhado da mesma forma que
reason: o Claude recebe a mensagem do stderr como a explicação de por que deve continuar.
additionalContext quando o hook estiver funcionando como projetado e dando orientação ao Claude, como “execute a suíte de testes antes de terminar”. Ele mantém a conversa em andamento com as mesmas proteções contra loop de decision: "block", a saber, a entrada stop_hook_active e o limite de 8 continuações consecutivas, mas a transcrição o rotula como Stop hook feedback e nenhuma notificação de erro de hook é exibida:
StopFailure
É executado em vez do Stop quando o turno termina devido a um erro de API. O Claude Code ignora a saída e o código de saída do hook, excetoterminalSequence. Use-o para registrar falhas em log, enviar alertas ou tomar ações de recuperação quando o Claude não consegue concluir uma resposta devido a rate limits, problemas de autenticação ou outros erros de API.
Entrada do StopFailure
Além dos campos de entrada comuns, os hooks StopFailure recebemerror, error_details opcional e last_assistant_message opcional. O campo error identifica o tipo de erro e é usado para a filtragem do matcher.
TeammateIdle
É executado quando um colega de uma equipe de agentes está prestes a ficar ocioso depois de terminar seu turno. Use-o para impor critérios de qualidade antes que um colega de equipe pare de trabalhar, como exigir que as verificações de lint passem ou verificar se os arquivos de saída existem. Os hooks TeammateIdle não suportam matchers e são disparados em todas as ocorrências.Entrada do TeammateIdle
Além dos campos de entrada comuns, os hooks TeammateIdle recebemteammate_name e team_name.
Controle de decisão do TeammateIdle
Os hooks TeammateIdle suportam duas formas de controlar o comportamento do colega de equipe:- Código de saída 2: o colega de equipe recebe a mensagem do stderr como feedback e continua trabalhando em vez de ficar ocioso.
- JSON
{"continue": false, "stopReason": "..."}: interrompe o colega de equipe por completo, correspondendo ao comportamento do hookStop. OstopReasoné mostrado ao usuário.
ConfigChange
É executado quando um arquivo de configuração muda durante uma sessão. Use-o para auditar alterações de configurações, impor políticas de segurança ou bloquear modificações não autorizadas em arquivos de configuração. O Claude Code executa hooks ConfigChange quando um arquivo de configurações, um arquivo de política gerenciada ou um arquivo de skill muda. Para política gerenciada, ele os executa somente quandomanaged-settings.json ou um arquivo em managed-settings.d/ muda.
O matcher filtra pela origem da configuração:
Alterações como estas entram em vigor sem executar os hooks:
- Regras e configurações que você salva com Yes, and don’t ask again,
/permissionsou/model, na sessão a partir da qual você as salvou. Se outra sessão aberta carregar o mesmo arquivo, os hooks são executados lá. - Atualizações nas configurações gerenciadas pelo servidor, nas preferências gerenciadas do macOS ou na política do registro do Windows
- No WSL com
wslInheritsWindowsSettings, uma alteração no arquivo de configurações gerenciadas do lado do Windows, que o Claude Code detecta em sua verificação periódica de políticas
Entrada do ConfigChange
Além dos campos de entrada comuns, os hooks ConfigChange recebemsource e, opcionalmente, file_path. O campo source indica qual tipo de configuração mudou, e file_path fornece o caminho do arquivo específico que foi modificado.
Controle de decisão do ConfigChange
Os hooks ConfigChange podem impedir que alterações de configuração entrem em vigor. Use o código de saída 2 ou umadecision JSON para impedir a alteração. Quando bloqueadas, as novas configurações não são aplicadas à sessão em execução.
policy_settings não podem ser bloqueadas. Os hooks ainda são disparados para origens policy_settings quando um arquivo de configurações gerenciadas na máquina muda, então você pode usá-los para registrar essas edições em log, mas qualquer decisão de bloqueio é ignorada. Isso garante que as configurações gerenciadas pela empresa sempre entrem em vigor. O Claude Code não executa hooks ConfigChange quando configurações gerenciadas pelo servidor chegam ou são atualizadas.
O Claude Code age com base na decisão de bloqueio da saída JSON de um hook ConfigChange e descarta systemMessage e continue. Uma alteração bloqueada não exibe nenhuma mensagem para você nem para o Claude, quer você bloqueie com reason ou com stderr na saída com código 2. O Claude Code apenas grava uma linha no log de depuração.
CwdChanged
É executado quando um comando de shell na conversa principal altera o diretório de trabalho, por exemplo quando o Claude executa um comandocd. Use-o para reagir a mudanças de diretório: recarregar variáveis de ambiente, ativar toolchains específicas do projeto ou executar scripts de configuração automaticamente. Combina com FileChanged para ferramentas como o direnv, que gerenciam o ambiente por diretório.
Hooks CwdChanged têm acesso a CLAUDE_ENV_FILE. Se seu hook gravar variáveis nesse arquivo, elas persistem nos comandos Bash subsequentes até o próximo evento CwdChanged, quando o Claude Code as limpa.
O CwdChanged não suporta matchers e é disparado em todas as ocorrências.
Entrada do CwdChanged
Além dos campos de entrada comuns, os hooks CwdChanged recebemold_cwd e new_cwd.
Saída do CwdChanged
Além dos campos de saída JSON disponíveis para todos os hooks, os hooks CwdChanged podem retornarwatchPaths para definir dinamicamente quais caminhos de arquivo o FileChanged observa:
Os hooks CwdChanged não têm controle de decisão. Eles não podem bloquear a mudança de diretório.
O Claude Code lê
watchPaths e systemMessage da saída JSON deles e descarta continue. Em sessões interativas, ele mostra o systemMessage como uma breve notificação no terminal. A mensagem não chega ao fluxo de mensagens do SDK.
DirectoryAdded
É executado depois que você adiciona um diretório de trabalho no meio da sessão com o comando/add-dir, ou depois que um cliente SDK adiciona um com a requisição de controle register_repo_root. Use-o para preparar um repositório recém-adicionado, por exemplo instalando suas dependências.
O Claude Code não dispara este evento quando:
- Você passa um diretório com a flag de inicialização
--add-dir; o SessionStart cobre esses diretórios - Você adiciona um diretório na aba Workspace de
/permissions - Você adiciona um diretório que já é um diretório de trabalho ou está dentro de um
Entrada do DirectoryAdded
Além dos campos de entrada comuns, os hooks DirectoryAdded recebemdirectory e source.
continue da saída JSON deles e trata o restante de forma diferente conforme a origem:
slash_command: o Claude Code entrega osystemMessagedo hook ao Claude como contexto no próximo turno da conversa, em vez de mostrá-lo a você. Uma contagem de hooks com falha aparece na transcrição. A saída completa das falhas vai para o log de depuraçãoregister_repo_root: o Claude Code grava a saída desystemMessagee a saída das falhas apenas no log de depuração
FileChanged
É executado quando um arquivo monitorado muda no disco. O Claude Code detecta alterações com um monitor do sistema de arquivos, não inspecionando chamadas de ferramenta, então ele executa o hook independentemente do que alterou o arquivo: uma chamada de ferramentaEdit ou Write, um script que o Claude executa com Bash ou um processo totalmente fora do Claude Code. Um uso comum é recarregar variáveis de ambiente quando arquivos de configuração do projeto mudam.
O matcher deste evento tem duas funções:
- Montar a lista de monitoramento: o valor é dividido em
|e cada segmento é registrado como um nome de arquivo literal no diretório de trabalho, então".envrc|.env"monitora exatamente esses dois arquivos. Padrões regex não são úteis aqui: um valor como^\.envmonitoraria um arquivo chamado literalmente^\.env. - Filtrar quais hooks são executados: quando um arquivo monitorado muda, o mesmo valor filtra quais grupos de hooks são executados usando as regras de matcher padrão em relação ao nome base do arquivo alterado.
data.csv após qualquer alteração, incluindo um comando Bash ou um script externo reescrevendo o arquivo:
file_path da entrada JSON em stdin. Sua verificação com grep testa a mesma coisa que o perl remove, um CR no final de uma linha, então a execução após uma normalização termina sem tocar no arquivo. Uma verificação mais permissiva entra em loop infinito, porque perl -i reescreve o arquivo mesmo quando não substitui nada e o Claude Code executa o hook novamente após cada reescrita. Salve este script em /path/to/normalize-line-endings.sh e torne-o executável:
data.csv com um comando Bash. O Claude Code executa o hook e o arquivo termina com quebras de linha LF.
Para monitorar arquivos que você não pode nomear de antemão, retorne watchPaths de um hook para atualizar a lista de monitoramento dinamicamente. O Claude Code inicia o monitor somente quando algo nomeia um arquivo a ser monitorado, então inicialize a lista com um grupo FileChanged cujo matcher nomeie pelo menos um arquivo, ou com um hook SessionStart ou CwdChanged que retorne watchPaths. O matcher ainda filtra quais grupos de hooks são executados quando um arquivo monitorado muda, então deixe sem matcher o grupo que lida com caminhos dinâmicos, o que corresponde a todos os arquivos monitorados e não adiciona nada à lista de monitoramento. Um matcher "*" também corresponde a todos os arquivos, mas o Claude Code o registra na lista de monitoramento como qualquer outro valor, como um arquivo literal chamado *.
Os hooks FileChanged têm acesso a CLAUDE_ENV_FILE. As variáveis gravadas nesse arquivo persistem nos comandos Bash subsequentes até o próximo evento CwdChanged, quando o Claude Code as limpa.
Entrada do FileChanged
Além dos campos de entrada comuns, os hooks FileChanged recebemfile_path e event.
Saída do FileChanged
Além dos campos de saída JSON disponíveis para todos os hooks, os hooks FileChanged podem retornarwatchPaths para atualizar dinamicamente quais caminhos de arquivo são monitorados:
Os hooks FileChanged não têm controle de decisão. Eles não podem impedir que a alteração do arquivo ocorra.
O Claude Code lê
watchPaths e systemMessage da saída JSON deles e descarta continue. Em sessões interativas, ele mostra a systemMessage como uma breve notificação no terminal. A mensagem não chega ao fluxo de mensagens do SDK.
WorktreeCreate
É executado quando o Claude Code cria um worktree em casos como estes:- Você inicia uma sessão com
claude --worktree - O Claude cria um worktree durante uma sessão e muda para ele com a ferramenta
EnterWorktree - Um subagente usa
isolation: "worktree" - Um fluxo de trabalho executa um agente em seu próprio worktree
- O Claude Code isola uma sessão em segundo plano em seu próprio worktree
claude remote-controlno modoworktreeinicia uma sessão em seu próprio worktree
--worktree e --tmux:
git worktree addvia Bash: para inspecionar ou bloquear esse comando, adicione um hookPreToolUsecom o matcherBash.--worktreecom--tmux: o Claude Code cria o worktree antes de carregar os plugins, então um hook WorktreeCreate de um plugin não é executado. Para que seu hook seja executado com ambas as flags, defina-o em um arquivo de configurações. Antes da v2.1.300, o hook WorktreeCreate de um plugin também não era executado apenas com--worktree.
git worktree. Configurar um hook WorktreeCreate substitui esse comportamento padrão do git, permitindo que você use um sistema de controle de versão diferente, como SVN, Perforce ou Mercurial.
Como o hook substitui totalmente o comportamento padrão, .worktreeinclude não é processado. Se você precisar copiar arquivos de configuração locais como .env para o novo worktree, faça isso dentro do seu script de hook.
O hook deve retornar o caminho para o diretório do worktree criado. O Claude Code usa esse caminho como diretório de trabalho para a sessão isolada. Consulte Saída do WorktreeCreate para saber como cada tipo de hook retorna o caminho.
O Claude Code age com base no sucesso do hook e no caminho retornado, e descarta systemMessage e continue.
Este exemplo cria uma cópia de trabalho SVN e imprime o caminho para o Claude Code usar. Substitua a URL do repositório pela sua:
name do worktree da entrada JSON em stdin, faz checkout de uma cópia nova em um novo diretório e imprime o caminho do diretório. O echo na última linha é o que o Claude Code lê como caminho do worktree. Redirecione qualquer outra saída para stderr para que ela não interfira no caminho.
Entrada do WorktreeCreate
Além dos campos de entrada comuns, os hooks WorktreeCreate recebem o camponame. Este é um identificador slug para o novo worktree, especificado pelo usuário ou gerado automaticamente, por exemplo bold-oak-a3f2.
Saída do WorktreeCreate
Os hooks WorktreeCreate não usam o modelo padrão de decisão permitir/bloquear. Em vez disso, o sucesso ou a falha do hook determina o resultado. O hook deve retornar o caminho para o diretório do worktree criado:- Hooks de comando (
type: "command"): imprima o caminho como a última linha não vazia de stdout. O Claude Code remove códigos de escape ANSI antes de ler essa linha, então banners de inicialização do shell impressos antes do seuechosão ignorados. Redirecione qualquer outra saída do hook para stderr. - Hooks HTTP (
type: "http"): retorne{ "hookSpecificOutput": { "hookEventName": "WorktreeCreate", "worktreePath": "/absolute/path" } }no corpo da resposta.
. ou .. nele. Se o caminho resultante não for um diretório em que o Claude Code possa entrar, a sessão imprime um erro indicando o caminho e sai com código 1.
O Claude Code recusa um caminho absoluto que contenha segmentos . ou .., e qualquer caminho que passe por um link simbólico abaixo da raiz do repositório. O erro indica o componente rejeitado. Um link simbólico incluído em um commit no repositório poderia redirecionar o worktree para fora dele. Retorne um caminho normalizado que não passe por um link simbólico dentro do repositório.
WorktreeRemove
É executado quando o Claude Code limpa um worktree que o seu hookWorktreeCreate criou. O evento é disparado quando:
- Você sai de uma sessão de worktree interativa e escolhe remover o worktree quando o Claude Code solicita
- Você sai de uma sessão de worktree interativa que não nomeou, o Claude Code não encontra arquivos alterados ou não rastreados e remove o worktree sem solicitar confirmação
- Você exclui uma sessão em segundo plano que é executada no worktree
- Você pede ao Claude para sair e remover o worktree durante uma sessão, e o Claude o remove com a ferramenta
ExitWorktree - Uma sessão que
claude remote-controliniciou no modoworktreetermina sem falhar, e o Claude Code não encontra arquivos alterados ou não rastreados nem novos commits em seu worktree - Você interrompe
claude remote-controlenquanto sessões que ele iniciou no modoworktreeainda estão em execução, e o Claude Code não encontra arquivos alterados ou não rastreados nem novos commits em seus worktrees
ExitWorktree ou uma limpeza do claude remote-control. ExitWorktree se recusa a remover um worktree criado por hook, a menos que a chamada passe discard_changes: true, o que torna o seu hook a última verificação nesse caminho.
O Claude Code usa o git para procurar arquivos alterados ou não rastreados, então não encontra nenhum em um worktree que não seja um checkout git nem esteja dentro de um, mesmo quando o diretório contém trabalho sem commit. Verifique esse trabalho no seu hook WorktreeRemove antes que ele exclua qualquer coisa.
Para worktrees baseados em git, o Claude Code lida com a limpeza automaticamente com git worktree remove. Se você configurou um hook WorktreeCreate, combine-o com um hook WorktreeRemove para controlar a limpeza:
- Sem hook WorktreeRemove: o Claude Code recorre ao git para uma remoção ao sair ou por meio de
ExitWorktree, e mantém o worktree quando oclaude remote-controlfaz a limpeza:- Você sai de uma sessão de worktree, ou o Claude chama
ExitWorktree: o Claude Code remove o caminho que o seu hook WorktreeCreate retornou comogit worktree remove --forcefaria, então um worktree que o git reconhece é removido. Um worktree que o git não reconhece, por exemplo um que o seu hook criou com um sistema de controle de versão que não seja git, permanece no disco. claude remote-controllimpa o worktree de uma sessão: o worktree permanece no disco, e o terminal que executaclaude remote-controlmostraworktree removal failed, kept: <path>.- Você exclui uma sessão em segundo plano: consulte O que a exclusão de uma sessão remove.
- Você sai de uma sessão de worktree, ou o Claude chama
- O hook termina com 0: o worktree conta como removido. O Claude Code não lê mais nada do hook, então certifique-se de que o seu hook excluiu o diretório.
- O hook termina com código diferente de zero: a remoção falha se o diretório em
worktree_pathainda existir depois, e o worktree permanece no disco sem fallback para o git. Um hook que excluiu o diretório antes de terminar com código diferente de zero conta como removido. Para saber como a falha é relatada, consulte Entrada do WorktreeRemove.
systemMessage e continue.
Para a exclusão de uma sessão em segundo plano, o Claude Code verifica o caminho do worktree armazenado antes de executar o hook, recusando um caminho que seja um link simbólico ou passe por um abaixo da raiz do repositório. Nesse caminho, o hook é executado para um worktree que ainda contém arquivos somente quando você confirma a exclusão na visualização de agentes. Para esse worktree, claude rm mantém a sessão e o worktree.
O Claude Code passa o caminho retornado pelo WorktreeCreate como worktree_path na entrada do hook. Este exemplo lê esse caminho e remove o diretório:
Entrada do WorktreeRemove
Além dos campos de entrada comuns, os hooks WorktreeRemove recebem o campoworktree_path, que é o caminho absoluto para o worktree sendo removido.
worktree_path ainda existe depois, a remoção falha:
- O worktree permanece no disco, e o comando e o stderr do hook vão para o log de depuração.
- Se você estava excluindo uma sessão em segundo plano, a sessão também permanece. A mensagem de recusa na visualização de agentes informa como o hook terminou, como
exited 1, cita o início do seu stderr e diz se excluir a sessão novamente remove o diretório mesmo assim. - Se o
claude remote-controlestava limpando o worktree de uma sessão, o terminal que o executa mostraworktree removal failed, kept: <path>.
PreCompact
É executado antes de o Claude Code executar uma operação de compactação. O valor do matcher indica se a compactação foi acionada manual ou automaticamente:
Termine com código 2 para bloquear a compactação. Para um
/compact manual, a mensagem de stderr é mostrada ao usuário. Você também pode bloquear retornando JSON com "decision": "block".
Bloquear a compactação automática tem efeitos diferentes dependendo de quando ela é disparada. Se a compactação foi acionada proativamente antes do limite de contexto, o Claude Code a ignora e a conversa continua sem compactação. Se a compactação foi acionada para se recuperar de um erro de limite de contexto já retornado pela API, o erro subjacente aparece e a requisição atual falha.
O Claude Code descarta os campos systemMessage e continue de um hook PreCompact.
Entrada do PreCompact
Além dos campos de entrada comuns, os hooks PreCompact recebemtrigger e custom_instructions. Para manual, custom_instructions contém o que o usuário passa para /compact e é null quando ele não passa nada. Para auto, custom_instructions é null.
Saída do PreCompact
Quando um hook PreCompact termina com 0 e não bloqueia, o Claude Code usa seu stdout como instruções para o resumo da compactação. Mantenha esse stdout abaixo de 10.000 caracteres por hook. O Claude Code corta saídas mais longas no limite e acrescenta um marcador.PostCompact
É executado depois que o Claude Code conclui uma operação de compactação. Use este evento para reagir ao novo estado compactado, por exemplo para registrar em log o resumo gerado ou atualizar um estado externo. O Claude Code descarta os campossystemMessage e continue de um hook PostCompact.
Os mesmos valores de matcher se aplicam como no PreCompact:
Entrada do PostCompact
Além dos campos de entrada comuns, os hooks PostCompact recebemtrigger e compact_summary. O campo compact_summary contém o resumo da conversa gerado pela operação de compactação.
PreModelSwitch
É executado antes de o Claude Code aplicar uma troca de modelo que você ou um cliente solicitou. Use-o para bloquear uma troca, exigir confirmação ou mostrar quanto a troca custará antes que ela aconteça. O PreModelSwitch requer o Claude Code v2.1.251 ou posterior. O Claude Code o executa para estas solicitações:/model <name>e o seletor do/model- O seletor de modelo
Option+PouAlt+P - A configuração Model em
/config - Ativar o modo rápido quando isso altera o modelo da sessão
- Uma requisição
set_model, ou uma alteração de modelo em uma requisiçãoapply_flag_settings, de um host do Agent SDK ou do Remote Control
[1m]. Um alias como opus, um ID de modelo com data e um ID específico de provedor, como um ID de modelo do Amazon Bedrock, correspondem todos ao único nome canônico para o qual são resolvidos, então claude-opus-5 cobre todas as grafias do Opus 5.
Quando o Claude Code não consegue determinar um nome canônico para o destino, por exemplo um ID de modelo personalizado que só o seu gateway de LLM conhece, ele executa todos os hooks PreModelSwitch independentemente do matcher. Um hook que bloqueia deve, portanto, verificar to_model na sua entrada em vez de confiar apenas no matcher.
Escreva o matcher como um nome exato, uma lista separada por | como claude-opus-4-6|claude-opus-5, ou uma expressão regular como .*opus.*. Este exemplo usa um matcher de nome exato e também verifica to_model na entrada do hook, então recusa uma troca para o Opus 4.6 terminando com código 2 e deixa passar qualquer outro destino:
- macOS/Linux
- Windows (PowerShell)
O comando verifica
to_model com jq:/model claude-opus-4-6 a partir de uma sessão que esteja executando um modelo diferente. O Claude Code mantém o modelo atual e informa que um hook PreModelSwitch bloqueou a troca, com a sua mensagem como motivo.
Entrada do PreModelSwitch
Além dos campos de entrada comuns, os hooks PreModelSwitch recebem os campos desta tabela. Os últimos cinco descrevem quanto custa reenviar a conversa para o novo modelo, para que um hook possa mostrar esse valor antes que a troca aconteça.
Este exemplo mostra a entrada para
/model opus em uma sessão que executa o Sonnet 5:
Controle de decisão do PreModelSwitch
Os hooksPreModelSwitch podem cancelar a troca, pedir ao usuário que a confirme ou deixá-la prosseguir. O código de saída 2 ou um decision: "block" de nível superior cancela a troca.
Para um controle mais refinado, retorne permissionDecision e permissionDecisionReason em um objeto hookSpecificOutput, como no PreToolUse. O PreModelSwitch aceita "allow", "deny" e "ask". Ele não aceita "defer", updatedInput nem additionalContext. A tabela abaixo descreve ambos os campos:
Somente o
/model em uma sessão interativa pode mostrar o prompt de "ask". Em todas as outras superfícies, incluindo o modo não interativo com a flag -p, /config e requisições set_model, o Claude Code trata "ask" como uma recusa.
Este exemplo pede ao usuário que confirme e cita a contagem de tokens de context_tokens:
deny > ask > allow.
O Claude Code mostra ao usuário qualquer systemMessage que o seu hook retorne, independentemente da decisão, então um hook de relatório de custos pode retornar {"systemMessage": "..."} e terminar com 0.
Timeouts e outros códigos de saída do PreModelSwitch
Um hook PreModelSwitch que não responde antes do seu timeout bloqueia a troca. O timeout padrão para este evento é de 30 segundos. Um código de saída diferente de 0 ou 2 sem saída JSON válida é um erro não bloqueante, então a troca prossegue, exceto para hooks cuja falha a bloqueia.PostModelSwitch
É executado depois que o modelo da sessão muda. Use-o para dar ao Claude orientações específicas do modelo sem editar cada CLAUDE.md, por exemplo uma instrução para toda a organização que se aplica a determinados modelos. O PostModelSwitch requer o Claude Code v2.1.251 ou posterior. Ele não pode bloquear, porque o modelo já mudou. O Claude Code executa hooks PostModelSwitch após qualquer uma destas alterações:- Uma troca que você ou um cliente solicitou
- Um fallback automático de modelo, que altera o modelo da sessão
- Uma configuração como
opusplanentrando ou saindo do modo de planejamento - O Claude Code restaurando o modelo quando você retoma uma sessão
/model opus em uma sessão do Sonnet, e depois pergunte ao Claude quais orientações ele tem sobre o modelo atual.
Entrada do PostModelSwitch
Os hooks PostModelSwitch recebem os mesmos campos que o PreModelSwitch, comhook_event_name definido como "PostModelSwitch" e mais dois valores de source: "auto" para um fallback automático ou outra alteração que o Claude Code fez por conta própria, e "resume" para o modelo restaurado quando você retoma uma sessão.
requested_model é null quando source é "auto". Quando source é "resume", é a configuração de modelo salva que o Claude Code restaurou.
Controle de decisão do PostModelSwitch
O Claude Code pega o stdout em texto simples do seu hook ao terminar com 0, ouadditionalContext da saída JSON, e o entrega ao Claude com a próxima requisição após a troca. Além dos campos de saída JSON disponíveis para todos os hooks, você pode retornar:
Se o hook não tiver terminado dentro de cinco segundos após você enviar o próximo prompt, o Claude Code envia essa requisição sem a saída e a anexa à requisição seguinte. Se o modelo mudar várias vezes antes da próxima requisição, o Claude Code entrega apenas a saída correspondente ao modelo de destino da última troca.
SessionEnd
É executado quando uma sessão do Claude Code termina. Útil para tarefas de limpeza, registro de estatísticas da sessão ou salvamento do estado da sessão. Suporta matchers para filtrar pelo motivo de saída. O camporeason na entrada do hook indica por que a sessão terminou:
Entrada do SessionEnd
Além dos campos de entrada comuns, os hooks SessionEnd recebem um camporeason indicando por que a sessão terminou. Consulte a tabela de motivos acima para todos os valores.
systemMessage.
Os hooks SessionEnd têm um timeout padrão de 1,5 segundo. Ele se aplica quando você sai, executa /clear ou troca de sessão com o /resume interativo. Você pode dar mais tempo a um hook de duas maneiras:
timeoutpor hook: definatimeoutna configuração desse hook. O orçamento geral aumenta automaticamente para corresponder ao maiortimeoutpor hook nos seus arquivos de configurações, até 60 segundos. Se você aumentar o orçamento dessa forma, um hook sem seu própriotimeoutainda mantém o padrão. Timeouts definidos em hooks fornecidos por plugins não aumentam o orçamento.CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS: defina esta variável de ambiente em milissegundos para sobrescrever o orçamento explicitamente. O valor que você definir também se torna o timeout de cada hook sem seu própriotimeout.
CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS aumentava apenas o orçamento geral, e um hook sem seu próprio timeout ainda era cancelado após 1,5 segundo.
Elicitation
É executado quando um servidor MCP solicita entrada do usuário no meio de uma tarefa. Por padrão, o Claude Code mostra um diálogo interativo para o usuário responder. Os hooks podem interceptar essa solicitação e responder programaticamente, ignorando totalmente o diálogo. Para um hook completo com sua entrada de configurações e script, consulte Responder a uma solicitação de formulário a partir de um script. O campo matcher corresponde ao nome do servidor MCP.Entrada do Elicitation
Além dos campos de entrada comuns, os hooks Elicitation recebemmcp_server_name, message e os campos opcionais mode, url, elicitation_id e requested_schema.
Para elicitação no modo de formulário, o caso mais comum:
Saída do Elicitation
Um hook Elicitation pode responder à solicitação pelo usuário, recusá-la ou cancelá-la, ou deixá-la para o diálogo. Para responder, recusar ou cancelar, termine com 0 e imprima um objetohookSpecificOutput com uma action. O servidor recebe a sua resposta e nenhum diálogo aparece. Cada linha desta tabela mostra o que retornar para um resultado e o que o servidor MCP recebe:
Esta saída responde à solicitação no modo de formulário mostrada em Entrada do Elicitation. As chaves em
content são os nomes de propriedades do requested_schema dessa solicitação:
accept ignora o diálogo, então a URL nunca é aberta.
O Claude Code descarta reason, systemMessage e continue da saída JSON de um hook Elicitation, seja qual for a action que você retornar.
Outras maneiras de recusar uma elicitação
O seu hook também pode recusar destas maneiras. O servidor recebe o mesmodecline que para "action": "decline":
- Termina com código 2: o Claude Code ignora um
hookSpecificOutputimpresso pelo mesmo hook - Imprime um
"decision": "block"de nível superior: o bloqueio sobrescreve umaactionna mesma saída
accept ou cancel de outro.
Este script recusa solicitações no modo URL e deixa as solicitações de formulário para o diálogo:
reason.
O Claude Code ignorou um decision de nível superior dos hooks Elicitation e ElicitationResult da v2.1.105 até a correção na v2.1.284.
Responder a uma solicitação de formulário a partir de um script
Este exemplo responde a uma pergunta recorrente pelo usuário. Um servidor MCP chamadoissue-tracker pede uma chave de projeto em um formulário, e o hook preenche DOCS. O script aceita quando project_key é o único campo do formulário. Para qualquer outra solicitação, ele não imprime nada, então o diálogo aparece.
- macOS/Linux
- Windows (PowerShell)
Registre um hook de comando para o evento no seu arquivo de configurações, com o nome do servidor como matcher:Salve este script em
.claude/hooks/answer-project-key.sh no seu projeto e torne-o executável com chmod +x:claude --debug e dê ao Claude uma tarefa que faça o servidor pedir a chave do projeto. Nenhum diálogo aparece, e o log de depuração tem uma linha que termina com Elicitation resolved by hook: {"action":"accept","content":{"project_key":"DOCS"}}.
ElicitationResult
É executado depois que um usuário responde a uma elicitação MCP. Os hooks podem observar, modificar ou bloquear a resposta antes que ela seja enviada de volta ao servidor MCP. Quando um hook Elicitation responde a uma solicitação, o Claude Code envia essa resposta ao servidor sem executar hooks ElicitationResult. O campo matcher corresponde ao nome do servidor MCP.Entrada do ElicitationResult
Além dos campos de entrada comuns, os hooks ElicitationResult recebemmcp_server_name, action e os campos opcionais mode, elicitation_id e content.
Saída do ElicitationResult
Um hook ElicitationResult pode deixar a resposta do usuário passar, alterar seus valores ou bloqueá-la. Para alterar ou bloquear a resposta, termine com 0 e imprima um objetohookSpecificOutput com uma action. Cada linha desta tabela mostra o que retornar para um resultado e o que o servidor MCP recebe:
Esta saída altera a resposta mostrada em Entrada do ElicitationResult, então o servidor recebe
alice@example.com onde o usuário enviou alice:
content substitui todo o objeto content do usuário, então inclua os campos que você não está alterando. Retorne action junto com ele, porque o Claude Code ignora um hookSpecificOutput que não tenha action.
Os hooks ElicitationResult também são executados quando o usuário recusa ou cancela, e a sua action substitui a dele. Verifique se a action da entrada é accept antes de retornar accept, ou o seu hook transformará uma solicitação recusada em uma aceita. Este script faz a mesma alteração quando o usuário aceitou, mantém os outros campos e não imprime nada caso contrário:
"decision": "block" de nível superior também bloqueiam a resposta. Outras maneiras de recusar uma elicitação aborda qual deles tem efeito quando um hook os combina, o que o usuário vê e quais versões ignoravam decision.
O Claude Code descarta reason, systemMessage e continue da saída JSON de um hook ElicitationResult, seja qual for a action que você retornar.
Hooks baseados em prompt
Além de hooks de comando, HTTP e MCP tool, Claude Code suporta hooks baseados em prompt (type: "prompt") que usam um LLM para avaliar se deve permitir ou bloquear uma ação, e hooks de agente (type: "agent") que geram um verificador agentic com acesso a ferramentas. Nem todos os eventos suportam cada tipo de hook.
Eventos que suportam todos os cinco tipos de hook (command, http, mcp_tool, prompt e agent):
PermissionDeniedPostToolBatchPostToolUsePostToolUseFailurePreToolUseStopSubagentStopTaskCompletedTaskCreatedTeammateIdleUserPromptExpansionUserPromptSubmit
PermissionRequest suporta hooks command, http, mcp_tool e prompt mas não hooks agent. Se você configurar um hook de agente neste evento, Claude Code o ignora e o fluxo de permissão prossegue inalterado. Para permitir ou negar de um hook, retorne o objeto de decisão de um hook de comando ou HTTP.
Eventos que suportam hooks command, http e mcp_tool mas não prompt ou agent:
ConfigChangeCwdChangedDirectoryAddedElicitationElicitationResultFileChangedInstructionsLoadedMessageDisplayNotificationPostCompactPostModelSwitchPreCompactPreModelSwitchSessionEndStopFailureSubagentStartWorktreeCreateWorktreeRemove
SessionStart e Setup suportam hooks command e mcp_tool, e MCP tool hook fields descreve quando seus hooks mcp_tool são executados. Eles não suportam hooks http, prompt ou agent.
Como hooks baseados em prompt funcionam
Em vez de executar um comando Bash, hooks baseados em prompt:- Enviam a entrada do hook e seu prompt para um modelo Claude, por padrão aquele que Claude Code usa para funcionalidade em segundo plano
- O LLM responde com JSON estruturado contendo uma decisão
- Claude Code processa a decisão automaticamente
Configuração de hook de prompt
Definatype para "prompt" e forneça uma string prompt em vez de um command. Use o placeholder $ARGUMENTS para injetar dados de entrada do hook em seu texto de prompt.
Em um hook de prompt ou de agente, você pode escrever o prompt como uma regra sobre o que bloquear ou permitir, como “Bloquear qualquer comando Bash que leia arquivos .env”, ou como uma condição que deve ser verdadeira, como “Todos os testes unitários passam”.
Este hook Stop pede ao LLM para avaliar se todas as tarefas estão completas antes de permitir que Claude termine:
Esquema de resposta
O LLM deve responder com JSON contendo:
O que acontece em
ok: false depende do evento:
StopeSubagentStop: a razão é alimentada de volta para Claude como sua próxima instrução e o turno continua, a menos que a resposta também definaimpossible: true, caso em que Claude Code permite a parada e o turno terminaPreToolUse: a chamada de ferramenta é negada; por padrão o turno termina e a razão de negação aparece no chat como uma linha de aviso. DefinacontinueOnBlock: truepara em vez disso retornar a razão para Claude como o erro da ferramenta para que possa se ajustar e continuar, equivalente a um hook de comando compermissionDecision: "deny"PostToolUse: por padrão o turno termina e a razão aparece no chat como uma linha de aviso. DefinacontinueOnBlock: truepara alimentar a razão de volta para Claude e continuar o turno em vez dissoPostToolBatch,UserPromptSubmiteUserPromptExpansion: o turno termina e a razão aparece como uma linha de aviso. Esses eventos terminam o turno emdecision: "block"independentemente decontinuePostToolUseFailureeTaskCreated: a razão é retornada para Claude como um erro de ferramenta e o turno continua, independentemente decontinueOnBlockTaskCompleted: quando dispara porque uma tarefa é marcada como concluída durante um turno, a razão é retornada para Claude como um erro de ferramenta e o turno continua, independentemente decontinueOnBlock. Quando dispara porque um colega para, se comporta comoTeammateIdlee interrompe o colega por padrãoTeammateIdle: por padrão o colega para e a razão aparece como uma linha de aviso. DefinacontinueOnBlock: truepara alimentar a razão de volta para o colega e mantê-lo trabalhando em vez dissoPermissionRequest:ok: falsenão tem efeito. Para negar uma aprovação de um hook, use um hook de comando retornandohookSpecificOutput.decision.behavior: "deny"PermissionDenied:ok: falsenão tem efeito porque a negação já aconteceu. A única saída que este evento lê éhookSpecificOutput.retry, que hooks de prompt e agente não podem definir. Eles são executados neste evento, mas sua saída é descartada. Use um hook de comando para retornarretry
Verificar múltiplas condições antes de parar
Este hookStop usa um prompt detalhado para verificar três condições antes de permitir que Claude pare. Hooks SubagentStop usam o mesmo formato para avaliar se um subagente deve parar. Se o modelo retornar "ok": false porque a condição ainda não foi atendida, Claude continua trabalhando com a razão fornecida como sua próxima instrução:
Hooks baseados em agente
Hooks baseados em agente (type: "agent") são como hooks baseados em prompt mas com acesso a ferramentas de múltiplos turnos. Em vez de uma única chamada LLM, um hook de agente gera um subagente que pode ler arquivos, pesquisar código e inspecionar o codebase para verificar condições. Hooks de agente suportam os mesmos eventos que hooks baseados em prompt, exceto PermissionRequest.
Como hooks de agente funcionam
Quando um hook de agente dispara:- Claude Code gera um subagente com seu prompt e a entrada JSON do hook
- O subagente pode usar ferramentas como Read, Grep e Glob para investigar
- Após até 50 turnos, o subagente retorna uma decisão estruturada
{ "ok": true/false } - Claude Code permite a ação se
okfortrue. Seokforfalse, Claude Code trata o bloqueio da mesma forma que um hook de prompt comcontinueOnBlock: truenaquele evento, conforme listado em Response schema
Configuração de hook de agente
Definatype para "agent" e forneça uma string prompt, usando $ARGUMENTS como placeholder para a entrada JSON do hook. Os campos de configuração são os mesmos que prompt hooks, exceto que hooks de agente têm um timeout padrão mais longo de 60 segundos e nenhum campo continueOnBlock.
O esquema de resposta é { "ok": true } para permitir ou { "ok": false, "reason": "..." } para bloquear. Em ok: false, Claude Code trata um hook de agente da forma que trata um prompt hook com continueOnBlock: true no mesmo evento; hooks de agente não têm campo continueOnBlock e não suportam o campo impossible do hook de prompt.
Este hook Stop verifica que todos os testes unitários passam antes de permitir que Claude termine:
Executar hooks em background
Por padrão, hooks bloqueiam a execução de Claude até que completem. Para tarefas de longa duração como deployments, suites de teste ou chamadas de API externas, defina"async": true para executar o hook em background enquanto Claude continua trabalhando. Hooks assíncronos não podem bloquear ou controlar comportamento de Claude: campos de resposta como decision, permissionDecision e continue não têm efeito, porque a ação que controlariam já completou.
Configurar um hook assíncrono
Adicione"async": true à configuração de um hook de comando para executá-lo em background sem bloquear Claude. Este campo está apenas disponível em hooks type: "command".
Este hook executa um script de teste após cada chamada de ferramenta Write. Claude continua trabalhando imediatamente enquanto run-tests.sh executa. Quando o script termina, sua saída é entregue no próximo turno de conversa:
timeout nele. Claude Code ainda impõe timeout em um hook que você executa com asyncRewake.
Claude Code entrega resultados de um hook assíncrono apenas enquanto a sessão está em execução:
- Em modo não-interativo com a flag
-p, Claude Code mata qualquer hook assíncrono ainda em execução no teardown e o finaliza com resultadocancelled - Se o trabalho do seu hook deve sobreviver a uma sessão
claude -p, inicie um processo totalmente desacoplado a partir dele
Como hooks assíncronos executam
Quando um hook assíncrono dispara, Claude Code inicia o processo do hook e imediatamente continua sem esperar que termine. O hook recebe a mesma entrada JSON via stdin que um hook síncrono. Após o processo em background sair, Claude Code entrega os camposadditionalContext e systemMessage da resposta JSON do hook ao Claude no próximo turno de conversa, exceto para saída repetida de SessionStart. Diferentemente de um systemMessage de hook síncrono, nenhum dos dois campos é mostrado para você.
Imprima a resposta JSON sozinha no stdout ou em uma linha própria:
- Sozinha no stdout: quando a resposta é o único texto no stdout, ela pode ocupar várias linhas, como a saída formatada do
jq. Ocupar várias linhas requer Claude Code v2.1.295 ou posterior. - Em uma linha própria: um hook assíncrono pode imprimir outro texto no stdout quando a resposta cabe sozinha em uma linha, por exemplo com
jq -c.
systemMessage que não seja uma string, em vez de entregá-lo. Execute com --debug para ver um aviso nomeando cada campo descartado.
Notificações de conclusão de hook assíncrono são suprimidas por padrão. Para vê-las, ative modo verbose com Ctrl+O ou inicie Claude Code com --verbose.
Executar testes após mudanças de arquivo
Este hook inicia uma suite de testes em background sempre que Claude escreve um arquivo, então relata os resultados de volta ao Claude quando os testes terminam. Salve este script em.claude/hooks/run-tests-async.sh em seu projeto e torne-o executável com chmod +x:
.claude/settings.json na raiz do seu projeto. A flag async: true permite que Claude continue trabalhando enquanto testes executam:
Limitações
Hooks assíncronos têm restrições adicionais comparados a hooks síncronos:- Saída de hook é entregue no próximo turno de conversa. Se a sessão está ociosa, a resposta espera até a próxima interação do usuário. Exceção: um hook
asyncRewakeque sai com código 2 acorda Claude imediatamente mesmo quando a sessão está ociosa. - Cada execução cria um processo em background separado.
- Um hook
SessionStartassíncrono é executado toda vez que o evento dispara. Claude Code ignora a saída do hook quando o texto deadditionalContextesystemMessagecorresponde ao que Claude recebeu por último desse hook, a menos que um hookSessionStartsíncrono tenha adicionado outro texto desde então. Claude Code entrega o texto quando ele muda, e novamente na próxima vez que o hook for executado após uma compactação ou/clear. Antes da v2.1.295, Claude Code adicionava o mesmo texto à conversa novamente a cada retomada.
Considerações de segurança
Aviso
Confiança do workspace
Claude Code verifica a confiança do workspace antes de executar qualquer hook de um arquivo de configurações. O que conta como confiável depende do tipo de sessão:- Sessão interativa: Claude Code retém hooks de todos os arquivos de configurações, incluindo seu próprio
~/.claude/settings.json, até que você aceite o diálogo de confiança do workspace para a pasta, ou para um diretório pai cuja confiança se estende a ela - Sessão
-pou SDK: Claude Code nunca mostra o diálogo e trata a pasta como confiável, então hooks confirmados no.claude/settings.jsonde um repositório são executados em uma pasta que você nunca confiou
claude -p em um repositório que você não escreveu, revise seus arquivos de configurações .claude/, comece com --bare, ou desative hooks para essa execução com --settings '{"disableAllHooks": true}'. Hooks de frontmatter em um subagente de projeto seguem uma regra mais rigorosa do que hooks de arquivo de configurações. O que é executado antes de você confiar em uma pasta lista cada tipo de conteúdo de repositório por tipo de sessão.
Melhores práticas de segurança
Mantenha essas práticas em mente ao escrever hooks:- Valide e sanitize entradas: nunca confie em dados de entrada cegamente
- Sempre cite variáveis shell: use
"$VAR"não$VAR - Bloqueie traversal de caminho: verifique
..em caminhos de arquivo - Use caminhos absolutos: especifique caminhos completos para scripts. Na forma exec, use
${CLAUDE_PROJECT_DIR}e o caminho não precisa de aspas. Na forma shell, envolva-o em aspas duplas - Pule arquivos sensíveis: evite
.env,.git/, chaves, etc.
Ferramenta Windows PowerShell
No Windows, você pode executar hooks individuais em PowerShell definindo"shell": "powershell" em um hook de comando. Claude Code auto-detecta pwsh.exe, o executável do PowerShell 7 e posterior, e volta para powershell.exe para Windows PowerShell 5.1.
Referenciar scripts por caminho em hooks do PowerShell
Para referenciar o diretório raiz do projeto a partir de um comando em forma de shell do PowerShell, escreva${CLAUDE_PROJECT_DIR} ou $env:CLAUDE_PROJECT_DIR. Claude Code reescreve os espaços reservados ${CLAUDE_PROJECT_DIR}, ${CLAUDE_PLUGIN_ROOT} e ${CLAUDE_PLUGIN_DATA} em um comando em forma de shell do PowerShell para a forma ${env:NAME} do PowerShell, independentemente de o hook estar definido em settings.json, um plugin ou uma skill. PowerShell então resolve o valor do ambiente exportado após análise, então o espaço reservado funciona dentro de strings entre aspas duplas, mas não dentro de strings entre aspas simples, onde PowerShell nunca expande variáveis.
Não escreva a forma nua $CLAUDE_PROJECT_DIR em um hook do PowerShell. PowerShell a analisa como uma variável local indefinida e a resolve para $null, o que deixa o caminho do script sem seu prefixo de diretório raiz do projeto. Claude Code não reescreve essa forma; em vez disso, registra um aviso no log de depuração.
O exemplo abaixo mostra um hook settings.json que executa um script de projeto com a forma $env::
Debug de hooks
Detalhes de execução de hook são escritos no arquivo de log de debug. Inicie Claude Code comclaude --debug-file <path> para escrever o log em um local conhecido, ou execute claude --debug e leia o log em ~/.claude/debug/<session-id>.txt. A flag --debug não imprime no terminal.
Por exemplo, um hook PostToolUse em Write cujo comando imprime hook-ran produz entradas como:
Hooks: que terminam com uma duração. No Claude Code v2.1.296 ou posterior, cada hook de comando em um evento de ferramenta, UserPromptSubmit, SessionStart, Stop e vários outros eventos deixa uma dessas linhas quando termina, independentemente do que tenha impresso. A linha fornece o nome do evento, unido por dois-pontos ao nome da ferramenta ou a outro valor com o qual o hook correspondeu, depois o comando do hook entre colchetes, o plugin de onde ele veio, se houver, como a execução terminou e quanto tempo levou, como em Hooks: PostToolUse:Write [.claude/hooks/log-write.sh] finished with status 0 (31ms). Uma execução também pode terminar como timed out after <N>ms, cancelled, moved to the background ou failed to start. Em alguns eventos, como Notification, SessionEnd e PreCompact, um hook de comando deixa, em vez disso, uma linha completed with status sem duração.
Para detalhes de correspondência de hook mais granulares, defina CLAUDE_CODE_DEBUG_LOG_LEVEL=verbose para ver linhas de log adicionais como contagens de matcher de hook e correspondência de consulta.
Para troubleshooting de problemas comuns como hooks não disparando, Stop hooks que continuam bloqueando, ou erros de configuração, consulte Limitações e troubleshooting no guia. Para um passo a passo de diagnóstico mais amplo cobrindo /context, /doctor e precedência de configurações, consulte Debug your config.