O hook já está configurado, o comando /hooks o mostra, e a partir daí começam as coisas estranhas. O(a) senhor(a) envia uma solicitação, mas a nova linha não aparece em requests.log. Ou aparece duas vezes. Às vezes é pior: uma ação automática dispara depois de qualquer edição e passa a atrapalhar o trabalho normal.
Numa situação assim não é preciso remontar toda a configuração do zero. É mais útil transformar a observação numa tarefa pequena e verificável: o que deve disparar o hook, que rastro deve ficar e qual caso ele precisa ignorar. Depois disso o Claude Code consegue conferir arquivos concretos e propor uma correção mínima.

Quando um hook deve disparar
Neste artigo analisamos os hooks do tipo comando definidos nos arquivos de configuração. Num hook assim três partes importam: o evento, a condição de disparo e o manipulador. O evento responde à pergunta "quando olhar", a condição estreita os casos que se encaixam, e o manipulador executa a ação.
Por exemplo, um registro de solicitações está ligado ao evento UserPromptSubmit. Esse evento acontece quando chega uma solicitação à sessão, antes mesmo de o modelo processá-la. Na maioria das vezes é a solicitação do(a) senhor(a), mas o Claude Code o dispara também nas rodadas que ele mesmo inicia: a próxima volta do /loop, o relatório de um subagente em segundo plano. Por isso uma linha nova no registro confirma muito pouco - o hook recebeu a solicitação e anotou, nada além disso. Essa linha não diz se o agente cumpriu a tarefa corretamente.
UserPromptSubmit não tem matcher. Se o registro precisa só de algumas solicitações, quem filtra é o próprio manipulador. Com os eventos de ferramenta a situação é outra. Por exemplo, o matcher Edit|Write seleciona ferramentas, enquanto o caminho do arquivo é conferido à parte, a partir dos dados da chamada. Um matcher com o nome de uma ferramenta não quer dizer "só arquivos dentro de src".
O evento Stop significa que o Claude terminou de responder. É um bom momento para uma notificação, mas não é prova de que o código está correto nem de que a tarefa deu certo.
Antes de corrigir qualquer coisa, anote dois cenários curtos:
- o desejado: enviar uma solicitação de teste e ver uma linha nova em
requests.log; - o indesejado: abrir o arquivo num editor comum, sem enviar uma nova solicitação ao Claude Code, e confirmar que o registro não mudou. Num registro de todas as solicitações, um segundo prompt enviado também deve gerar uma entrada; esse caso não serve como controle negativo.
Esses são os critérios de verificação. Não é preciso adivinhar de antemão a resposta exata do Claude Code.
A entrada não aparece
Comece pelo ponto onde a observação diverge da expectativa. Para o registro, isso é a ausência de uma linha nova depois da solicitação de teste. Daí em diante, siga da configuração até a ação:
- Digite
/hooksnuma sessão interativa do Claude Code e confira se a entrada necessária está carregada. Esse menu quem abre é o(a) senhor(a); o resultado da conferência é passado ao agente. - Confira o evento. O registro de solicitações deve reagir a
UserPromptSubmit, enquanto uma ação depois de alterar um arquivo costuma estar ligada a um evento de ferramenta. - Encontre o arquivo de configuração de origem. Pode ser uma configuração de usuário, de projeto ou local; compare não só os nomes, mas os comandos completos. O mesmo manipulador aparecendo em vários arquivos de configuração ao mesmo tempo não significa, por si só, dois disparos.
- Confira o comando do manipulador: o arquivo existe, o comando serve para o seu sistema operacional, um caminho com espaços não quebrou nada.
- Confira onde o resultado é gravado. Um caminho relativo depende do diretório de trabalho do processo, então o manipulador pode ter gravado o arquivo num lugar diferente de onde o(a) senhor(a) está procurando.
O caminho principal aqui passa pelo agente. Entregue a ele a observação, o resultado da conferência em /hooks e os limites da correção:
O hook UserPromptSubmit aparece em /hooks, mas depois de uma solicitação
de teste não há nenhuma linha nova em requests.log.
Encontre a configuração de origem e o manipulador. Confira o evento, o caminho
do comando, o diretório de trabalho e a criação do diretório do registro.
Mostre a causa e faça a correção mínima. Mantenha os demais hooks
e configurações como estão. Depois da correção, descreva o cenário de controle
desejado e o negativo.Peça ao agente para indicar o arquivo e as linhas exatas que ele está mudando. Assim o(a) senhor(a) vê se ele está corrigindo a configuração de origem ou uma cópia qualquer que nem chega a ser carregada.
Por exemplo, o agente descobriu isto: o manipulador escreve em logs/requests.log, mas a pasta logs/ não existe e o script não a cria. A correção mínima é criar essa pasta antes de gravar. Depois disso, confira exatamente logs/requests.log: uma solicitação de teste deve acrescentar uma entrada. Este é um exemplo de causa possível, não o diagnóstico de qualquer registro vazio.
Se a configuração está no arquivo, mas não aparece em /hooks, a causa pode estar na sintaxe do JSON, no escopo da configuração ou no fato de que os hooks agora simplesmente não rodam: a pasta do projeto não foi marcada como confiável, o disableAllHooks está ativado ou o administrador permitiu apenas hooks da política gerenciada. Hooks de arquivos de configuração diferentes se somam, em vez de substituir uns aos outros. Se a entrada está carregada, mas não deixa rastro, a atenção se desloca para o comando, os dados de entrada e o caminho de saída.
O sentido da bifurcação é simples: enquanto o Claude Code não carregou a entrada, é cedo para investigar o funcionamento do script. Quando a entrada está visível, a configuração já chegou até a aplicação, e é mais útil conferir a execução do manipulador, o JSON de entrada e o lugar onde o resultado deve aparecer.
O manipulador terminou com erro
Um hook do tipo comando recebe o JSON pela entrada padrão. Nele estão os campos comuns do evento e os dados específicos daquele evento. Para UserPromptSubmit, o texto da solicitação chega no campo prompt. Esse texto precisa ser tratado como dado. Não se deve concatená-lo com um comando shell e executá-lo: uma solicitação de teste pode conter aspas, quebras de linha e qualquer texto comum.
Peça ao Claude Code para reproduzir a execução do manipulador com uma entrada inventada. Já na solicitação, indique os casos importantes:
Confira o manipulador do hook fora da sessão, com um JSON inventado.
São necessários os casos: prompt comum e multilinha, caminho do projeto com espaços,
diretório do registro ausente e entrada inválida.
Não execute o texto do prompt como código. Mostre o comando de execução, o código
de saída, o stderr e a mudança real no arquivo de teste. Não altere o registro em uso.O código de saída ajuda a entender o que aconteceu com o próprio manipulador, mas o significado dele depende do evento. exit 0 diz que o comando do hook terminou sem erro. Isso não confirma o resultado da tarefa inteira. exit 2 pode bloquear a ação em eventos "antes", mas depois que a ferramenta foi executada, não desfaz mais o trabalho dela. Por isso, uma receita única com exit 2 não pode ser transportada entre eventos às cegas.
Se a execução isolada dá certo, mas na sessão o hook continua em silêncio, inicie o Claude Code a partir da pasta do projeto com o comando claude --debug-file hook-debug.log e repita uma solicitação de teste. Abra o hook-debug.log gerado e procure o evento, os hooks que corresponderam ao evento e o código de saída. Esse é o registro do próprio Claude Code, separado do requests.log do(a) senhor(a). Depois da conferência, encerre essa sessão de diagnóstico; para o trabalho normal, inicie o Claude Code sem a flag. O stdout comum da maioria dos eventos vai para o debug log e não precisa aparecer no transcript. As exceções dependem do evento, então linhas de diagnóstico soltas no stdout podem acabar afetando o contexto em vez de virar um log útil.
Para uma primeira análise é mais seguro escrever a marca de diagnóstico num arquivo local à parte e removê-la depois da conferência. A documentação oficial não tem uma flag dry-run universal para hooks; o modo de teste fica por conta de cada manipulador didático específico.
O hook dispara mais vezes do que deveria
Duas linhas iguais depois de uma única solicitação podem indicar que o hook foi registrado duas vezes: hooks parecidos, mas não totalmente idênticos, estão, por exemplo, na configuração de usuário e na de projeto ao mesmo tempo. Se for literalmente o mesmo comando, apenas repetido em arquivos diferentes, ele ainda assim dispara uma vez só. Cópias vindas de um plugin ou skill contam à parte, então a origem mostrada no menu também importa. Primeiro entregue ao agente o resultado de /hooks e peça para listar as entradas desse evento em todos os arquivos de configuração disponíveis. Se a configuração estiver em ordem, confira se o próprio manipulador não grava duas vezes numa única execução. Apagar a primeira linha encontrada ainda é cedo.
Outra causa comum é uma condição ampla demais. Suponha que o hook deve deixar uma marca de diagnóstico depois de alterar arquivos em src/, mas reage a cada uso de Edit e Write. Aqui são necessários dois níveis de filtro:
- o matcher seleciona as ferramentas
EditeWrite; - uma condição separada confere o caminho a partir dos argumentos da ferramenta e ignora tudo fora de
src/.
Uma conferência não substitui a outra. O matcher descarta as ferramentas que não se encaixam, depois a condição sobre os argumentos mantém só os caminhos dentro de src/. A marca de diagnóstico só aparece quando as duas conferências responderam "sim".
Um trecho da configuração pode ter esta aparência:
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "python .claude/hooks/mark-source-edit.py" }
]
}
]Este é um elemento do objeto hooks dentro de um settings.json já existente, não um documento JSON completo. A conferência do caminho deve ficar no manipulador; o script mark-source-edit.py aqui é hipotético, seu corpo não está no artigo. O comando pressupõe python disponível e execução a partir da raiz do projeto. O agente deve conferir o interpretador, o shell e o caminho na sua configuração; não convém copiar o exemplo como uma configuração pronta para uso.
Este trecho é fácil de ler como uma única frase:
- Depois de uma edição de arquivo bem-sucedida
- Se a ferramenta for Edit ou Write
- Executar mark-source-edit.py
A cadeia mostra só o que está definido na configuração. A decisão "deixar a marca ou ignorar o arquivo" já é do manipulador, depois de conferir o caminho. Por isso a presença do matcher confirma a escolha da ferramenta, mas ainda não comprova a filtragem correta de src/.
| Ação | Rastro esperado | O que confere |
|---|---|---|
Alterar src/card.js via Edit | Uma marca de diagnóstico nova | A ferramenta certa e o caminho certo passam pela condição |
Criar src/theme.css via Write | Uma marca de diagnóstico nova | A segunda operação permitida também é considerada |
Alterar README.md via Edit | Nenhuma marca nova | O arquivo fora de src/ fica excluído |
Nesta tabela, Edit e Write são ferramentas do Claude Code. Alterar um arquivo à mão no editor não as aciona e, por isso, não serve para testar um matcher assim. Antes de cada ação, marque onde termina o arquivo de diagnóstico e, depois, compare só as entradas novas.
Enquanto o limite não estiver confirmado, deixe a ação inofensiva: apenas uma marca de que disparou, sem formatação, bloqueio ou edição em massa de arquivos. Primeiro garanta que o caso desejado passa exatamente uma vez e o indesejado não passa.
Um disparo a mais sempre gera trabalho extra. Ainda assim, um comando local que só escreve num arquivo não recorre ao modelo por conta própria. Um hook do tipo prompt ou agent funciona de outro jeito e usa o modelo. Não é preciso entrar em detalhes de custo aqui, basta não misturar esses dois tipos de manipulador.
Como desativar uma reação
Se um hook está atrapalhando agora mesmo, encontre a entrada de origem dele e remova só essa entrada do array do evento correspondente. Deixe os demais hooks onde estão. Isso é desativar disparos futuros: não desfaz um comando já executado, não restaura arquivos alterados nem apaga linhas que já foram para o registro.
Antes de excluir, guarde uma cópia da entrada escolhida caso pretenda trazê-la de volta. Depois da mudança, abra /hooks novamente e confirme que essa entrada não está mais lá. Se o menu ainda mostrar a configuração antiga, encerre a sessão e abra uma nova a partir do mesmo projeto. Em seguida, execute a ação de controle e compare o registro antes e depois. Não deve haver linhas novas vindas do hook desativado.
Para desativar todos os hooks temporariamente existe a configuração "disableAllHooks": true. Mas isso é um interruptor geral, não uma forma de desligar uma única entrada. Para essa própria configuração, a prioridade dos arquivos vale: "disableAllHooks": false no arquivo do projeto sobrepõe o true das configurações de usuário do(a) senhor(a). Além disso, hooks definidos por uma política gerenciada da organização não podem ser desativados por uma configuração comum de usuário ou de projeto.
Um hook desativado deixa de disparar no futuro. Se o manipulador já alterou um arquivo, a restauração desse arquivo é feita à parte, só depois de olhar o diff ou uma versão salva.
Como delegar a correção ao Claude Code
Um bom pedido contém a observação, o evento esperado, os arquivos concretos e o limite da mudança. Isso basta para o agente investigar a configuração sem reescrever toda a automação:
Investigue o problema do hook neste projeto.
Observação: depois de uma solicitação de teste, requests.log recebe duas linhas.
/loop e subagentes em segundo plano não estão rodando nesta sessão.
Expectativa: UserPromptSubmit deve acrescentar exatamente uma linha.
Vou anexar o resultado de /hooks. Confira todas as fontes de configuração
disponíveis e o comando do manipulador.
Primeiro diga a causa e os arquivos que precisam mudar. Depois faça
a correção mínima, mantenha os demais hooks e mostre o diff.
Confira o caso desejado e o caso negativo. Depois disso, mostre
como desativar só essa reação.No final, o(a) senhor(a) deve ficar com quatro respostas claras:
- qual evento dispara o hook;
- qual condição ignora os casos indesejados;
- onde estão a configuração de origem e o manipulador;
- como desativar exatamente essa reação, sem afetar as demais.
E o roteiro de controle completo: a ação desejada deixa um único rastro esperado, a indesejada não deixa rastro, o erro do manipulador aparece num diagnóstico dirigido, e depois de desativar não surge mais nenhum rastro novo. Tudo bem concreto. É exatamente por isso que um hook assim é mais fácil de manter do que uma automação que simplesmente "às vezes faz alguma coisa".
Para conferir o comportamento, use a referência oficial de hooks e o guia prático: a interface muda junto com o Claude Code.
Comportamento conferido com a documentação oficial em 18 de setembro de 2026. Os exemplos mostram a ordem de verificação; não há um manipulador pronto aqui. Confira o comando e os caminhos no seu sistema operacional e shell.
GO TO FULL VERSION