Pular para o conteúdo principal

Hooks: Automação Determinística

Avançado

Hooks são comandos de shell que o Claude Code executa automaticamente em pontos definidos do seu ciclo de vida. Enquanto as permissões decidem se uma ação é permitida, os hooks permitem que você execute uma lógica determinística em torno dela — formatação, validação, registro de logs, barreiras. É assim que você torna o comportamento garantido em vez de "por favor, lembre-se de".

What you'll learn
  • Quando recorrer a um hook em vez de uma instrução ou uma permissão
  • Como um hook é configurado: evento, matcher e o payload JSON no stdin
  • As duas formas pelas quais um hook bloqueia uma ação — código de saída 2 vs JSON no stdout
  • As boas práticas e os erros comuns que separam hooks rápidos e seguros dos lentos e silenciosos

Quando recorrer a um hook

Recorra a um hook quando quiser que um comportamento seja garantido, não apenas solicitado. Cada tarefa comum mapeia para um evento do ciclo de vida:

  • Formatar / fazer lint automaticamente após cada edição de arquivo (PostToolUse).
  • Bloquear uma ação que viola uma regra antes que ela seja executada (PreToolUse).
  • Notificar ou registrar em log quando uma sessão termina ou uma tarefa é concluída (Stop).
  • Injetar contexto no início da sessão.
Eventos de hook em resumo
Pressione Enter ou Espaço para virar o cartão. Use as setas esquerda e direita para navegar entre os cartões.Termo exibido.
1 / 4

Como funcionam

Você registra hooks em settings.json, associando um evento (e, muitas vezes, um matcher de ferramenta). Quando o evento dispara, o Claude executa seu comando, passando um payload JSON no stdin (o nome da ferramenta, suas entradas, a sessão). O código de saída e a saída do seu comando decidem o que acontece em seguida.

Guided walkthrough1 of 4
  1. Registre o hook em settings.json sob o evento do ciclo de vida que lhe interessa — por exemplo, PostToolUse.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }
]
}
]
}
}

O hook acima lê o caminho do arquivo editado a partir do JSON de stdin (.tool_input.file_path) e o formata. Não presuma que uma variável de ambiente contém o caminho — leia-o do stdin. Placeholders de caminho úteis como ${CLAUDE_PROJECT_DIR} estão disponíveis para localizar scripts.

Como um hook bloqueia

Duas formas, dependendo do evento:

  • Código de saída 2 — o hook faz a ação falhar e o que quer que ele tenha escrito no stderr se torna a mensagem que o Claude vê. Simples e funciona para hooks de comando.
  • JSON no stdout (saída 0) — retorne uma decisão estruturada. Para PreToolUse, isso é uma permissionDecision de deny; para PostToolUse/Stop/etc. é {"decision": "block", "reason": "…"}.

O script abaixo é um hook PreToolUse na ferramenta Bash. Leia-o de cima para baixo: ele extrai o comando do stdin e, se ele parecer destrutivo, escreve uma razão no stderr e sai com código 2 para bloquear.

#!/usr/bin/env bash
# PreToolUse hook on the Bash tool: refuse to delete things.
command=$(jq -r '.tool_input.command' < /dev/stdin)
if [[ "$command" == rm\ * || "$command" == *"rm -rf"* ]]; then
echo "Blocked: destructive 'rm' is not allowed by policy." >&2
exit 2
fi
exit 0

O modelo mental

Um hook PreToolUse roda antes da ação e pode bloqueá-la; um hook PostToolUse roda depois que ela tem sucesso e reage ao resultado.

Boas práticas

  • Mantenha os hooks rápidos e idempotentes — eles rodam muito.
  • Falhe de forma ruidosa em problemas reais, mas não bloqueie por questões cosméticas.
  • Trate a saída do hook como feedback para o Claude — uma mensagem clara o ajuda a se autocorrigir.
  • Hooks rodam com os privilégios do seu shell — revise qualquer hook que você não escreveu (Revisando Código de Terceiros).

Erros comuns

  • Ler o caminho do arquivo a partir de uma variável de ambiente. O caminho vive no JSON de stdin (.tool_input.file_path), não em $CLAUDE_FILE_PATH. Encaminhe o stdin através do jq.
  • Bloqueios silenciosos. Se um hook PreToolUse sai com código 2 sem nada no stderr, o Claude é bloqueado, mas não sabe por quê e não consegue se adaptar. Sempre escreva uma razão clara.
  • Hooks lentos. Um hook PostToolUse roda após cada edição correspondente. Um linter de 3 segundos faz toda a sessão parecer lenta — mantenha os hooks rápidos e, idealmente, atue apenas sobre o que mudou.
  • Matchers excessivamente amplos. matcher: ".*" dispara em cada ferramenta. Restrinja com um nome exato, uma lista Edit|Write, ou o campo if por handler (ex.: "if": "Bash(git push *)").
  • Confiar em hooks que você não escreveu. Um hook executa shell arbitrário com os seus privilégios. Revise primeiro qualquer hook vindo de um plugin ou template — veja Revisando Código de Terceiros.
Watch out
  • Um hook executa shell arbitrário com os seus privilégios — nunca configure um hook de um plugin ou template sem lê-lo primeiro.

Modelos prontos para copiar e colar estão em Receitas de Hooks e settings.json.

Formatar automaticamente arquivos editados (PostToolUse em Edit|Write)

{
"hooks": {
  "PostToolUse": [
    {
      "matcher": "Edit|Write",
      "hooks": [
        { "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }
      ]
    }
  ]
}
}

Teste seus conhecimentos

0/3
  1. Onde um hook encontra o caminho do arquivo que acabou de ser editado?
  2. Um hook PreToolUse sai com código 2. O que acontece?
  3. Por que o matcher ".*" é considerado um erro comum?
Key takeaways
  • Hooks tornam o comportamento garantido, não solicitado — eles executam lógica determinística em torno de ações que as permissões apenas permitem ou negam.
  • Registre um hook em settings.json contra um evento mais um matcher; o Claude canaliza um payload JSON no stdin e lê seu código de saída e sua saída.
  • Leia o caminho do arquivo do stdin (.tool_input.file_path) — não de uma variável de ambiente.
  • Bloqueie com o código de saída 2 (o stderr se torna a mensagem) ou com JSON estruturado no stdout (saída 0); sempre inclua uma razão clara.
  • Mantenha os hooks rápidos, idempotentes e estreitamente associados — e revise qualquer hook que você não escreveu, já que ele roda com os privilégios do seu shell.

Próximos passos