Advanced (Atualizado: 01/06/2026)

Guia de Claude Code Hooks: checks seguros antes e depois do trabalho

Guia prático de Claude Code Hooks para iniciantes: bloquear comandos perigosos, salvar logs, formatar e rodar testes.

Guia de Claude Code Hooks: checks seguros antes e depois do trabalho

Claude Code Hooks são verificações automáticas executadas antes ou depois de uma ação do Claude Code. Em vez de repetir em todo prompt “não execute comandos perigosos”, “formate o arquivo” ou “rode os testes”, você pode colocar essas regras dentro do workflow do projeto.

O modelo mental mais simples é este: PreToolUse é o freio, PostToolUse é a manutenção, UserPromptSubmit é o registro de entrada e Stop é a checagem antes de sair. Hooks não substituem revisão humana, permissões ou CI. Eles tornam as verificações repetidas mais difíceis de esquecer.

Este artigo segue a referência oficial de Claude Code Hooks e a documentação oficial de settings. Para organizar o contexto do projeto, leia também boas práticas de CLAUDE.md. Para o desenho de segurança, combine com o guia de permissões do Claude Code.

Quatro eventos para aprender primeiro

Claude Code tem vários eventos de Hooks, mas a maioria dos times consegue valor começando por estes quatro.

EventoMelhor usoExemplo
UserPromptSubmitAntes de o prompt chegar ao ClaudeSalvar a solicitação, detectar segredos, adicionar contexto leve
PreToolUseAntes de executar uma ferramentaBloquear comandos Bash destrutivos ou ações em produção
PostToolUseDepois de uma ferramenta executar com sucessoRodar formatter, lint ou testes relacionados
StopQuando Claude vai terminar a respostaChecar conflitos, salvar resumo, lembrar validação faltante

Use PreToolUse quando a ação não pode acontecer. Use PostToolUse quando a ação já aconteceu e precisa de limpeza ou validação. Use UserPromptSubmit para observar a qualidade das solicitações. Use Stop para evitar encerrar uma sessão com problema evidente.

Regras compartilhadas normalmente ficam em .claude/settings.json. Experimentos pessoais são mais seguros em .claude/settings.local.json, porque não devem ir para o repositório. Em equipe, documente quais Hooks bloqueiam, quais apenas registram e quem mantém cada um.

Configuração mínima para copiar

A configuração abaixo salva prompts, bloqueia comandos Bash perigosos, executa checks depois de edições e registra um resumo no final.

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node .claude/hooks/log-prompt.mjs"
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "node .claude/hooks/block-dangerous-command.mjs"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "node .claude/hooks/run-quality-checks.mjs",
            "timeout": 120
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node .claude/hooks/stop-summary.mjs"
          }
        ]
      }
    ]
  }
}

O detalhe importante é o array hooks aninhado. A estrutura atual define o evento, um grupo com matcher quando necessário, e depois handlers como type: "command". Exemplos antigos com command diretamente ao lado de matcher ainda aparecem, mas não são o padrão recomendado para copiar hoje.

Use case 1: bloquear comandos perigosos com PreToolUse

O primeiro use case real é segurança de comandos. Quando o agente trabalha rápido, o momento crítico não é depois da execução, e sim imediatamente antes. PreToolUse pode ler a entrada do Bash e negar uma ação claramente arriscada.

Salve como .claude/hooks/block-dangerous-command.mjs.

import fs from "node:fs";

const input = JSON.parse(fs.readFileSync(0, "utf8") || "{}");
const command = String(input.tool_input?.command || "");

const denyPatterns = [
  /rm\s+-rf\s+(\/|\*|\.|\$HOME)/i,
  /cat\s+\.env(\.|$|\s)/i,
  /printenv/i,
  /aws\s+.*\s+delete-/i,
  /gcloud\s+.*\s+delete/i,
  /kubectl\s+delete\s+(namespace|deployment|secret)/i,
  /DROP\s+DATABASE/i
];

const matched = denyPatterns.find((pattern) => pattern.test(command));

if (matched) {
  console.log(JSON.stringify({
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "deny",
      permissionDecisionReason: `Blocked by project hook: ${matched}`
    }
  }));
  process.exit(0);
}

Isso não é um produto completo de segurança. Expressões regulares podem falhar. Mesmo assim, o script bloqueia erros óbvios: mostrar .env, apagar diretórios amplos, deletar recursos cloud, remover objetos Kubernetes ou executar SQL destrutivo. Para produção, combine com permissões do Claude Code, branches protegidos, CI e aprovação humana.

Use case 2: registrar prompts com UserPromptSubmit

O segundo use case é observabilidade do prompt. Muitas sessões ruins não começam por causa de um modelo fraco, mas por uma solicitação vaga: “conserta”, “limpa”, “deixa melhor”. Com log, você consegue revisar quais pedidos geram bons resultados.

Salve como .claude/hooks/log-prompt.mjs.

import fs from "node:fs";
import path from "node:path";

const input = JSON.parse(fs.readFileSync(0, "utf8") || "{}");
const dir = path.join(process.cwd(), ".claude", "hook-logs");
fs.mkdirSync(dir, { recursive: true });

const record = {
  time: new Date().toISOString(),
  event: input.hook_event_name,
  cwd: input.cwd,
  prompt: input.prompt || input.user_prompt || ""
};

fs.appendFileSync(
  path.join(dir, "prompts.jsonl"),
  JSON.stringify(record) + "\n",
  "utf8"
);

Mantenha esse log local no começo. Prompts podem conter nomes de clientes, URLs internas, tokens colados por engano ou contexto de negócio sensível. Adicione .claude/hook-logs/ ao .gitignore e defina retenção, acesso e responsabilidade antes de virar padrão do time.

Use case 3: rodar format e test depois de editar

O terceiro use case é o ciclo de qualidade diário. Depois que Claude escreve ou edita um arquivo, execute formatter e uma verificação pequena. Assim você não precisa escrever “formate e teste” no final de todo prompt.

Salve como .claude/hooks/run-quality-checks.mjs.

import fs from "node:fs";
import { execFileSync } from "node:child_process";

const input = JSON.parse(fs.readFileSync(0, "utf8") || "{}");
const filePath = String(input.tool_input?.file_path || "");

const isSourceFile = /\.(js|jsx|ts|tsx|css|md|mdx|json)$/.test(filePath);
if (!isSourceFile) process.exit(0);

const run = (cmd, args) => {
  try {
    return execFileSync(cmd, args, {
      cwd: process.cwd(),
      encoding: "utf8",
      stdio: ["ignore", "pipe", "pipe"]
    });
  } catch (error) {
    return String(error.stdout || "") + String(error.stderr || "");
  }
};

const messages = [];
messages.push(run("npx", ["prettier", "--write", filePath]));

if (/\.(js|jsx|ts|tsx)$/.test(filePath)) {
  messages.push(run("npm", ["test", "--", "--runInBand"]));
}

console.log(JSON.stringify({
  hookSpecificOutput: {
    hookEventName: "PostToolUse",
    additionalContext: messages.join("\n").slice(-4000)
  }
}));

Em monorepos grandes, não rode a suíte inteira a cada edição. Comece por format, depois adicione testes relacionados e deixe checks pesados para Hooks async ou CI. Também limite a saída enviada de volta ao Claude para não consumir contexto com logs enormes.

Use case 4: revisar a sessão com Stop

Stop dispara quando Claude está prestes a terminar. É um bom lugar para registrar resumo ou bloquear apenas estados claramente incompletos, como conflitos de Git não resolvidos.

import fs from "node:fs";
import { execFileSync } from "node:child_process";

const input = JSON.parse(fs.readFileSync(0, "utf8") || "{}");

if (input.stop_hook_active) {
  process.exit(0);
}

let status = "";
try {
  status = execFileSync("git", ["status", "--short"], {
    cwd: process.cwd(),
    encoding: "utf8"
  });
} catch {
  process.exit(0);
}

if (status.includes("UU ")) {
  console.error("Git conflict remains. Resolve conflicts before finishing.");
  process.exit(2);
}

fs.mkdirSync(".claude/hook-logs", { recursive: true });
fs.appendFileSync(
  ".claude/hook-logs/stop.jsonl",
  JSON.stringify({
    time: new Date().toISOString(),
    lastAssistantMessage: input.last_assistant_message || "",
    gitStatus: status.slice(0, 2000)
  }) + "\n"
);

Tome cuidado com Stop. Se bloquear demais, o agente pode parecer preso tentando finalizar. Verifique stop_hook_active, mantenha condições estreitas e comece registrando mais do que bloqueando.

Pitfall: erros comuns e como evitar

O primeiro pitfall é tratar Hooks como substituto de permissões. Um command hook roda com as permissões do seu usuário do sistema. Se estiver mal escrito, pode ler segredos ou apagar arquivos. Valide entradas, proteja caminhos, evite .env e .git, e trate path traversal.

O segundo pitfall é executar trabalho demais de forma síncrona. Formatar um arquivo é aceitável. Rodar build, testes completos, browser tests e deploy depois de cada edição geralmente pesa demais. Checks rápidos ficam no PostToolUse; checks lentos vão para async ou CI.

O terceiro pitfall é salvar logs sem política. Logs ajudam no debug, mas podem conter informação sensível. Defina local, retenção, acesso e exclusão do Git antes de padronizar.

O quarto pitfall é confundir matcher com lógica de negócio. matcher: "Bash" só envia eventos Bash para o handler. A decisão real precisa analisar o comando completo dentro do script.

Nota de verificação no estilo Masa

Na prática, o maior ganho veio de devolver format e test para Claude com additionalContext. Claude consegue corrigir o próximo passo sem alguém copiar logs no chat. O bloqueio de comandos perigosos também ajuda, não porque é perfeito, mas porque para erros óbvios no momento certo.

Para um time iniciante, eu implantaria em três etapas: uma semana de logs de prompts, depois format após edição, e então uma lista pequena de padrões Bash proibidos. Esse caminho cria confiança antes de adicionar atrito.

Se quiser levar isso para o time, a página de training de Claude Code cobre permissões, CLAUDE.md, Hooks e review workflow. Para uso individual, o mesmo conteúdo pode virar uma checklist Gumroad para iniciar projetos com uma base repetível.

Resumo

Claude Code Hooks são guardrails práticos. Use UserPromptSubmit para entender solicitações, PreToolUse para bloquear ações arriscadas, PostToolUse para verificar mudanças e Stop para não encerrar com problemas evidentes.

Comece pequeno. Um Hook simples que continua ligado vale mais do que uma automação ambiciosa que o time desativa depois de dois dias.

#Claude Code #Hooks #automation #security #testing
Grátis

PDF grátis: cheatsheet do Claude Code

Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.

Cuidamos dos seus dados e não enviamos spam.

Masa

Sobre o autor

Masa

Engenheiro focado em workflows práticos com Claude Code.