Skip to main content

Hooks

Hooks são comandos shell, endpoints HTTP ou prompts LLM que executam automaticamente em pontos específicos do ciclo de vida do Claude Code. Diferente do CLAUDE.md, que é instrução textual e portanto sujeita à interpretação do modelo, hooks são determinísticos: se você configurou, vai rodar.

Use hook quando precisar de garantia. "Sempre formate código depois de editar" no CLAUDE.md é uma sugestão. Um PostToolUse que roda prettier é uma certeza.

Onde Configurar

Hooks vivem em arquivos de settings JSON, na mesma hierarquia das outras configurações:

LocalEscopo
~/.claude/settings.jsonTodos os projetos
.claude/settings.jsonProjeto, versionado
.claude/settings.local.jsonProjeto, gitignored
Plugin hooks/hooks.jsonQuando o plugin está habilitado
Skill/Agent frontmatterEnquanto o componente está ativo
Managed policy settingsToda a organização

Estrutura de um Hook

Três níveis de aninhamento:

{
"hooks": {
"EventName": [
{
"matcher": "ToolName|OutroTool",
"hooks": [
{
"type": "command",
"command": "/caminho/pro/script.sh"
}
]
}
]
}
}

Tipos de Handler

TipoO que faz
commandExecuta script shell, recebe JSON via stdin
httpManda POST com payload JSON
promptAvaliação LLM single-turn (ex: "isso é seguro?")
agentSpawna subagente pra verificar (experimental)

Eventos Principais

Os hooks disparam em diferentes cadências:

Por sessão

  • SessionStart - quando a sessão começa ou retoma
  • SessionEnd - quando termina

Por turno

  • UserPromptSubmit - antes do Claude processar seu prompt
  • Stop - quando o Claude termina de responder
  • StopFailure - quando termina com falha

Por tool call

  • PreToolUse - antes de executar qualquer tool
  • PostToolUse - depois de executar com sucesso
  • PostToolUseFailure - depois de executar com falha
  • PermissionRequest - quando aparece dialog de permissão
  • PermissionDenied - quando o classificador do auto mode bloqueia

Assíncronos

  • FileChanged - quando um arquivo monitorado muda
  • CwdChanged - quando o working directory muda
  • InstructionsLoaded - quando CLAUDE.md ou rules carregam
  • PreCompact / PostCompact - antes e depois de compactação
  • SubagentStart / SubagentStop - lifecycle de subagentes
  • Notification - notificações (idle, permission prompt)

Exemplos Práticos

Bloquear comandos destrutivos

{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/block-rm.sh"
}
]
}
]
}
}

E o script:

#!/bin/bash
COMMAND=$(jq -r '.tool_input.command')

if echo "$COMMAND" | grep -q 'rm -rf'; then
jq -n '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "rm -rf bloqueado"
}
}'
else
exit 0
fi

Lint automático após editar

{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "npm run lint --silent || true"
}
]
}
]
}
}

Carregar contexto do projeto no início

{
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/load-context.sh"
}
]
}
]
}
}
#!/bin/bash
CONTEXT="Issues abertas: $(gh issue list --json title | jq -r '.[].title' | head -3)"
jq -n --arg ctx "$CONTEXT" '{
hookSpecificOutput: {
hookEventName: "SessionStart",
additionalContext: $ctx
}
}'

Filtrar output de teste para economizar tokens

Esse aqui é um dos mais valiosos. Em vez do Claude receber 10.000 linhas de output de teste, você devolve só as falhas:

{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/filter-test-output.sh"
}
]
}
]
}
}
#!/bin/bash
input=$(cat)
cmd=$(echo "$input" | jq -r '.tool_input.command')

if [[ "$cmd" =~ ^(npm test|pytest|go test) ]]; then
filtered_cmd="$cmd 2>&1 | grep -A 5 -E '(FAIL|ERROR|error:)' | head -100"
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"allow\",\"updatedInput\":{\"command\":\"$filtered_cmd\"}}}"
else
echo "{}"
fi

Auto-aprovar comandos seguros

{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"if": "Bash(git status|git log|git diff)",
"command": "exit 0"
}
]
}
]
}
}

Decision Control

Hooks podem influenciar o que acontece a seguir através do JSON que retornam. As principais decisões pra PreToolUse:

DecisãoEfeito
allowAprova a tool sem perguntar
denyBloqueia
askForça dialog de permissão
deferDeixa em aberto (pra UIs externas)
updatedInputModifica o input antes de executar

Precedência: deny > defer > ask > allow.

Exit Codes (para command hooks)

CódigoSignificado
0Sucesso, parseia stdout como JSON
2Erro bloqueante, ignora JSON, usa stderr
OutroErro não-bloqueante, loga stderr e continua

Variáveis de Ambiente

Disponíveis nos scripts:

VariávelO que é
$CLAUDE_PROJECT_DIRRaiz do projeto
${CLAUDE_PLUGIN_ROOT}Diretório do plugin (se aplicável)
${CLAUDE_PLUGIN_DATA}Diretório de dados persistentes do plugin

Matchers

Controlam quando o hook dispara:

PatternComportamento
"*", "", omitidoMatch em tudo
Bash ou Edit|WriteExact match ou lista
^Notebook ou mcp__.*Regex

Para tools MCP o padrão é mcp__<servidor>__<tool>. Exemplo: mcp__memory__.* mata todas as tools do servidor memory.

O Comando /hooks

Digite /hooks no Claude Code pra ver um browser read-only com:

  • Todos os eventos configurados
  • Quantos hooks por evento
  • Detalhes de matchers
  • Configuração completa de cada handler
  • Source (User, Project, Local, Plugin, Session, Built-in)

Útil pra debug quando você não tem certeza do que está rodando.

O Claude Pode Escrever Hooks Pra Você

Tente prompts como:

  • "Escreva um hook que roda eslint depois de cada edit de arquivo"
  • "Escreva um hook que bloqueia escritas na pasta migrations"
  • "Escreva um hook que filtra output do pytest pra mostrar só as falhas"

Ele edita seu settings.json e cria os scripts. Você revisa, testa, commita.

Best Practices

Hooks de produção precisam ser rápidos

Cada hook adiciona latência. Hooks pesados (que rodam test suites inteiras, por exemplo) podem ir pro SessionStart (uma vez por sessão) em vez de PostToolUse (a cada edit).

Use PreToolUse pra modificar input

Reescrever o comando do Bash pra filtrar output, redirecionar pra log, ou adicionar timeouts é uma forma poderosa de economizar tokens e proteger o sistema sem precisar bloquear nada.

Versione os hooks que importam pro time

.claude/settings.json e os scripts em .claude/hooks/ no git. Cada dev clona, e o setup já está aplicado.

.claude/settings.local.json pra preferências pessoais

Configurações que são suas (allowlists pessoais, hooks de produtividade individual) ficam aí. Não vão pro git.

Hooks gerenciados pra compliance

Em organização, settings managed forçam hooks que usuários não conseguem desabilitar. Útil pra garantir audit logs, bloqueios de segurança, validação obrigatória.

Conclusão

Hook é a forma de transformar uma instrução ("sempre faça X") em garantia ("X sempre acontece"). Use pra:

  • Validar antes de comandos perigosos
  • Filtrar output verboso e economizar tokens
  • Carregar contexto dinâmico no começo da sessão
  • Forçar formatação, lint, ou testes em momentos certos
  • Audit trail de comandos sensíveis

Combinado com skills e subagents, hooks fecham o ciclo de automação determinística.


Próximo: MCP e Integrações

Referências: