Hook é um comando que o Claude Code roda sozinho, num ponto fixo do trabalho dele. A diferença para escrever no CLAUDE.md: instrução no CLAUDE.md a IA pode esquecer. Hook não. Ele sempre roda.
Tudo vai em ~/.claude/settings.json (global) ou .claude/settings.json (do projeto).
1. Ser avisado quando ele para e espera você
O caso mais comum: você manda a tarefa, vai fazer outra coisa, e volta vinte minutos depois — ele estava parado esperando você responder.
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "notify-send 'Claude Code' 'Precisa de voce'"
}
]
}
]
}
}
- Linux:
notify-send(já vem na maioria das distros) - macOS:
osascript -e 'display notification \"Precisa de voce\" with title \"Claude Code\"'
2. Formatar o código depois de toda edição
Sem hook, você pede "formata antes de terminar" e às vezes ele formata. Com hook, formata sempre.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "npx prettier --write ." }
]
}
]
}
}
O matcher filtra por ferramenta: só dispara quando ele edita ou escreve arquivo.
3. Impedir que segredo vá para o commit
Este é o que mais paga o esforço. Um script que lê o comando prestes a rodar e
recusa se for git commit com arquivo de credencial dentro.
~/.claude/hooks/block-secret-commit.sh:
#!/usr/bin/env bash
entrada=$(cat)
comando=$(printf '%s' "$entrada" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("tool_input",{}).get("command",""))')
case "$comando" in
*git\ commit*)
if git diff --cached --name-only | grep -qE '(^|/)\.env$|\.pem$|credentials\.json$'; then
echo "Bloqueado: ha arquivo de credencial no commit." >&2
exit 2
fi
;;
esac
exit 0
Registro:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "~/.claude/hooks/block-secret-commit.sh" }
]
}
]
}
}
Saia com código 2 para bloquear. É o número que o Claude Code entende como
"não faça isso" — qualquer outro código ele trata como aviso e segue em frente.
Não esqueça o chmod +x no script.
4. Carregar contexto sempre que a sessão abre
{
"hooks": {
"SessionStart": [
{
"matcher": "",
"hooks": [
{ "type": "command", "command": "git log --oneline -10" }
]
}
]
}
}
O que o script imprime entra no contexto. Serve para ele começar sabendo os últimos commits, o estado do banco, a fila de tarefas — o que for seu caso.
Como o hook conversa com o Claude Code
- Ele recebe JSON pelo stdin com o que está acontecendo (
tool_input,tool_name, etc.). - Código de saída 0 = seguiu tudo bem.
- Código de saída 2 = bloqueia a ação, e o texto do
stderrvolta para o Claude ler. - Qualquer outro código = aviso, não bloqueia.
Os eventos que existem
São mais de vinte. Os que resolvem quase tudo:
| Evento | Dispara quando |
|---|---|
SessionStart | a sessão abre |
UserPromptSubmit | você manda uma mensagem |
PreToolUse | antes de usar uma ferramenta (dá para bloquear) |
PostToolUse | depois de usar uma ferramenta |
Notification | ele precisa da sua atenção |
Stop | ele termina a resposta |
SessionEnd | a sessão fecha |
Lista completa e o formato de cada um: docs.claude.com/en/docs/claude-code/hooks
Depois de configurar
Rode /hooks dentro do Claude Code para conferir que ele enxergou.
Se o menu vier vazio, o JSON está malformado ou está no arquivo errado.
Guia do @vinn_ai