Hooks do Claude Code são comandos (ou chamadas HTTP, prompts e alguns outros tipos de handler) que o Claude Code executa automaticamente em pontos fixos de uma sessão, como antes de uma ferramenta rodar, quando uma permissão é necessária ou quando o Claude termina de responder. Você os define na chave hooks de um arquivo de configuração como ~/.claude/settings.json. Cada hook recebe um JSON sobre o evento via stdin e pode responder pelo código de saída ou por um objeto JSON no stdout, o que permite registrar logs, enviar notificações, bloquear uma ação ou responder por você.
01Como um hook é estruturado
A configuração de um hook tem três níveis:
- O evento do hook, como
PreToolUseouStop. - Um grupo de matcher, que filtra quando ele dispara, como "só para a ferramenta Bash".
- Um ou mais handlers do hook, que é o que de fato executa.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "/path/to/lint-check.sh"
}
]
}
]
}
}
Isto roda um script de lint depois que o Claude cria ou edita um arquivo. Para adicionar um segundo evento, inclua uma chave irmã dentro do mesmo objeto hooks.
02Onde ficam os hooks
~/.claude/settings.jsonTodos os seus projetosNão, só na sua máquina.claude/settings.jsonUm projetoSim, pode ser commitado.claude/settings.local.jsonUm projetoNãohooks/hooks.json de um pluginEnquanto o plugin estiver ativadoSimHooks de arquivos diferentes se somam, em vez de se substituírem. Digite /hooks no Claude Code para ver todos os hooks ativos e de onde cada um veio.
Em uma sessão interativa, o Claude Code segura os hooks, inclusive os seus, até você aceitar o diálogo de confiança do workspace para a pasta.
03Tipos de handler
A maioria dos hooks é "type": "command", que executa um comando de shell. Existem outros quatro:
http: envia o JSON do evento via POST para uma URL e lê o corpo da resposta.mcp_tool: chama uma ferramenta em um servidor MCP que você configurou.prompt: faz uma pergunta de turno único a um modelo Claude e lê uma decisão em JSON.agent: inicia um subagente que pode ler arquivos antes de decidir (experimental).
Hooks de comando rodam com todas as suas permissões de usuário, via sh -c no macOS e no Linux e via Git Bash (ou PowerShell) no Windows. Adicione "async": true para rodar um hook em segundo plano; nesse caso, ele não pode mais tomar decisões.
04Matchers
O matcher define quais ocorrências de um evento executam o hook. Com o que ele é comparado depende do evento: o nome da ferramenta em eventos de ferramenta, o tipo de notificação em Notification, como a sessão começou em SessionStart, e assim por diante.
"*",""ou nenhum matcher corresponde a tudo.- Letras, dígitos,
_,-, espaços,|e,são tratados como nomes exatos.Edit|Writecorresponde a qualquer uma das duas ferramentas. - Qualquer outra coisa é uma expressão regular JavaScript, então
mcp__memory__.*corresponde a todas as ferramentas de um servidor MCP.
Matchers diferenciam maiúsculas de minúsculas. Alguns eventos, como Stop e UserPromptSubmit, ignoram matchers. Em eventos de ferramenta, um campo if com uma regra de permissão como "Bash(git *)" restringe ainda mais um handler específico.
05Entrada: o que seu hook recebe
Todo hook recebe um JSON via stdin com alguns campos comuns, incluindo session_id, transcript_path, cwd e hook_event_name, além de campos específicos do evento. Um hook PreToolUse para uma chamada Bash, por exemplo, também recebe tool_name e tool_input.command. Leia com jq ou qualquer parser de JSON:
#!/bin/bash
input=$(cat)
cmd=$(jq -r '.tool_input.command // empty' <<<"$input")
echo "Claude wants to run: $cmd" >> ~/claude-commands.log
exit 0
06Saída: códigos de saída e JSON
Um hook pode responder de duas formas.
Exit codes. 0 significa sucesso. 2 é um erro bloqueante: em eventos que podem bloquear, a ação é interrompida e o seu stderr vira o motivo. Qualquer outro código, incluindo o comum 1, é um erro não bloqueante, então a ação segue normalmente e você vê um aviso de erro do hook. Se o hook serve para impor uma regra, saia com 2, não com 1.
JSON no stdout. Saia com 0 e imprima um único objeto JSON para ter um controle mais fino. Alguns campos funcionam em qualquer evento, como continue: false para parar o Claude por completo. Outros são específicos de cada evento: Stop usa decision: "block" com um reason, enquanto PreToolUse e PermissionRequest colocam a decisão dentro de hookSpecificOutput. Não imprima mais nada no stdout: uma linha perdida do seu perfil de shell impede o Claude Code de ler o JSON.
07Todos os eventos de hook
SessionStartUma sessão começa ou é retomadaNão (adiciona contexto)SetupIniciado com --init-only, ou --init / --maintenance com -pNãoInstructionsLoadedUm arquivo CLAUDE.md ou .claude/rules/*.md é carregadoNãoUserPromptSubmitVocê envia um prompt, antes de o Claude vê-loSimUserPromptExpansionUm comando digitado é expandido em um promptSimPreToolUseAntes de qualquer chamada de ferramentaSimPermissionRequestUma chamada de ferramenta precisa de uma decisão de permissãoPermite ou nega via JSONPermissionDeniedO auto mode nega uma chamada de ferramentaNãoPostToolUseDepois que uma chamada de ferramenta é bem-sucedidaNão (a ferramenta já foi executada)PostToolUseFailureDepois que uma chamada de ferramenta falhaNãoPostToolBatchDepois de um lote de chamadas de ferramenta em paralelo, antes da próxima chamada ao modeloSimNotificationO Claude Code envia uma notificaçãoNãoMessageDisplayEnquanto o texto da resposta do Claude é exibidoNão (pode alterar o que é exibido)SubagentStart / SubagentStopUm subagente começa ou terminaSó SubagentStopTaskCreated / TaskCompletedUma tarefa é criada ou marcada como concluídaSimStopO Claude termina de responderSim (mantém o Claude trabalhando)StopFailureO turno termina com um erro de APINãoTeammateIdleUm colega de um agent team está prestes a ficar ociosoSimConfigChangeUm arquivo de configurações muda durante a sessãoSimCwdChangedO diretório de trabalho mudaNãoDirectoryAddedUm diretório é adicionado com /add-dirNãoFileChangedUm arquivo monitorado muda no discoNãoWorktreeCreate / WorktreeRemoveUma worktree é criada ou removidaSimPreCompact / PostCompactAntes e depois da compactação do contextoApenas PreCompactPreModelSwitch / PostModelSwitchAntes e depois da troca de modeloApenas PreModelSwitchElicitation / ElicitationResultUm servidor MCP pede uma entrada, e depois que você respondeSimSessionEndUma sessão terminaNãoA Anthropic adiciona eventos de vez em quando, então consulte a referência de hooks para ver a lista atual e os campos de entrada de cada evento.
08Quais eventos importam para notificações
Quatro eventos cobrem quase tudo que as pessoas querem ser avisadas:
Stoppara "o Claude terminou". Veja o guia do Stop hook.Notificationpara "o Claude está esperando por você", com tipos comopermission_prompteidle_prompt. Veja o guia do Notification hook.PermissionRequestpara ser avisado, ou responder, no instante em que uma permissão for necessária. Veja o guia do PermissionRequest.PreToolUsena ferramentaAskUserQuestion, para ver ou responder às perguntas de múltipla escolha do Claude. Veja como responder perguntas pelo celular.
Para uma configuração de desktop pronta para colar, comece por como receber uma notificação quando o Claude Code terminar.
09Onde o Claude Code Notifier se encaixa
O Claude Code Notifier é construído inteiramente sobre esses hooks. Sua ferramenta de linha de comando gratuita, ccn, roda no Mac, Windows e Linux. A instalação adiciona sete entradas de hook ao ~/.claude/settings.json, cada uma executando ccn hook, e faz um backup único do arquivo. O ccn roda por alguns milissegundos a cada evento e depois encerra, então nada fica rodando em segundo plano.
Sozinho, ele mostra notificações no desktop. Com o app de iPhone ou Android pareado, os mesmos hooks levam suas respostas de volta: permitir ou negar uma permissão, responder uma pergunta ou enviar a próxima instrução depois que o Claude para. Ele é independente e não é feito pela Anthropic. Se você só precisa de um log ou de uma etapa de lint, algumas linhas suas são mais simples. Detalhes na página do ccn.
10Perguntas frequentes
Como testar um hook sem esperar pelo Claude?
Passe um JSON de exemplo para o script via pipe e confira o código de saída: echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh; echo $?. Depois rode /hooks no Claude Code para confirmar que ele está registrado no evento certo.
Por que meu hook não está rodando?
As causas mais comuns são JSON inválido no settings.json (vírgulas sobrando, comentários), um matcher que não bate exatamente (eles diferenciam maiúsculas de minúsculas), um script sem permissão de execução ou uma pasta que você ainda não marcou como confiável. Inicie o Claude Code com claude --debug e leia o log de debug para ver o que foi executado. A lista completa está no checklist de solução de problemas.
Como desativar todos os hooks por um tempo?
Defina "disableAllHooks": true em um arquivo de configurações. Para pulá-los em uma única execução, inicie o Claude Code com --settings '{"disableAllHooks": true}'. Não existe uma chave para desativar um hook específico; nesse caso, você remove a entrada dele. Nenhuma das opções desativa hooks definidos pela sua organização nas configurações gerenciadas.
Qual é o timeout padrão de um hook?
Dez minutos (600 segundos) para hooks de comando, HTTP e ferramentas MCP, 30 segundos para hooks de prompt e 60 para hooks de agente. Alguns eventos usam padrões menores, e você pode definir timeout em segundos em qualquer handler.