Hooks: a única camada que garante
Um hook que nega bloqueia a ferramenta até com bypassPermissions. Hooks apertam restrição e nunca afrouxam, e é isso que os torna a camada de política.
- claude code
- hooks

Sumário
- Os 30 eventos, agrupados pelo que servem
- Cinco tipos, e dois que não são determinísticos
- A regra que faz o hook valer: aperta, nunca afrouxa
- Hooks rodam em paralelo, e isso tem consequência
- Onde o hook mora define o alcance dele
- Três hooks que valem o esforço
- Quando não usar hook
- Perguntas frequentes
- Fontes
O CLAUDE.md é contexto e o agente pode ignorar. A skill é contexto e o agente pode não invocar. O hook é comando de shell que o Claude Code executa em ponto fixo do ciclo de vida — acontece independentemente do que o modelo decidir.
Essa é a diferença que importa, e ela tem uma prova documentada: um hook PreToolUse que retorna deny bloqueia a ferramenta mesmo em modo bypassPermissions, mesmo com --dangerously-skip-permissions.
Nenhuma outra camada do Claude Code faz isso.
Os 30 eventos, agrupados pelo que servem
A maioria dos textos sobre hooks cobre dois eventos. Existem trinta.
Ciclo da sessão: SessionStart, SessionEnd, Setup, PreCompact, PostCompact, ConfigChange, InstructionsLoaded.
Ciclo do turno: UserPromptSubmit, UserPromptExpansion, Stop, StopFailure, MessageDisplay, Notification.
Ciclo da ferramenta: PreToolUse, PostToolUse, PostToolUseFailure, PostToolBatch, PermissionRequest, PermissionDenied.
Delegação: SubagentStart, SubagentStop, TeammateIdle, TaskCreated, TaskCompleted.
Ambiente: CwdChanged, DirectoryAdded, FileChanged, WorktreeCreate, WorktreeRemove.
MCP: Elicitation, ElicitationResult.
Alguns merecem destaque porque resolvem problemas que as pessoas tentam resolver de outro jeito:
InstructionsLoadeddispara quando umCLAUDE.mdou uma regra de.claude/rules/entra no contexto, inclusive nos carregamentos preguiçosos durante a sessão. É a ferramenta certa para depurar regra compathsque você não sabe se carregou.PostCompactroda depois da compactação — o lugar para reinjetar contexto que não sobrevive ao/compact.CwdChangeddispara quando o agente executa umcd. Serve para gestão reativa de ambiente, no estilo dodirenv.FileChangedobserva arquivo em disco, com omatcherdefinindo quais nomes vigiar.
Vários desses eventos existem para resolver armadilhas que degradam em silêncio.
Cinco tipos, e dois que não são determinísticos
Aqui está a parte que contraria a definição corrente de hook.
| Tipo | O que faz |
|---|---|
command | Roda comando de shell. É o padrão |
http | Faz POST dos dados do evento para uma URL |
mcp_tool | Chama ferramenta de um servidor MCP já conectado |
prompt | Avaliação de uma passada por LLM |
agent | Verificação multi-turno com acesso a ferramentas — experimental |
Os dois últimos existem para decisão que exige julgamento em vez de regra fixa.
Hook de prompt. Em vez de rodar shell, o Claude Code manda o seu prompt e os dados do evento para um modelo (Haiku por padrão), que devolve a decisão em JSON:
{
"hooks": {
"Stop": [{
"hooks": [{
"type": "prompt",
"prompt": "Verifique se todas as tarefas foram concluídas. Se não, responda {\"ok\": false, \"reason\": \"o que falta\"}."
}]
}]
}
}Com "ok": false num evento Stop, o reason volta para o Claude como próxima instrução e ele continua trabalhando. Existe uma válvula de escape importante: "impossible": true marca a condição como impossível de satisfazer, e aí o turno encerra em vez de entrar em laço.
Hook de agente. Quando a verificação exige ler arquivo ou rodar comando, o type: "agent" cria um subagente que investiga antes de decidir. Timeout padrão de 60 segundos e até 50 turnos de ferramenta.
{
"type": "agent",
"prompt": "Verifique se todos os testes unitários passam. Rode a suíte e cheque o resultado. $ARGUMENTS",
"timeout": 120
}A documentação marca hooks de agente como experimentais e recomenda hooks de comando para fluxo de produção.
O critério entre os dois: use prompt quando os dados do evento bastam para decidir; use agente quando é preciso verificar contra o estado real do código.
A regra que faz o hook valer: aperta, nunca afrouxa
Esta é a propriedade que transforma hook em camada de política.
PreToolUse dispara antes de qualquer checagem de modo de permissão, em todos os modos, inclusive dontAsk. Um hook que retorna permissionDecision: "deny" bloqueia a ferramenta em bypassPermissions e com --dangerously-skip-permissions.
Em outras palavras: dá para impor política que o usuário não consegue contornar mudando o modo de permissão. Para time com requisito de conformidade, é a única forma documentada de fazer isso.
O inverso não vale. Um hook que retorna allow:
- não burla regra de
denydas configurações - não suprime o prompt de ferramenta de conector que a organização marcou como
ask - não suprime ferramenta MCP marcada com
requiresUserInteraction
A assimetria é deliberada, e é o que torna o mecanismo confiável. Hook aperta; nunca solta.
Vale saber também que código de saída 2 bloqueia, e bloqueia forte: mesmo um JSON com permissionDecision: "allow" não sobrepõe um exit 2.
Os eventos de delegação (SubagentStart, SubagentStop, TeammateIdle) fecham o ciclo descrito em subagentes: quando delegar e quando não.
Hooks rodam em paralelo, e isso tem consequência
Quando vários hooks casam com o mesmo evento, todos rodam em paralelo e todos completam antes de o Claude Code juntar os resultados.
A consequência que pega: um hook retornando deny não impede o efeito colateral de um hook irmão.
O exemplo da documentação é claro. Dois hooks em Bash: um registra o comando num log e sai 0; o outro sai 2 para negar quando o comando contém rm -rf. Quando o Claude tenta rodar rm -rf /tmp/build, os dois executam. O comando é bloqueado, e a linha de log é escrita mesmo assim — porque o hook de log já rodou.
Para combinar decisões, a resposta mais restritiva vence, na ordem deny → defer → ask → allow. Já o texto de additionalContext é preservado de todos os hooks e entregue junto.
E há uma armadilha de concorrência: quando mais de um hook PreToolUse devolve updatedInput para reescrever os argumentos de uma ferramenta, o último a terminar vence — e a ordem é não-determinística. A recomendação oficial é não ter dois hooks modificando a entrada da mesma ferramenta.
Onde o hook mora define o alcance dele
São sete lugares possíveis, e a escolha decide quem herda a regra.
| Onde | Alcance | Compartilhável |
|---|---|---|
~/.claude/settings.json | Todos os seus projetos | Não |
.claude/settings.json | Um projeto | Sim, versionável |
.claude/settings.local.json | Um projeto | Não, fica no gitignore |
| Configuração gerenciada | A organização inteira | Sim, controlada pelo admin |
Plugin, em hooks/hooks.json | Onde o plugin estiver ativo | Sim, junto com o plugin |
| Frontmatter de skill | O resto da sessão, após a skill ser invocada | Sim, dentro do arquivo da skill |
| Frontmatter de subagente | Enquanto aquele subagente roda | Sim, dentro do arquivo do subagente |
As duas últimas linhas são as menos conhecidas e as mais interessantes.
Um hook declarado no frontmatter de uma skill é registrado quando a skill é invocada e continua valendo pelo resto da sessão. Isso permite empacotar política junto com o procedimento: a skill que faz deploy pode trazer o hook que impede escrita em produção.
Um hook declarado no frontmatter de um subagente vale só enquanto ele roda. É a forma de dar ao subagente uma restrição que não vale para a sessão principal — o exemplo da documentação valida query somente-leitura antes de deixar o subagente tocar no banco.
Para desligar tudo, "disableAllHooks": true nas configurações. Duas ressalvas: a precedência de configuração se aplica, então o arquivo do projeto pode sobrepor o seu; e hooks de configuração gerenciada continuam rodando a menos que a flag também esteja lá. É coerente com a regra de que hook aperta e não afrouxa.
O /hooks lista tudo o que está configurado, agrupado por evento — e é por onde começar quando algo dispara e você não sabe de onde veio.
Três hooks que valem o esforço
1. Filtrar saída verbosa antes que ela vire contexto. O caso de maior retorno. Em vez de o agente ler um log de 10.000 linhas para achar os erros, o hook faz o filtro e devolve só o que importa:
#!/bin/bash
input=$(cat)
cmd=$(echo "$input" | jq -r '.tool_input.command')
if [[ "$cmd" =~ ^(npm test|pytest|go test) ]]; then
filtered="$cmd 2>&1 | grep -A 5 -E '(FAIL|ERROR|error:)' | head -100"
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"allow\",\"updatedInput\":{\"command\":\"$filtered\"}}}"
else
echo "{}"
fi2. Bloquear caminho protegido. Regra que não depende do agente lembrar:
{
"hooks": {
"PreToolUse": [{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/bloqueia-protegidos.sh"
}]
}]
}
}3. Reinjetar contexto depois da compactação. Um PostCompact resolve o problema de instrução que some no meio da sessão — os CLAUDE.md aninhados e as regras com paths não são reinjetados sozinhos.
Para verificar se um hook está ativo, /hooks mostra se ele aparece sob o evento correto. E claude --debug mostra modified tool input keys quando um hook reescreve o comando.
Quando não usar hook
Quando a decisão exige contexto da conversa. Hook de comando se comunica só por stdout, stderr e código de saída. Ele não enxerga o que foi discutido.
Quando você precisa desfazer. PostToolUse roda depois que a ferramenta já executou. Não existe rollback.
Quando "sempre" não é sempre. O Stop dispara toda vez que o Claude termina de responder, não só quando a tarefa acabou. E ele não dispara em interrupção do usuário — erro de API dispara StopFailure, que é outro evento.
Quando o custo de latência não compensa. Os timeouts variam: command, http e mcp_tool têm 10 minutos, mas UserPromptSubmit cai para 30 segundos e MessageDisplay para 10. Hook de prompt tem 30 segundos e o de agent, 60. Os de SessionEnd dividem um orçamento de 1,5 segundo.
E uma nota de depuração que economiza tempo: matchers são case-sensitive. Metade dos "meu hook não dispara" é o nome da ferramenta com a caixa errada.
Vale lembrar que hook também chega de fora: um plugin instalado pode registrar os próprios. O que checar antes está em plugins e marketplaces.
Perguntas frequentes
Hook é melhor que instrução no CLAUDE.md?
São camadas diferentes. O CLAUDE.md orienta comportamento e o agente pode não seguir. O hook executa em ponto fixo do ciclo, independentemente do modelo. Use CLAUDE.md para convenção e hook para o que precisa de garantia.
Dá para impedir que alguém desative meus hooks trocando o modo de permissão?
Sim, e essa é a propriedade central. PreToolUse dispara antes da checagem de modo, então um deny vale mesmo em bypassPermissions e com --dangerously-skip-permissions. O caminho inverso não existe: hook não afrouxa restrição de configuração.
Meu hook não dispara. Por onde começo?
Três checagens, nessa ordem: /hooks confirma que ele aparece sob o evento certo; o matcher precisa casar o nome da ferramenta exatamente, com a mesma caixa; e o evento precisa ser o certo — PreToolUse antes, PostToolUse depois.
Hook de prompt não deixa o mecanismo não-determinístico?
Deixa, e é intencional. Os tipos prompt e agent existem para decisão que exige julgamento. Quando você precisa de garantia determinística, o tipo é command com código de saída — e a documentação recomenda exatamente isso para fluxo de produção.
Fontes
- Anthropic — Claude Code Docs: Automate actions with hooks. Acesso em 20/08/2026.
- Anthropic — Claude Code Docs: Hooks reference. Acesso em 20/08/2026.
- Anthropic — Claude Code Docs: Manage costs effectively. Acesso em 19/08/2026.
- Anthropic — Claude Code Docs: How Claude remembers your project. Acesso em 19/08/2026.
- Anthropic — Claude Code Docs: Sub-agents. Acesso em 20/08/2026.
Verificado em 20 de agosto de 2026.
Gatilho de reavaliação: revisar quando (a) hooks de agente saírem do estágio experimental, (b) mudar a lista de 30 eventos ou os timeouts por tipo, ou (c) a precedência entre hook e modo de permissão for alterada — hoje ela é o que sustenta o uso de hook como camada de política.
Leia também
Plugins e marketplaces: como avaliar antes de instalar
A documentação diz que plugin executa código arbitrário com seus privilégios. O checklist de cinco minutos usando as ferramentas que já vêm no Claude Code.
- claude code
- plugins
Permissões e auto mode: o que liberar e o que travar
Deny vence ask, que vence allow, e especificidade não muda nada. As três camadas de permissão do Claude Code e as regras que parecem proteger sem proteger.
- claude code
- permissões
Slash commands: transformar processo em comando
Comando personalizado virou skill. O que muda: argumentos posicionais, injeção de contexto antes do agente ver, e empilhamento de até seis numa mensagem.
- claude code
- slash commands


