Free

Guia completo de Claude Code Hooks: controle cada ação do Claude

Análise completa do mecanismo Claude Code Hooks: cinco tipos de eventos, controle de códigos de saída e quatro configurações reais para auditar, interceptar e automatizar ações de IA.


Cada vez que o Claude Code lê um arquivo, escreve código ou executa um comando, há um sistema de eventos rodando em segundo plano. Os Hooks são a interface para se conectar a esse sistema — você pode injetar sua própria lógica em qualquer momento: executar linters automaticamente, registrar operações, interceptar ações perigosas ou disparar qualquer comando de shell.

Este artigo cobre completamente o mecanismo de Hooks, a configuração e o uso prático.


O que são Hooks

Hooks são comandos de shell configurados no settings.json que o Claude Code executa automaticamente quando eventos específicos ocorrem.

A analogia mais direta: git hooks. O git pode disparar scripts antes e depois de operações como commit e push. Os Claude Code Hooks funcionam exatamente da mesma forma — a diferença é que os pontos de disparo são as chamadas de ferramentas da IA.

Por que isso importa?

Quanto mais capaz o Claude Code se torna, mais você precisa de uma camada de controle determinista. Os Hooks fornecem:
- Garantias de execução que não dependem do prompt (o Claude pode ignorar instruções, mas os hooks sempre rodam)
- Registros de operações auditáveis
- Verificações de qualidade automatizadas


Cinco tipos de Hooks

Tipo Gatilho Uso típico
PreToolUse Antes de uma chamada de ferramenta Bloquear operações perigosas, registrar intenção
PostToolUse Depois de uma chamada de ferramenta Auto-lint, rodar testes
PreCompact Antes da compactação do contexto Salvar snapshot do estado atual
Notification Quando o Claude envia uma notificação Alertas de desktop, mensagens no Slack
Stop Quando o Claude termina de responder Resumir logs, disparar fluxos posteriores

Os mais usados são PreToolUse e PostToolUse, para interceptar e pós-processar chamadas de ferramentas.


Formato de configuração

Os Hooks vão em ~/.claude/settings.json (global) ou em .claude/settings.json na raiz do projeto (nível projeto):

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

Três campos principais:

  • matcher: Regex que corresponde a nomes de ferramentas, determina quais chamadas disparam este hook. "Write|Edit" dispara ao escrever ou editar arquivos. Deixe vazio ou use ".*" para corresponder a todas as ferramentas.
  • type: Por enquanto apenas "command".
  • command: Qualquer comando de shell.

Referência de nomes de ferramentas

Nomes de ferramentas necessários para escrever matchers:

Nome Ação
Write Escrever um novo arquivo
Edit Editar um arquivo
Bash Executar um comando de shell
Read Ler um arquivo
Glob Busca de arquivos
Grep Busca de conteúdo
TodoWrite Atualizar lista de tarefas

Ambiente de execução do Hook

Durante a execução, os dados são passados como JSON pelo stdin:

{
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.rb",
    "content": "..."
  },
  "tool_response": "..."
}

PreToolUse recebe tool_input (os argumentos antes da chamada). PostToolUse também recebe tool_response (o valor de retorno da ferramenta).

Exemplo de hook com lógica condicional:

#!/bin/bash
input=$(cat)
file=$(echo "$input" | jq -r '.tool_input.file_path')

# Executar rubocop apenas em arquivos .rb
if [[ "$file" == *.rb ]]; then
  rubocop "$file" --autocorrect-all --no-color
fi

Significado dos códigos de saída

O código de saída do hook controla o comportamento posterior do Claude Code:

Código de saída Significado
0 Sucesso, continuar execução
2 Bloquear: cancelar a chamada de ferramenta atual, enviar stderr de volta ao Claude
Outros não-zero Registrar o erro, mas continuar

O código de saída 2 é o mais poderoso — permite escrever lógica de interceptação no PreToolUse para impedir o Claude de realizar uma operação e explicar o motivo.


Na prática: quatro configurações de Hook

1. Auto-formatação ao escrever arquivos

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'file=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r .file_path 2>/dev/null); [[ \"$file\" == *.rb ]] && rubocop -A \"$file\" --no-color -q || true'"
          }
        ]
      }
    ]
  }
}

2. Bloquear exclusão de diretórios específicos

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'cmd=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r .command); if echo \"$cmd\" | grep -qE \"rm.*/(migrations|seeds)\"; then echo \"Não é permitido excluir os diretórios migrations ou seeds\" >&2; exit 2; fi'"
          }
        ]
      }
    ]
  }
}

3. Log de auditoria de operações

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit|Bash",
        "hooks": [
          {
            "type": "command",
            "command": "echo \"$(date '+%Y-%m-%d %H:%M:%S') $CLAUDE_TOOL_NAME: $(echo $CLAUDE_TOOL_INPUT | jq -c .)\" >> ~/.claude/audit.log"
          }
        ]
      }
    ]
  }
}

4. Notificação de desktop ao concluir

{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude concluiu\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

Global vs. nível projeto

Os Hooks podem ficar em dois lugares:

Global (~/.claude/settings.json): Regras comuns a todos os projetos — logs, notificações.

Nível projeto (.claude/settings.json): Verificações específicas do projeto. Os hooks de projeto e os globais se combinam e ambos são executados.

Em projetos de equipe, faça commit do settings.json do projeto no git para que todos executem os mesmos hooks.


Depurando Hooks

Passos para resolver problemas quando um hook não está funcionando:

  1. Verificar o matcher: Nomes de ferramentas diferenciam maiúsculas de minúsculas — write não é Write
  2. Executar o comando separadamente: Copie o comando do hook e execute diretamente no terminal
  3. Verificar a saída do Claude Code: O stderr do hook aparece na conversa
  4. Simplificar para testar: Comece com echo "hook triggered" >> /tmp/hook.log para confirmar o disparo

Resumo

O valor central dos Hooks é conectar o comportamento imprevisível da IA com os padrões de engenharia deterministas. O Claude pode esquecer de rodar os testes, mas um PostToolUse hook não. O Claude pode excluir arquivos por acidente, mas um interceptor PreToolUse não vai deixar passar.

Comece com um hook: auto-lint ao escrever arquivos. Quando estiver funcionando, adicione mais.