Toda regra do time que vive só na cabeça das pessoas vai ser quebrada mais cedo ou mais tarde. "Sempre roda o prettier antes de commitar." "Nunca deixa subir direto pra main." "Lint antes de declarar pronto." Com gente isso já vazava. Com um agente que toma dezenas de decisões por minuto, vaza na primeira sessão distraída. Hooks são onde essas regras param de ser folclore e viram contrato executável.
Hook, no Claude Code, é um comando de shell que o harness dispara automaticamente em eventos
do ciclo de vida da sessão. Eles ficam no settings.json, não no julgamento do
modelo. Essa é a parte que importa: o agente não decide se vai rodar o hook. O harness roda,
toda vez, independente do que o modelo "lembrou" de fazer. É justamente por serem
determinísticos e fora da discrição do agente que eles servem de guardrail.
Antes: validar e bloquear
O evento mais poderoso é o PreToolUse. Ele roda antes de uma ferramenta
executar e pode barrar a ação. Um hook que sai com código de saída 2, ou que devolve um JSON
com permissionDecision: "deny", impede a chamada de acontecer e ainda diz ao
agente por quê. É aqui que mora o "nunca deixa subir pra main": um matcher no Bash que
inspeciona o comando e nega qualquer git push que aponte pra branch protegida. Não
é uma sugestão no prompt. É uma porta trancada.
"Um guardrail que depende do modelo lembrar não é um guardrail - é uma esperança."
A diferença prática é brutal. Pedir "por favor não dê push na main" no
CLAUDE.md funciona até a sessão ficar longa o suficiente pra aquela instrução sair
de foco. O PreToolUse não esquece, não fica distraído e não negocia. Ou o comando
passa no filtro, ou ele simplesmente não roda.
Depois: formatar e verificar
O PostToolUse roda depois que a ferramenta já executou - então ele não bloqueia,
ele reage. O caso clássico é o auto-format: um matcher em Write|Edit que pega o arquivo
recém-editado e roda o prettier nele. O agente nem precisa saber que isso existe; o código sai
formatado do jeito do time, toda vez. É exatamente o padrão que uso aqui no portfólio, com a formatação
amarrada num hook de pós-edição.
O mesmo evento serve pra verificação barulhenta. Editou um arquivo de teste? Roda o teste e injeta o resultado de volta no contexto. Mexeu num schema? Dispara o type-check. O ponto não é deixar bonito - é fechar o loop sem depender do agente "lembrar" de validar antes de dizer que terminou.
Guardrail bom falha barulhento e determinístico. Se a única coisa que segura uma regra é o modelo se lembrar dela, ela não é uma regra - é um detalhe de implementação esperando pra dar errado.
Ao redor: preparar o terreno
Tem ainda os eventos que cercam a sessão inteira. O SessionStart roda quando a conversa
começa e é ótimo pra carregar contexto que o agente vai precisar de qualquer jeito: a branch atual,
as issues abertas, o estado do banco local. O Stop roda quando o agente acha que
terminou - e pode impedir que ele pare se um gate não passou, devolvendo a bola: "o lint ainda
está falhando, continua". Antes, depois e ao redor: os três cercam a autonomia do agente sem amarrar
o que ele faz no meio.
No fim, hooks são a forma de codificar a cultura do time num arquivo versionado - e uma das peças centrais do harness em volta do agente. As regras que antes viviam num canal do Slack, num onboarding mal documentado ou na memória de quem está há mais tempo viram um contrato que o agente assina sem ter escolha. E contrato que não depende de boa vontade é o único que aguenta produção.