# Hooks do Claude Code: guia prático com exemplos

URL: https://agentvera.dev/pt/blog/claude-code-hooks-guide/ · Publicado: 2026-10-23

Como funcionam os hooks do Claude Code: eventos, settings.json, matchers, exit codes e saída JSON, mais hooks prontos que formatam, bloqueiam e avisam você.

**Resumo:**

- Os hooks são definidos na chave hooks do settings.json e sempre rodam no seu evento, porque quem os executa é o Claude Code, não o modelo.
- Para bloquear uma chamada de ferramenta, um hook PreToolUse sai com código 2 ou retorna JSON com permissionDecision igual a deny; o exit code 1 não bloqueia nada.
- Um hook de deny ainda bloqueia chamadas com --dangerously-skip-permissions, mas hooks não são um sandbox e rodam com as permissões do seu usuário.

Hooks do Claude Code são comandos que o Claude Code executa sozinho em pontos fixos de uma sessão: antes de uma chamada de ferramenta, depois de editar um arquivo, quando um prompt é enviado, quando o Claude para ou precisa da sua atenção. Você os define na chave `hooks` do `settings.json`. Um hook pode adicionar contexto, formatar um arquivo ou bloquear uma ação saindo com código 2 ou retornando uma decisão em JSON. Diferente das instruções no `CLAUDE.md`, um hook sempre roda, porque quem o executa é o harness, não o modelo.

Este guia cobre os eventos que importam, o formato da configuração, matchers, exit codes e saída JSON, três hooks que você pode copiar hoje e as notas de segurança para ler antes de adicionar qualquer um. As informações vêm da [referência de hooks](https://code.claude.com/docs/en/hooks "Referência de hooks do Claude Code") e do [guia de hooks](https://code.claude.com/docs/en/hooks-guide "Guia de hooks do Claude Code") oficiais. Se você só quer a definição curta, veja o [verbete hooks do Claude Code no glossário](/pt/glossary/claude-code-hooks/ "Hooks do Claude Code").

## Por que usar hooks em vez de instruções

Você pode escrever “sempre rode o Prettier depois de editar” no `CLAUDE.md`, e o Claude normalmente vai fazer isso. O problema é o “normalmente”. Instruções são conselhos que o modelo pesa contra todo o resto do contexto. Hooks são código que roda toda vez que o evento dispara.

Isso faz dos hooks a ferramenta certa para três tipos de regra:

- **Coisas que sempre devem acontecer**, como formatação, lint ou log.
- **Coisas que nunca devem acontecer**, como editar o `.env` ou rodar `rm -rf` na pasta errada.
- **Coisas que você quer saber**, como o Claude esperando uma resposta de permissão enquanto você está em outra janela.

Deixe conselhos de estilo e conhecimento do projeto no [CLAUDE.md](/pt/blog/claude-md-agents-md/ "CLAUDE.md e AGENTS.md") e coloque regras rígidas em hooks.

## Eventos de hook que você vai usar de verdade

A referência lista mais de trinta eventos, e a lista cresce a cada versão. A maioria das configurações reais usa um punhado:

| Evento | Quando dispara | Pode bloquear? |
| --- | --- | --- |
| `PreToolUse` | Antes de uma chamada de ferramenta rodar | Sim, bloqueia a chamada |
| `PostToolUse` | Depois que uma chamada de ferramenta dá certo | Não, a ferramenta já rodou; o stderr vai para o Claude |
| `UserPromptSubmit` | Quando você envia um prompt | Sim, o prompt nunca chega ao Claude |
| `Notification` | Quando o Claude Code envia uma notificação, como um pedido de permissão ou espera ociosa | Não |
| `Stop` | Quando o Claude termina a resposta | Sim, o Claude continua trabalhando |
| `SubagentStart` / `SubagentStop` | Quando um subagente inicia ou termina | Só `SubagentStop` |
| `SessionStart` | Na inicialização, ao retomar, em `/clear` ou na compactação | Não, mas o stdout vira contexto |
| `PreCompact` | Antes de o contexto ser compactado | Sim, bloqueia a compactação |
| `PermissionRequest` | Quando um diálogo de permissão está prestes a aparecer | Só via JSON, não com exit 2 |
| `SessionEnd` | Quando a sessão termina | Não |

`PreToolUse` e `PostToolUse` cobrem a maioria das necessidades. `Notification` e `Stop` são os de “me avise quando terminar ou travar”.

## Como os hooks são configurados no settings.json

Os hooks ficam nos mesmos arquivos de configuração que as permissões:

| Arquivo | Escopo | Compartilhado via git? |
| --- | --- | --- |
| `~/.claude/settings.json` | Todos os seus projetos | Não |
| `.claude/settings.json` | Um projeto | Sim |
| `.claude/settings.local.json` | Um projeto, só você | Não (no gitignore) |
| Configurações de política gerenciada | Organização inteira | Definidas por admins |

Plugins podem trazer hooks em `hooks/hooks.json`, e skills e subagentes podem definir hooks no frontmatter.

A estrutura tem três níveis: o evento, um grupo de matcher e uma lista de handlers.

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write",
            "timeout": 30
          }
        ]
      }
    ]
  }
}
```

O `type` de um handler pode ser `command` (um comando de shell), `http` (um POST para uma URL), `mcp_tool` (uma ferramenta de um servidor MCP conectado), `prompt` (uma checagem rápida de sim/não feita por um modelo) ou `agent` (uma checagem experimental por subagente). O timeout padrão é de 600 segundos para handlers command, HTTP e de ferramenta MCP, 30 segundos para hooks de prompt e 60 para hooks de agente.

Todo hook recebe JSON no stdin. Os campos comuns são `session_id`, `transcript_path`, `cwd`, `permission_mode` e `hook_event_name`. Eventos de ferramenta adicionam `tool_name`, `tool_input` e `tool_use_id`. Seu script lê esse JSON, geralmente com `jq`, e decide o que fazer. A variável de ambiente `CLAUDE_PROJECT_DIR` aponta para a raiz do projeto, o que ajuda a referenciar scripts guardados no repositório.

Você pode digitar `/hooks` dentro do Claude Code para ver o que está carregado e de qual arquivo veio cada hook. Essa tela é somente leitura; para mudar hooks, você edita o JSON.

## Matchers: quais chamadas de ferramenta um hook vê

O `matcher` decide quais chamadas disparam um hook. Em eventos de ferramenta, ele compara com o nome da ferramenta:

| Matcher | Significado |
| --- | --- |
| `"*"`, `""` ou sem matcher | Toda chamada |
| `"Bash"` | Exatamente a ferramenta Bash |
| `"Edit\|Write"` | Edit ou Write (uma lista) |
| `"mcp__memory__.*"` | Toda ferramenta do servidor MCP `memory` |
| `"mcp__.*__write.*"` | Qualquer ferramenta MCP cujo nome começa com `write` |

A regra é simples. Se o matcher tem só letras, dígitos, `_`, `-`, espaços, vírgulas ou `|`, ele é um nome exato ou uma lista de nomes. Qualquer outro caractere o transforma numa expressão regular JavaScript. Ferramentas MCP se chamam `mcp__<server>__<tool>`.

Alguns eventos ignoram o matcher, como `UserPromptSubmit` e `Stop`, porque não há o que comparar. Outros comparam algo que não é o nome de uma ferramenta. `SessionStart` compara como a sessão começou (`startup`, `resume`, `clear`, `compact`), e `Notification` compara o tipo da notificação, como `permission_prompt` ou `idle_prompt`.

Eventos de ferramenta também aceitam um campo `if` com a sintaxe das regras de permissão, então um hook de Bash pode rodar só para, digamos, `"Bash(git *)"`. A documentação descreve isso como um filtro de melhor esforço, então mantenha a checagem real no seu script.

## Exit codes e saída JSON

Um hook de comando responde ao Claude Code de duas formas: o exit code e um JSON opcional no stdout.

| Exit code | O que acontece |
| --- | --- |
| `0` | Sucesso. O stdout é interpretado como JSON se for um único objeto JSON. Em `UserPromptSubmit` e `SessionStart`, texto puro no stdout é adicionado ao contexto do Claude. |
| `2` | Erro bloqueante. O stderr é o motivo. Em `PreToolUse` a chamada é cancelada, em `UserPromptSubmit` o prompt é rejeitado, em `Stop` o Claude continua. |
| Qualquer outro, incluindo `1` | Erro não bloqueante. O Claude Code registra e segue em frente. |

A armadilha aqui é o exit code 1. Muitos scripts falham com 1 por padrão, e isso **não** bloqueia nada. Se você quer dizer “pare”, saia com 2.

Para um controle mais fino, saia com 0 e imprima JSON. Um hook `PreToolUse` pode permitir, negar ou perguntar:

```json
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Use rg instead of grep for better performance"
  }
}
```

`permissionDecision` aceita `allow`, `deny`, `ask` ou `defer`. Um hook também pode reescrever a chamada com `updatedInput` ou passar texto extra ao Claude com `additionalContext`. Campos que funcionam em qualquer evento incluem `continue: false` (para o Claude por completo, com um `stopReason`) e `systemMessage` (um aviso mostrado a você).

Quando vários hooks batem, eles rodam em paralelo, e a resposta mais restritiva vence: deny ganha de defer, defer ganha de ask, ask ganha de allow. Um `allow` vindo de um hook não sobrepõe uma regra deny nas suas permissões.

## Exemplo 1: formatar arquivos depois de cada edição

Este é o hook com que a maioria começa. Ele roda o Prettier em todo arquivo que o Claude escreve ou edita:

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}
```

Troque por `ruff format`, `gofmt -w` ou `rustfmt` para outras linguagens. Como o formatador roda depois da edição, o Claude vê o arquivo formatado na próxima leitura, e você para de ver diffs só de estilo na revisão.

## Exemplo 2: bloquear comandos perigosos e arquivos protegidos

Um hook `PreToolUse` é o lugar para limites rígidos. Este script, adaptado do guia oficial, bloqueia edições em arquivos sensíveis. Salve como `.claude/hooks/protect-files.sh`:

```bash
#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")

for pattern in "${PROTECTED_PATTERNS[@]}"; do
  if [[ "$FILE_PATH" == *"$pattern"* ]]; then
    echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
    exit 2
  fi
done

exit 0
```

Torne-o executável com `chmod +x .claude/hooks/protect-files.sh` e depois registre:

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
          }
        ]
      }
    ]
  }
}
```

O mesmo padrão funciona para comandos de shell. Use o matcher `Bash`, leia `.tool_input.command` e saia com 2 quando ele contiver algo que você nunca quer, como `rm -rf /`, `git push --force` ou `DROP TABLE`. Lembre que uma checagem de string é fácil de contornar, então trate isso como cinto de segurança, não como cadeado.

## Exemplo 3: receber uma notificação no desktop

Tarefas longas param e esperam por você mais do que você gostaria. Um hook `Notification` avisa na hora. No macOS:

```json
{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}
```

No Linux, use `notify-send 'Claude Code' 'Claude Code needs your attention'`. Defina o matcher como `permission_prompt` se só te interessam os pedidos de permissão, ou adicione um hook `Stop` com o mesmo comando para saber quando o Claude termina.

## Mais padrões úteis

- **Reinjetar contexto depois da compactação.** Um hook `SessionStart` com matcher `compact` pode dar `echo` num lembrete curto das suas regras. O stdout dele é adicionado ao novo contexto.
- **Auditar mudanças de configuração.** Um hook `ConfigChange` pode acrescentar cada mudança de configuração a um arquivo de log.
- **Portão de qualidade no Stop.** Um hook `Stop` pode rodar seus testes e sair com 2 trazendo as falhas, para o Claude continuar corrigindo. Verifique o campo `stop_hook_active` na entrada para evitar um loop infinito. O Claude Code também ignora um hook Stop depois de vários bloqueios seguidos.
- **Aprovar automaticamente um pedido seguro.** Um hook `PermissionRequest` pode responder a um diálogo específico com `{"behavior": "allow"}` dentro do objeto de decisão. Mantenha o matcher bem restrito.

## Notas de segurança antes de adicionar hooks

Hooks rodam como comandos de shell com as permissões do seu usuário, sem perguntar. Esse é o objetivo, e também o risco.

- **Leia os hooks antes de confiar num repositório.** O `.claude/settings.json` de um projeto pode trazer hooks. Revise-os como você revisaria um script de `postinstall`.
- **Coloque suas variáveis entre aspas.** A entrada do hook vem do modelo, e o modelo lê arquivos e páginas web que podem conter [prompt injection](/pt/glossary/prompt-injection/ "Prompt injection"). Use `"$VAR"`, nunca dê eval na entrada e prefira `jq` a parsing feito à mão.
- **Use caminhos absolutos ou relativos ao projeto** com `$CLAUDE_PROJECT_DIR`, para que um hook não dependa da pasta atual.
- **Mantenha os hooks rápidos.** Um hook `PreToolUse` lento deixa toda chamada de ferramenta lenta. Defina um `timeout`.
- **Hooks não são um sandbox.** Um hook de deny bloqueia chamadas mesmo com `--dangerously-skip-permissions`, o que é útil, mas um agente determinado ou confuso pode chegar ao mesmo resultado por outro caminho. Combine hooks com regras deny e isolamento, como explicado em [segurança de agentes de código com IA](/pt/blog/ai-coding-agent-security/ "Segurança de agentes de código com IA") e [pular permissões com segurança](/pt/blog/claude-code-skip-permissions/ "Claude Code --dangerously-skip-permissions").
- **Conheça os botões de desligar.** `"disableAllHooks": true` desliga os hooks, e admins podem definir `allowManagedHooksOnly` nas configurações gerenciadas para bloquear hooks de usuário e de projeto.

Quando um hook se comporta mal, inicie o Claude Code com `claude --debug`, ou grave o log num arquivo com `--debug-file /tmp/claude.log`, para ver o matcher, o exit code e a saída de cada hook.

## Como o AgentVera usa hooks

O AgentVera é um app desktop que roda Claude Code, Codex, Gemini CLI e outras CLIs de código lado a lado. Hooks são uma parte importante de como ele trabalha com o Claude Code.

- **Seus hooks continuam seus.** O AgentVera passa os próprios hooks para cada processo do Claude Code com a flag `--settings`. O Claude Code os mescla com os hooks dos seus arquivos de configuração, e o seu `settings.json` não é editado.
- **O status do agente vem dos hooks.** O status que cada agente mostra no app é lido dos eventos de hook da própria CLI, não adivinhado a partir do texto do terminal.
- **As ferramentas inteligentes são hooks.** O recurso de [ferramentas inteligentes](/pt/features/smart-tools/ "Ferramentas inteligentes") adiciona quatro hooks aos agentes Claude Code locais: bloqueia leituras repetidas do mesmo arquivo, roda só os testes afetados por uma edição, verifica erros logo depois de uma edição e compartilha resultados entre agentes. Eles vêm ativados por padrão e você pode desativá-los em Settings → “Token saving”.
- **Nenhum script de notificação necessário.** [Notificações e aprovações](/pt/features/notifications-and-approvals/ "Notificações e aprovações") reúnem numa só fila todos os agentes esperando aprovação, enviam notificações no desktop enquanto o app está em segundo plano e podem avisar seu celular pelo Telegram.

O Qwen Code também recebe os hooks do AgentVera, porque o sistema de hooks dele segue os eventos e o formato JSON do Claude Code.

## Conclusão

Comece com um formatador `PostToolUse` e uma barreira `PreToolUse`, confira-os com `/hooks` e `--debug` e só adicione mais quando uma regra continuar sendo quebrada. Saia com 2 para bloquear, imprima JSON quando precisar de mais controle e trate cada hook como código que roda com as suas permissões.

Leia mais:

- [Hooks do Claude Code (glossário)](/pt/glossary/claude-code-hooks/ "Hooks do Claude Code")
- [Ferramentas inteligentes](/pt/features/smart-tools/ "Ferramentas inteligentes")
- [Notificações e aprovações](/pt/features/notifications-and-approvals/ "Notificações e aprovações")
- [Agente Claude Code](/pt/agents/claude-code/ "Claude Code no AgentVera")

Para experimentar o AgentVera, comece pela [página inicial](/pt/ "AgentVera").

## Perguntas frequentes

**O que são hooks do Claude Code?** Hooks são comandos de shell, chamadas HTTP, ferramentas MCP ou prompts que o Claude Code executa sozinho em pontos definidos de uma sessão, como antes de uma chamada de ferramenta, depois de editar um arquivo ou quando o Claude precisa da sua atenção. Você os define no settings.json.

**Onde coloco os hooks do Claude Code?** Na chave hooks de um arquivo de configurações: ~/.claude/settings.json para todos os seus projetos, .claude/settings.json para um projeto compartilhado via git, ou .claude/settings.local.json para um projeto só na sua máquina. Plugins, skills e subagentes também podem definir hooks.

**Como um hook bloqueia uma chamada de ferramenta?** Um hook PreToolUse sai com código 2 e escreve o motivo no stderr, ou sai com 0 e imprime JSON com permissionDecision igual a deny. O Claude Code cancela a chamada e mostra o motivo ao Claude. O exit code 1 não bloqueia.

**Os hooks ainda rodam com --dangerously-skip-permissions?** Sim. Um hook que retorna deny bloqueia a chamada de ferramenta mesmo no modo bypassPermissions. Isso faz de um hook PreToolUse uma última barreira útil para comandos que você nunca quer, embora não seja um sandbox.

**Como depuro um hook do Claude Code que não dispara?** Abra /hooks para ver quais hooks estão carregados e de onde vêm, confira se o matcher bate exatamente com o nome da ferramenta e inicie o Claude Code com --debug ou --debug-file para ver cada execução do hook, seu exit code e sua saída.

---

**Sobre o AgentVera.** AgentVera é um app desktop para macOS, Windows e Linux, desenvolvido pela Solviera Teknoloji. Ele roda 18 agentes de programação com IA (Claude Code, Codex, Gemini CLI, Copilot, Cursor, Antigravity, opencode, Hermes, Qwen Code, Kimi Code, Kiro, Amp, Droid, Goose, Vibe, Crush, Aider, Cline) lado a lado, por projeto, em terminais reais com as instalações e logins de CLI do próprio usuário. O plano gratuito tem agentes ilimitados. Baixar: https://agentvera.dev/pt/download/ · Preços: https://agentvera.dev/pt/pricing/
