Hooks (Gatilhos de Terminal): Automações de Eventos
📚 Navegação da Série: O artigo anterior 32 Estilos de Exibição (Output Styles) ensinou a redefinir a persona do console. Este capítulo aborda outro nível de automação—não para moldar a conversação, mas para disparar scripts locais obrigatoriamente no instante em que eventos de terminal ocorrem: formatar códigos automaticamente após edições, bloquear comandos perigosos com segurança ou emitir alertas na conclusão do chat. Apresentamos os Hooks.
Imagine este cenário: em uma única semana, você teve que executar o comando prettier --write manualmente 23 vezes após edições do Claude.
Vinte e três execuções repetitivas de um mesmo comando. Para piorar, duas vezes você esqueceu de rodar o formatador local—fazendo com que a integração contínua (CI) rejeitasse os commits devido a erros de estilização, exigindo refazer o fluxo.
Diante disso, surge a questão: por que depender da sua memória ou esperar que o Claude lembre de rodar tarefas repetitivas de forma espontânea? Pedir no CLAUDE.md para "rodar o prettier após alterar arquivos" falha eventualmente, pois trata-se de uma recomendação contextual (soft request), não de uma garantia física.
A implementação de um Hook resolve essa demanda com uma linha de configuração: a partir desse momento, toda modificação de arquivos executada pelo Claude disparará a formatação de forma autônoma, eliminando as chamadas manuais e os bloqueios no CI. Explicaremos neste artigo a sintaxe e a depuração de Hooks locais.
Ao terminar este artigo, você obterá:
- O conceito real de Hooks e a diferença estrutural em relação a orientações do
CLAUDE.md - Os gatilhos de eventos do ciclo de vida do terminal (
PreToolUse,PostToolUse,Stop,SessionStart) - Onde salvar os arquivos de Hooks e como usar o parâmetro
matcherpara filtrar execuções - Três modelos prontos para reuso: formatação automática, bloqueio de comandos bash perigosos e alertas de sistema
- O canal de comunicação entre o console e os scripts (via stdin em JSON, códigos de saída e stdout)
- Roteiro de diagnóstico de erros e falhas de acionamento de Hooks
01 O que são Hooks e a garantia física de execução
Conclusão direta: Um Hook é um script ou comando local executado obrigatoriamente quando um evento de ciclo de vida específico ocorre no terminal—ele independe do raciocínio da IA para rodar. A documentação oficial sinaliza:
Hooks são comandos shell definidos pelo usuário que são executados em pontos específicos no ciclo de vida do Claude Code. Eles fornecem controle determinístico sobre o comportamento do Claude Code, garantindo que certas ações sempre ocorram, em vez de depender do LLM para decidir executá-las.
Os termos "controle determinístico" e "garantindo que certas ações sempre ocorram" são a base dos Hooks.
Analogia: Automação residencial. Em rotinas de automação, você define regras lógicas do tipo "se a porta se abrir, acenda a lâmpada da sala" ou "se eu me afastar 100m da casa, desligue o aquecedor". O gatilho ocorre em nível físico de sensores, sem depender de comandos manuais. O Hook funciona como essa regra no Claude Code—se o evento ocorrer, o script correspondente roda obrigatoriamente.
Entenda a distinção: diretrizes no CLAUDE.md são recomendações textuais (soft requests) que dependem da interpretação da IA; Hooks são imposições físicas (hard constraints) de infraestrutura locais. O manual oficial esclarece:
Instruções como "nunca edite o .env" no CLAUDE.md ou em skills são apenas pedidos, não garantias. Um hook PreToolUse que impede a edição é uma imposição física.
Isso resolve os esquecimentos de lints: usar arquivos de texto para pedir formatação gera falhas; Hooks locais garantem a execução sempre.
Casos de uso comuns adequados para Hooks:
- Formatação de arquivos pós-edição: rodar formatações e lints automaticamente.
- Proteção de segurança de terminal: bloquear comandos bash perigosos como
rm -rf. - Notificações de conclusão: emitir alertas de sistema ao concluir tarefas demoradas.
💡 Resumo em uma frase: Um Hook é um script disparado por eventos que transforma recomendações contextuais do
CLAUDE.mdem execuções de terminal obrigatórias e determinísticas.
02 Gatilhos e eventos do ciclo de vida
Os Hooks são acionados em pontos específicos do fluxo de execução do Claude Code, denominados eventos (events). Você deve escolher o evento de acordo com a finalidade do seu script.
No Artigo 03, vimos que o Claude Code executa em um loop contínuo de raciocínio, ação e inspeção. Os eventos mapeados pela documentação oficial dividem-se em três frequências de disparo:
- Uma vez por sessão:
SessionStart(inicialização ou retomada do chat) eSessionEnd(encerramento do console). - Uma vez por interação (rodada de prompt):
UserPromptSubmit(entrada de dados enviada) eStop(conclusão da resposta do assistente). - A cada chamada de ferramenta (tool calls):
PreToolUse(antes da execução da ferramenta) ePostToolUse(após a conclusão do comando).
O diagrama abaixo ilustra o momento exato de disparo desses gatilhos no fluxo de conversação:

Ao iniciar o terminal, o SessionStart é chamado. Quando você envia um prompt, roda o UserPromptSubmit. A fase de execução dispara PreToolUse (para validações) e PostToolUse (para lints) a cada ferramenta chamada. Na conclusão da resposta, o Stop é acionado.
Embora a API de Hooks suporte dezenas de eventos secundários de sistema (como modificações de arquivos físicas ou inicializações de subagentes), o desenvolvimento de fluxos foca nestes quatro cenários padrão:
| Evento de Gatilho | Momento de acionamento | Caso de uso recomendado |
|---|---|---|
PreToolUse | Antes de uma ferramenta ou comando rodar | Bloqueio de comandos inseguros e proteção de arquivos (permite interromper a execução). |
PostToolUse | Após a conclusão bem-sucedida de um comando | Formatação de arquivos automática (Prettier, ESLint). |
Stop | Ao finalizar a resposta e liberar o chat | Notificações de fim de tarefas e monitoramento de dependências locais. |
SessionStart | Na inicialização do console do Claude Code | Injeção de dados contextuais locais (ex: logs recentes de builds). |
Observe os prefixos: eventos Pre (como PreToolUse) ocorrem antes da ferramenta rodar, permitindo abortar a operação; eventos Post ocorrem após o comando finalizado, servindo para lints locais, mas incapazes de prevenir a execução.
💡 Resumo em uma frase: Hooks amarram scripts a eventos de ciclo de vida do terminal; utilize
PreToolUsepara proteções e validações pré-execução ePostToolUsepara lints e limpezas.
03 Caminhos de gravação e o uso de matchers
Os Hooks são declarados no arquivo central settings.json, e a camada selecionada determina o escopo de atuação, alinhado ao Artigo 31:
| Arquivo JSON de destino | Escopo de ação do Hook | Versionamento (Git) |
|---|---|---|
~/.claude/settings.json | Global do usuário em qualquer repositório | Não (raiz do sistema local) |
.claude/settings.json | Apenas o projeto/repositório ativo | Sim (versionado no git) |
.claude/settings.local.json | Apenas o projeto ativo (sobrescrita local) | Não (ignorado pelo gitignore) |
Siga as regras de camadas: scripts de formatação coletivos do repositório devem ser versionados em .claude/settings.json; avisos do monitor ou rotinas experimentais de máquina salvam-se nas pastas privadas.
Estrutura lógica de gravação
Abaixo está o modelo completo que gerencia formatações locais via Prettier após o Claude editar arquivos, salvo no .claude/settings.json do projeto:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}
]
}
]
}
}O JSON organiza-se em três níveis:
- O evento de gatilho: chave
PostToolUse(após execução de ferramentas). - O filtro de acionamento: chave
matcherlimitada aos editoresEditouWrite(evita rodar o linter em leituras ou consultas bash). - A ação do script: chave
type("command") indicando a chamada bash declarada emcommand.
O comando utiliza o analisador jq para ler os argumentos fornecidos pelo terminal do Claude, capturando o caminho físico do arquivo modificado e direcionando-o ao Prettier.
O parâmetro matcher
A chave matcher atua como o filtro de segmentação. Se omitida, o script rodará em qualquer comando acionado pelo console; se declarada, ela restringe o disparo.
Analogia: A portaria do condomínio. Sem critérios específicos, a portaria precisará barrar e interrogar qualquer carro na rua. Usar o matcher é como instruir a portaria: "só examine vans de transporte de carga; veículos normais de moradores podem passar sem inspeção". Isso otimiza o fluxo de compilação.
Padrões suportados para chaves de ferramentas:
| Sintaxe do matcher | Comportamento de busca | Exemplo de acionamento |
|---|---|---|
"Edit|Write" | Mapeia termos usando o operador lógico OR | Disparado apenas após editores. |
"Bash" | Mapeia o termo exato | Disparado apenas em execuções de console. |
"" ou omitido | Sem filtros (coringa de acionamento) | Dispara em toda e qualquer chamada de console. |
Atenção: o filtro matcher diferencia maiúsculas de minúsculas (case-sensitive). Escrever edit fará com que o editor Edit seja ignorado. Mantenha as chaves padronizadas.
Eventos de contexto (como Stop ou SessionStart) não lidam com chamadas de console e, por isso, não possuem parâmetros de matcher. Inserir o campo nesses blocos não terá efeito.
💡 Resumo em uma frase: Hooks residem no
settings.jsonestruturados em: Evento, Matcher e Script de ação; os filtros de ferramentamatcherdiferenciam maiúsculas de minúsculas.
04 Integração técnica de entrada e saída: stdin, stdout e códigos de erro
Compreender o canal de comunicação entre os binários do terminal e seus scripts é a base para o desenvolvimento de Hooks de segurança e lints avançados.
O fluxo baseia-se em três canais locais: o console do Claude injeta dados contextuais em formato JSON via entrada padrão (stdin) → seu script lê e processa as regras locais → a resposta é retornada via saída padrão (stdout) e códigos de erro.
Entrada: O payload JSON enviado via stdin
No instante de ativação do Hook, o console injeta as chaves do evento ativo no stdin. Exemplo de payload enviado ao PreToolUse de um comando bash:
{
"session_id": "abc123",
"cwd": "/Users/sarah/myproject",
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": {
"command": "npm test"
}
}O JSON detalha os parâmetros e o comando que a IA está tentando acionar. Com a chamada jq -r '.tool_input.file_path', seu script lê essa árvore, captura o caminho físico do arquivo e descarta formatações de aspas secundárias.
Saída: Códigos de retorno do terminal
Seu script orienta os próximos passos do console usando códigos de saída (exit code). Três estados padrão do terminal devem ser gerenciados:
| Código de Saída | Significado técnico | Comportamento no console |
|---|---|---|
0 | Execução bem-sucedida | O console prossegue para a chamada (sem pular telas de permissões padrão). |
2 | Interromper/Bloquear | O comando é abortado no console; logs enviados no stderr são reportados à IA. |
| Outros (ex: 1) | Erro interno não fatal | O terminal exibe um alerta de Hook, mas prossegue a execução. |
Importante: use exit 2 para interromper execuções. O uso do código 1 comum do Unix causará comportamentos incorretos:
Para a maioria dos eventos de hook, apenas o código de saída 2 impede a operação. O Claude Code trata o código de saída 1 como um erro não bloqueante e continua a operação, embora o 1 seja o código tradicional de falha do Unix. Se o seu hook for projetado para aplicar políticas, use
exit 2.
Se o script detectar perigo e precisar bloquear a escrita local, retorne exit 2. Usar exit 1 apenas registrará um alerta de erro nos logs de depuração locais, sem parar o comando.
Além de isso, apenas eventos preventivos (tipo PreToolUse) evitam a gravação. Disparar exit 2 no PostToolUse não reverterá alterações, pois os dados já foram salvos no disco.
Respostas estruturadas via stdout
Se precisar enviar feedbacks detalhados à IA (como o motivo lúdico do bloqueio) ou alimentar o histórico do chat com dados do script, retorne exit 0 e exiba um objeto JSON formatado no stdout:
Use códigos de saída 2 (com stderr) para bloqueios simples e retornos JSON com exit 0 para integrações lógicas. Não misture as duas formas (o interpretador ignora saídas JSON se o código de retorno for 2).
Exemplos de retornos estruturados:
1. Bloqueio preventivo no PreToolUse com indicação de motivo:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "A alteração neste arquivo de produção local foi bloqueada por políticas do projeto."
}
}Os valores para permissionDecision são: "deny" (rejeitar o comando e enviar o motivo), "ask" (solicitar aprovação manual no terminal), "allow" (executar silenciosamente) ou "defer" (postergar a execução para lints demorados).
Importante: saídas "allow" em Hooks não sobrescrevem restrições de permissões do repositório. A documentação pontua:
Retornar "allow" pula o prompt interativo, mas não substitui as regras de permissão. Se uma regra de recusa corresponder à chamada da ferramenta, a chamada será bloqueada mesmo que seu hook retorne "allow".
Isso assegura que nenhum script local possa rebaixar as chaves de segurança globais do repositório. Contudo, o bloqueio preventivo via Hook tem prioridade máxima: mesmo que a flag --dangerously-skip-permissions esteja ativa, um Hook que retorne "deny" bloqueará o comando.
2. Injeção de histórico no SessionStart: retornos em stdout são anexados diretamente ao boot do chat. Exemplo para enviar logs do git:
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "git log --oneline -5"
}
]
}
]
}
}💡 Resumo em uma frase: A comunicação usa stdin (entrada do JSON), exit code (controle de fluxo) e stdout (dados de saída); use exit 2 para bloquear execuções e stdout com exit 0 para passar parâmetros estruturados.
05 Modelos práticos para produção
Abaixo fornecemos três estruturas de uso comum para acelerar seu fluxo de trabalho:
Exemplo 1: Formatação automatizada (PostToolUse)
Configuração essencial recomendada para repositórios compartilhados, a ser salva em .claude/settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}
]
}
]
}
}Funcionamento: Toda gravação de editores físicos dispara a leitura do JSON, obtendo o caminho do arquivo e enviando-o ao formatador. Você pode alterar a linha de comando para rodar linter como o eslint --fix ou formatação do Go (gofmt).
Exemplo 2: Bloqueio de comandos bash perigosos (PreToolUse)
Recomenda-se modularizar lógicas complexas de segurança salvando as regras em um script de suporte avulso.
Etapa 1: Salve o validador em .claude/hooks/block-dangerous.sh:
#!/bin/bash
# block-dangerous.sh: Bloqueia chamadas de exclusão rm -rf
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')
if echo "$COMMAND" | grep -q "rm -rf"; then
echo "Blocked: Comandos rm -rf são rejeitados pelas políticas locais." >&2 # Enviado para stderr
exit 2 # Interrompe a execução técnica no console
fi
exit 0 # Permite a execução normalEtapa 2: Conceda permissão de execução local para o script (necessário no Linux/macOS):
chmod +x .claude/hooks/block-dangerous.shEtapa 3: Inscreva o script de validação no .claude/settings.json do projeto associado ao utilitário Bash:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-dangerous.sh"
}
]
}
]
}
}O uso da variável $CLAUDE_PROJECT_DIR é fundamental para manter a portabilidade de caminhos físicos locais em monorepositórios ou subpastas.
⚠️ Aviso de segurança (Artigo 21): Hooks executam códigos de shell com os privilégios locais do seu usuário no sistema operacional. Audite rigorosamente scripts antes de autorizar a execução.
Exemplo 3: Emissão de alertas do sistema (Notification)
Ideal para notificar o usuário quando tarefas pesadas de compilações em segundo plano forem concluídas ou aguardarem entrada manual:
Configuração no Global (User) para macOS:
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code aguarda ação.\" with title \"Claude Code\"'"
}
]
}
]
}
}Sintaxes recomendadas para outras plataformas locais:
| Sistema operacional | Script de chamada (command) |
|---|---|
| macOS | osascript -e 'display notification "..." with title "Claude Code"' |
| Linux | notify-send 'Claude Code' '...' |
| Windows (PowerShell) | PowerShell -Command "Add-Type -AssemblyName PresentationFramework; [System.Windows.MessageBox]::Show('...','Claude Code')" |
No macOS, certifique-se de habilitar as permissões de exibição de alertas para o interpretador Script Editor nas preferências de segurança locais.
💡 Resumo em uma frase: Implementações comuns incluem formatadores automáticos pós-ferramentas, bloqueios preventivos de console (com exit 2) e alertas visuais de sistema baseados em scripts locais.
06 Prática: Criando um log local de comandos bash
Criaremos um Hook inofensivo para monitoramento local: registrar todas as chamadas bash concluídas com sucesso pelo Claude em um arquivo de log na pasta do usuário.
Requisito: Ter o utilitário jq instalado em sua máquina local.
Passo 1: Criar a configuração local no repositório de testes
Crie a pasta .claude/ no seu diretório de testes e salve o .claude/settings.json com as seguintes definições:
{
"settings": {},
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.command' >> ~/claude-bash-log.txt"
}
]
}
]
}
}O Hook intercepta comandos de console (matcher: "Bash"), captura o comando rodado do input JSON e o anexa no arquivo claude-bash-log.txt da raiz do usuário.
Passo 2: Iniciar o console do Claude e inspecionar a árvore
claudeNo chat do Claude, execute o atalho de auditoria:
/hooksSaída esperada: O menu interativo (read-only) listará o evento PostToolUse com 1 Hook ativo associado ao Bash. Use a tecla Enter para validar a leitura técnica das chaves.
O menu /hooks serve apenas para depuração e conferência; edições e inclusões são feitas escrevendo nos arquivos JSON do disco.
Passo 3: Disparar um comando bash para ativar o Hook
Use a tecla Esc para voltar ao chat e peça para a IA listar os arquivos:
Liste os arquivos do diretório atual usando o comando ls.O console executará o comando bash ls. A ativação do Hook ocorre em segundo plano de forma silenciosa.
Passo 4: Validar a gravação física nos logs
Abra outro console local da sua máquina e confira o arquivo de log:
Get-Content -Path "$env:USERPROFILE\claude-bash-log.txt"Saída esperada: O comando ls executado pelo Claude estará salvo no arquivo local, confirmando o funcionamento de automatizações.
Passo 5: Limpeza técnica do ambiente
Para reverter o teste, remova a chave hooks do arquivo .claude/settings.json e delete o arquivo de log gerado.
Esse ciclo ilustra a esteira de desenvolvimento de qualquer automação guiada por eventos no Claude Code.
07 Resolução de problemas e depuração de erros
Se os scripts de Hooks falharem ou não responderem a eventos locais, consulte esta tabela de triagem:
| Sintoma no console | Diagnóstico sugerido |
|---|---|
| O Hook não dispara no chat | 1. Rode /hooks para auditar a indexação.2. Verifique maiúsculas no matcher (Edit != edit).3. Mude de PostToolUse para PreToolUse se precisar de prevenção. |
O Hook não consta no menu /hooks | 1. JSON corrompido (vírgulas extras ou comentários proibidos). 2. Caminhos salvos fora de .claude/settings.json. |
Erro hook error no console | O script retornou código de erro diferente de 0. Verifique se o jq está instalado localmente e use $CLAUDE_PROJECT_DIR para caminhos de scripts. |
| Falha de execução local do script | Conceda permissões físicas de terminal com chmod +x (macOS/Linux). |
| O comando rodou mesmo com erro | O script retornou exit 1 em vez do código obrigatório exit 2 para bloqueio preventivo. |
Duas técnicas úteis para depuração técnica:
1. Alimentar dados simulados em console separado: teste o script rodando pipelines locais sem precisar inicializar o console do Claude Code:
'{"tool_name":"Bash","tool_input":{"command":"rm -rf /tmp/x"}}' | .\.claude\hooks\block-dangerous.sh
$LASTEXITCODE # Deve retornar 2 em scripts de bloqueioEssa triagem isolada ajuda a depurar o código local antes de integrá-lo ao Claude.
2. Inspecionar logs em modo Debug: inicie a sessão do terminal com a flag --debug e avalie os logs gerados na pasta de logs local ~/.claude/debug/:
claude --debugO chat registrará os momentos em que mapear as regras do settings.json:
[DEBUG] Executing hooks for PostToolUse:Bash
[DEBUG] Hook command completed with status 0Para contornar o uso de Hooks temporariamente durante testes rápidos, declare "disableAllHooks": true na raiz do JSON, evitando ter que comentar ou deletar as linhas.
08 Resumo
Revisão dos pontos essenciais:
| Objetivo | Estrutura sugerida | Ponto-chave a lembrar |
|---|---|---|
| Garantir a execução de lints | Scripts de terminal guiados por eventos | Transforma recomendações de conduta em imposições de sistema. |
| Escolher o gatilho correto | Eventos do ciclo de vida | Eventos Pre previnem ações; eventos Post executam pós-ferramentas. |
| Declarar as automações | Configuração no settings.json | Formato unificado em: Evento, Matcher (case-sensitive) e Ação. |
| Conectar dados do console | stdin (JSON), exit code e stdout | Use exit 2 para interromper execuções locais de comandos. |
| Bloquear bash inseguro | Evento PreToolUse de terminal com validador | Conceda permissão chmod +x; Hooks não sobrescrevem restrições globais. |
| Diagnosticar falhas | Triagem de erros de Hooks | Consulte /hooks no console e inicialize a sessão em modo --debug. |
Agora você deve ser capaz de: Diferenciar diretrizes conceituais de imposições técnicas de terminal, selecionar eventos adequados de ciclo de vida (como PreToolUse ou PostToolUse), configurar matchers case-sensitive, escrever scripts locais integrando stdin JSON e capturar exceções com códigos de saída exit 2. Os Hooks automatizam as tarefas repetitivas pós-codificação de forma definitiva.
No próximo artigo, 34 "Manual de Referência da CLI (CLI Reference)"—consolidaremos a sintaxe de comandos do Claude Code. Faremos uma varredura completa de todas as flags e opções da CLI (como --debug, --dangerously-skip-permissions e novos comandos de console), servindo como guia rápido de consulta de terminal para seu dia a dia.