Skip to content

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 matcher para 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.md em 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) e SessionEnd (encerramento do console).
  • Uma vez por interação (rodada de prompt): UserPromptSubmit (entrada de dados enviada) e Stop (conclusão da resposta do assistente).
  • A cada chamada de ferramenta (tool calls): PreToolUse (antes da execução da ferramenta) e PostToolUse (após a conclusão do comando).

O diagrama abaixo ilustra o momento exato de disparo desses gatilhos no fluxo de conversação:

Gatilhos de Hooks no Ciclo de Vida: SessionStart, UserPromptSubmit, Pre/Post Tool e Stop

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 GatilhoMomento de acionamentoCaso de uso recomendado
PreToolUseAntes de uma ferramenta ou comando rodarBloqueio de comandos inseguros e proteção de arquivos (permite interromper a execução).
PostToolUseApós a conclusão bem-sucedida de um comandoFormatação de arquivos automática (Prettier, ESLint).
StopAo finalizar a resposta e liberar o chatNotificações de fim de tarefas e monitoramento de dependências locais.
SessionStartNa inicialização do console do Claude CodeInjeçã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 PreToolUse para proteções e validações pré-execução e PostToolUse para 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 destinoEscopo de ação do HookVersionamento (Git)
~/.claude/settings.jsonGlobal do usuário em qualquer repositórioNão (raiz do sistema local)
.claude/settings.jsonApenas o projeto/repositório ativoSim (versionado no git)
.claude/settings.local.jsonApenas 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:

json
{
  "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:

  1. O evento de gatilho: chave PostToolUse (após execução de ferramentas).
  2. O filtro de acionamento: chave matcher limitada aos editores Edit ou Write (evita rodar o linter em leituras ou consultas bash).
  3. A ação do script: chave type ("command") indicando a chamada bash declarada em command.

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 matcherComportamento de buscaExemplo de acionamento
"Edit|Write"Mapeia termos usando o operador lógico ORDisparado apenas após editores.
"Bash"Mapeia o termo exatoDisparado apenas em execuções de console.
"" ou omitidoSem 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.json estruturados em: Evento, Matcher e Script de ação; os filtros de ferramenta matcher diferenciam 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:

json
{
  "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ídaSignificado técnicoComportamento no console
0Execução bem-sucedidaO console prossegue para a chamada (sem pular telas de permissões padrão).
2Interromper/BloquearO comando é abortado no console; logs enviados no stderr são reportados à IA.
Outros (ex: 1)Erro interno não fatalO 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:

json
{
  "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:

json
{
  "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:

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:

bash
#!/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 normal

Etapa 2: Conceda permissão de execução local para o script (necessário no Linux/macOS):

bash
chmod +x .claude/hooks/block-dangerous.sh

Etapa 3: Inscreva o script de validação no .claude/settings.json do projeto associado ao utilitário Bash:

json
{
  "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:

json
{
  "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 operacionalScript de chamada (command)
macOSosascript -e 'display notification "..." with title "Claude Code"'
Linuxnotify-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:

json
{
  "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

powershell
claude

No chat do Claude, execute o atalho de auditoria:

text
/hooks

Saí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:

text
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:

powershell
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 consoleDiagnóstico sugerido
O Hook não dispara no chat1. 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 /hooks1. JSON corrompido (vírgulas extras ou comentários proibidos).
2. Caminhos salvos fora de .claude/settings.json.
Erro hook error no consoleO 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 scriptConceda permissões físicas de terminal com chmod +x (macOS/Linux).
O comando rodou mesmo com erroO 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:

powershell
'{"tool_name":"Bash","tool_input":{"command":"rm -rf /tmp/x"}}' | .\.claude\hooks\block-dangerous.sh
$LASTEXITCODE # Deve retornar 2 em scripts de bloqueio

Essa 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/:

bash
claude --debug

O chat registrará os momentos em que mapear as regras do settings.json:

text
[DEBUG] Executing hooks for PostToolUse:Bash
[DEBUG] Hook command completed with status 0

Para 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:

ObjetivoEstrutura sugeridaPonto-chave a lembrar
Garantir a execução de lintsScripts de terminal guiados por eventosTransforma recomendações de conduta em imposições de sistema.
Escolher o gatilho corretoEventos do ciclo de vidaEventos Pre previnem ações; eventos Post executam pós-ferramentas.
Declarar as automaçõesConfiguração no settings.jsonFormato unificado em: Evento, Matcher (case-sensitive) e Ação.
Conectar dados do consolestdin (JSON), exit code e stdoutUse exit 2 para interromper execuções locais de comandos.
Bloquear bash inseguroEvento PreToolUse de terminal com validadorConceda permissão chmod +x; Hooks não sobrescrevem restrições globais.
Diagnosticar falhasTriagem de erros de HooksConsulte /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.


Leitura Recomendada