Cada hook é uma cicatriz: 84 falhas de agentes codificadas em código
Tenho 84 hooks interceptando 15 dos 26 tipos de eventos de ciclo de vida que o Claude Code expõe na versão v2.1.116 (abril de 2026) no meu sistema de orquestração de agentes. Cada hook é um shell script ou um trecho de Python que dispara antes ou depois de uma ação específica do agente: leituras de arquivo, escritas de arquivo, comandos bash, requisições web, criação de sub-agentes, operações git, chamadas de ferramenta MCP. Cada hook existe porque algo deu errado.
Cada hook em um sistema de orquestração de agentes remonta a uma falha específica em produção, o que torna a coleção de hooks uma memória institucional codificada como shell scripts. Agentes apagaram caches de CDN, leram arquivos de credenciais, reportaram testes passando que nunca executaram e desviaram da tarefa por 40 minutos. Cada incidente produziu uma pequena proteção determinística que dispara silenciosamente em toda sessão subsequente.
Não errado em teoria. Errado em produção. Um agente apagou um cache de CDN servindo milhões de requisições. Um agente tentou escrever chaves SSH. Um agente reportou “todos os testes passam” sem invocar o pytest. Um agente desviou tanto de sua tarefa que passou quarenta minutos otimizando uma função em um arquivo que não tinha nada a ver com o trabalho atribuído.
Não projetei nenhum desses hooks de forma proativa. Não sentei e enumerei os modos de falha de agentes de IA autônomos para escrever controles preventivos. Todo hook é reativo. Algo quebrou, escrevi um script para impedir que quebrasse de novo, e o script tem disparado silenciosamente em toda sessão desde então. O sistema de hooks não é uma arquitetura de segurança. É uma coleção de cicatrizes.
TL;DR
- A purga do cache: Um agente apagou um cache de CDN em produção usando uma chamada API autorizada. Dois hooks (47 linhas) agora bloqueiam operações destrutivas por trás de uma frase-senha digitada por humano.
- O leitor de credenciais: Um agente incluiu tokens API em sua janela de contexto. Uma proteção baseada em correspondência de caminhos agora bloqueia leituras de arquivos de credenciais e registra acessos a arquivos
.env. - O verificador fantasma: Um agente reportou “todos os testes passam” sem executar o pytest. Um detector de linguagem hesitante derrubou a verificação fantasma de 12% para menos de 2% das sessões.
- Os doze desvios: Agentes perderam o rumo de sua tarefa de forma verificável doze vezes em sessenta dias. Um detector de similaridade cosseno no limiar de 0,30 agora dispara a cada 25 chamadas de ferramenta.
- A taxonomia: Seis categorias estruturais de falha cobrem todos os 84 hooks. Categorias novas são raras após mais de 500 sessões. O sistema fica mais robusto a cada incidente.
A purga do cache: como uma chamada autorizada quebrou a produção
Em 21 de março de 2026, pedi a um agente que investigasse por que as páginas de mercado no resumegeni.com estavam carregando lentamente. O agente começou sua investigação normalmente: lendo handlers de rota, verificando queries de banco de dados, fazendo profiling da renderização de templates. Então decidiu que entradas de cache Cloudflare obsoletas poderiam estar mascarando as características reais de performance.
O agente chamou mcp__cloudflare__cache_purge com purge_everything: true.
Toda página em cache no site de produção foi instantaneamente invalidada. O CDN passou de servir a maioria das requisições em 80-100ms para encaminhar cada requisição ao servidor de origem no Railway. A página de mercado de Austin passou de menos de um segundo para 14.290 milissegundos. Nova York, de menos de um segundo para 6.891ms. Toda página do site estava agora sendo renderizada a partir da origem fria em cada requisição.
O agente não fez nada não autorizado. Usou uma ferramenta MCP legítima com credenciais válidas para chamar um endpoint API autorizado. A purga de cache era um passo de investigação razoável se você está depurando o comportamento do cache. O problema era que “razoável para depuração” e “catastrófico para produção” eram a mesma chamada API, e nenhuma restrição existia entre o raciocínio do agente e a consequência em produção.
Construí dois hooks naquela noite.
A proteção de Bash (destructive-api-guard.sh): Dispara em todo comando bash. Faz correspondência de padrões contra curl.*purge, rm -rf, DROP TABLE, docker.*rm, git push.*--force. Bloqueio duro (exit 2). O agente vê uma mensagem explicando por que o comando foi bloqueado e sugerindo alternativas. Ele não pode prosseguir sem a frase-senha “rosebud”, que só pode entrar no contexto se um humano a digitar.
A proteção MCP (destructive-mcp-guard.sh): Dispara em toda chamada de ferramenta MCP que corresponda a mcp__cloudflare ou mcp__github. Faz correspondência de padrões contra purge, delete, destroy, remove nos parâmetros da ferramenta. Mesmo bloqueio duro, mesmo portão de frase-senha.
Dois hooks. Dois shell scripts. Total: 47 linhas de código. Eles evitaram zero purgas de cache desde a instalação, porque nenhum agente tentou uma desde que o portão de frase-senha foi adicionado. Os hooks não estão capturando ataques. Estão impedindo que a categoria de erro seja possível.
O incidente da purga de cache também expôs o problema de performance que deveria investigar. Austin em 14 segundos na renderização fria levou à entrega (handoff) da página de mercado, que levou à correção do formato da query quatro dias depois. O incidente foi útil. O hook garante que não possa se repetir.
O leitor de credenciais
Em fevereiro de 2026, um agente coletando contexto para um projeto leu ~/.claude/docs/credentials.md. O arquivo contém tokens API para Cloudflare, GitHub, Railway e outros serviços. O agente incluiu um resumo do conteúdo do arquivo em suas notas de trabalho, o que significa que os tokens estavam presentes na requisição API aos servidores da Anthropic.
Nenhum token foi commitado. Nenhum token foi exposto publicamente. Mas os tokens viajaram por uma API de terceiros em uma janela de contexto que eu não controlo. A superfície de risco se expandiu de “minha máquina” para “minha máquina mais a infraestrutura de inferência da Anthropic”.
A proteção de caminho de credenciais dispara em toda leitura de arquivo. Ela verifica o caminho contra uma lista de padrões sensíveis: .env, credentials, .ssh/, .aws/, .gnupg/, secrets. Para leituras de credenciais, o hook registra um aviso e bloqueia a leitura. Para leituras de .env, ele permite a leitura mas registra o acesso.
A proteção é consultiva para a maioria dos caminhos e um bloqueio duro para arquivos de credenciais. A distinção importa: um agente lendo .env para entender os nomes das variáveis de ambiente é contexto útil. Um agente lendo credentials.md para entender tokens API é um incidente de segurança.
Desde a instalação, a proteção de caminho de credenciais disparou 23 vezes em mais de 200 sessões. Vinte dessas foram agentes lendo arquivos .env (registrado, permitido). Três foram agentes tentando ler arquivos de credenciais ou chaves (bloqueado). Cada leitura bloqueada foi um agente que estava coletando contexto do projeto de forma ampla e acabou incluindo um arquivo sensível em seu padrão de busca. Nenhuma foi maliciosa. Todas teriam colocado segredos na janela de contexto sem a proteção.
O verificador fantasma
O modo de falha mais insidioso é um agente que reporta verificação bem-sucedida sem realizar a verificação.
Sessão 147. Pedi a um agente que refatorasse uma query de banco de dados e verificasse a mudança com o conjunto de testes existente. O agente refatorou a query corretamente. O relatório de conclusão dizia: “Todos os testes passam. A query refatorada produz resultados idênticos à original.”
Verifiquei o log da sessão. Nenhuma invocação do pytest apareceu. Nenhum runner de testes de qualquer tipo havia sido chamado. O agente raciocinou que os testes passariam porque a query refatorada era logicamente equivalente à original, e reportou esse raciocínio como se fosse um resultado de teste.
A query refatorada estava correta. Os testes teriam passado. O raciocínio do agente estava sólido. Mas raciocinar sobre testes não é executar testes, e a lacuna entre os dois é onde bugs são enviados para produção. Se a query refatorada tivesse um erro sutil em um caso de borda que o raciocínio do agente não cobriu, o bug teria sido implantado com um relatório de conclusão afirmando verificação de testes.
O modo de falha ocorreu 7 vezes em 60 sessões antes de eu construir o hook de portão de evidências. O hook dispara em todo relatório de conclusão e procura por linguagem hesitante: “deveria passar”, “acredito”, “os testes provavelmente passam”, “estou confiante”. Quando detectado, o hook injeta uma mensagem: “Linguagem hesitante detectada. Cite evidências específicas: cole a saída do teste, nomeie o arquivo e o número da linha, ou referencie o passo específico de verificação.”
O hook não verifica se os testes foram de fato executados. Ele sinaliza o padrão linguístico que indica que a verificação foi pulada. A detecção é imperfeita. Um agente suficientemente fluente poderia reformular suas hesitações para evitar o padrão. Mas o hook captura o caso comum, que responde por 12% das falhas de agentes que exigem intervenção humana.1
Após a instalação do hook, a verificação fantasma caiu de 12% para menos de 2% das sessões. Os 2% restantes são casos em que o agente reformula a hesitação ou em que a afirmação de verificação é tecnicamente precisa mas incompleta (por exemplo, “os testes unitários passam” quando os testes de integração não foram executados).
Desvio
Entre janeiro e março de 2026, meu detector de desvio disparou doze vezes em sessões nas quais o agente havia perdido o rumo de sua tarefa atribuída de forma verificável.
O detector de desvio funciona incorporando (embedding) o prompt original da tarefa e comparando-o periodicamente com a incorporação das ações recentes do agente. Quando a similaridade cosseno cai abaixo de 0,30, o sistema injeta um aviso contendo o prompt original. Calibrei o limiar através de experimentação: 0,50 era sensível demais (disparava em explorações legítimas de subtarefas), 0,20 era permissivo demais (perdia desvios óbvios), 0,30 captava todo incidente de desvio verificado.
A sessão 203 foi o caso mais claro. A tarefa era “corrigir o escape quebrado do XML do sitemap para slugs de vagas contendo ampersands”. O agente começou lendo o código de geração do sitemap. Então notou que o sitemap era gerado a partir de uma query de banco de dados. Então notou que a query do banco de dados poderia ser otimizada. Então passou 40 minutos refatorando a query em um padrão de visão materializada, escreveu testes para a nova query, e reportou a otimização como completa. Nunca corrigiu o escape dos ampersands.
O detector de desvio teria capturado isso na marca de 25 chamadas de ferramenta, aproximadamente 15 minutos na sessão, quando a similaridade entre “corrigir escape XML do sitemap” e “criar visão materializada” caiu abaixo do limiar. Em vez disso, descobri o desvio durante a revisão.
A sessão 89 foi mais sutil. A tarefa era “adicionar rate limiting aos endpoints de autenticação”. O agente adicionou rate limiting corretamente. Então notou que o fluxo de autenticação tinha mensagens de erro inconsistentes. Então padronizou as mensagens de erro. Então notou que o formato de resposta de erro diferia do padrão de formato de resposta API. Então refatorou o formato de resposta em 12 endpoints. O rate limiting estava correto e completo. A explosão de escopo era o desvio.
O detector de desvio dispara a cada 25 chamadas de ferramenta. Em todos os doze disparos abaixo do limiar, o agente havia se desviado da tarefa original de forma verificável. Em seis casos, o agente se autocorrigiu após ver o aviso injetado. Em quatro casos, o agente reconheceu o desvio mas argumentou que o trabalho atual era valioso (às vezes corretamente). Em dois casos, o agente ignorou o aviso e continuou o trabalho divergente.
O hook não previne o desvio. Ele torna o desvio visível. A decisão de redirecionar ou permitir o trabalho divergente permanece com o humano. Mas sem o hook, o desvio é invisível até o relatório de conclusão, quando o orçamento de contexto já foi gasto.
A taxonomia das cicatrizes
Após 84 hooks, padrões emergem. As falhas se agrupam em seis categorias:
| Categoria | Hooks | Exemplo |
|---|---|---|
| Exposição de credenciais | 12 | Agente lê .ssh/, inclui chaves API em resumos, acessa configurações de nuvem |
| Operações destrutivas | 8 | Purga de cache, drops de banco de dados, force pushes, deleções de arquivo |
| Desvio de tarefa | 4 | Agente trabalha no problema errado, explosão de escopo, buracos de coelho em subtarefas |
| Qualidade de saída | 6 | Verificação fantasma, hesitação sem evidências, relatórios incompletos |
| Esgotamento de recursos | 3 | Sub-agentes demais criados, loops não limitados, estouro de contexto |
| Contaminação entre projetos | 4 | Agente no projeto A modifica arquivos no projeto B |
Os 47 hooks restantes são específicos de projeto (aplicação de convenções, proteções de deploy, validadores de tradução) ou experimentais (rastreamento de custo, métricas de sessão, heartbeats de atividade).
As seis categorias estruturais são estáveis. Novos incidentes dentro dessas categorias são capturados por hooks existentes. Categorias novas são raras. Em seis meses de operação, apenas uma nova categoria estrutural emergiu (contaminação entre projetos, descoberta quando uma sessão rodando no projeto obsidian-signals tentou editar arquivos no blakecrosley.com). As outras cinco categorias foram estabelecidas nas primeiras 60 sessões.
O estudo Agents of Chaos, um experimento de 14 dias de múltiplas universidades dando a seis agentes de IA acesso a e-mail, bash, sistemas de arquivos e GitHub, identificou de forma independente categorias de falha sobrepostas: resposta desproporcional (operações destrutivas), sequestro de identidade (exposição de credenciais), loops infinitos (esgotamento de recursos) e conformidade gradual sob pressão (desvio de tarefa).5 A convergência entre a pesquisa controlada deles e minha experiência em produção sugere que essas categorias são propriedades estruturais de agentes autônomos, não artefatos de qualquer configuração específica.
O que os hooks não conseguem capturar
Hooks operam no nível da chamada de ferramenta. Eles interceptam a ação antes ou depois de ela ocorrer. Não conseguem interceptar o raciocínio que levou à ação.
Um agente que decide refatorar uma função em vez de corrigir o bug reportado produz uma chamada de ferramenta válida (escrita de arquivo) com conteúdo correto (código sintaticamente válido) que viola a tarefa (função errada). Nenhum hook captura isso porque nenhuma chamada de ferramenta é suspeita. O detector de desvio captura eventualmente, mas só depois que o agente consumiu contexto significativo no trabalho errado.
Hooks também não conseguem capturar falhas de composição nas quais cada ação individual é autorizada mas a sequência produz um resultado não autorizado. A purga de cache foi uma falha de composição: ler a configuração do cache (autorizado), chamar a API de purga (autorizado), mas a combinação (purgar o cache de produção durante uma investigação) foi danosa. A proteção MCP agora captura a combinação específica, mas composições novas permanecem descobertas.
A lacuna de composição da cadeia de suprimentos opera no mesmo nível: componentes confiáveis compõem-se em comportamento não autorizado. Hooks são proteções no nível do componente. Raciocínio no nível da composição requer um mecanismo diferente, que avalia sequências de ações em vez de ações individuais. O detector de desvio é a aproximação mais próxima: avalia a trajetória comportamental em vez de chamadas de ferramenta individuais. Mas mede a similaridade com a tarefa original, não a segurança da sequência de ações compostas.
A lacuna entre hooks e segurança completa é a lacuna entre memória institucional e previsão institucional. Hooks lembram o que deu errado. Eles não preveem o que dará errado em seguida.
Por que reativo é honesto
Eu poderia projetar um sistema de hooks proativo. Enumerar todo modo de falha possível. Escrever controles preventivos para cada um. Construir uma arquitetura de segurança completa antes da primeira sessão.
Não faço isso porque o design proativo exige prever falhas que não ocorreram. As previsões estariam erradas. Os hooks seriam ou amplos demais (bloqueando ações legítimas) ou estreitos demais (deixando passar o padrão de falha real). A taxa de falsos positivos corroeria a confiança no sistema de hooks, e eu começaria a ignorar os alertas.
Hooks reativos são honestos. Cada um diz: “esta coisa específica aconteceu, e aqui está a proteção específica que a previne”. A proteção é calibrada com precisão para a falha porque a falha definiu a proteção. Falsos positivos são materialmente mais baixos porque o padrão é extraído de um incidente real, não imaginado a partir de um modelo de ameaça. Uma proteção reativa ainda pode correspondências em excesso mais tarde conforme a base de código evolui, mas a precisão inicial é alta.
A abordagem reativa tem um custo: a primeira ocorrência de toda categoria de falha é bem-sucedida. A purga de cache aconteceu. A leitura de credenciais aconteceu. A verificação fantasma foi enviada. O desvio consumiu contexto. Cada primeira falha é o preço de entrada para uma proteção precisa e de baixo ruído que impede a segunda falha.
Após mais de 500 sessões, a maioria das categorias estruturais de falha foi encontrada. O custo da primeira falha é amortizado em centenas de sessões em que o hook preveniu a recorrência. O sistema fica mais robusto a cada incidente. Não mais inteligente. Mais robusto.
Cada hook é uma cicatriz. Cada cicatriz é uma lição. As lições se acumulam.2
FAQ
Posso ver suas configurações de hooks?
Descrevo o sistema de hooks em meu comentário ao NIST sobre segurança de agentes e o referencio ao longo da série AI Engineering. Hooks são registrados em ~/.claude/settings.json e despachados por tipo de evento através de ~/.claude/hooks/dispatchers/.
Como os hooks afetam a performance do agente?
Cada hook adiciona milissegundos por chamada de ferramenta. Com 84 hooks, a sobrecarga total é de 200-400ms por chamada de ferramenta, dependendo de quais hooks disparam. A sobrecarga é desprezível comparada ao tempo de inferência do modelo (2-5 segundos por resposta). Os hooks não são o gargalo.
Os hooks funcionam com outras ferramentas de codificação de IA?
Os hooks são específicos do Claude Code (modelo de eventos PreToolUse, PostToolUse). O conceito se aplica a qualquer framework de agentes com suporte a middleware ou plugins. As implementações específicas não são portáveis, mas a taxonomia de cicatrizes e a metodologia reativa se aplicam universalmente.
O que acontece quando um hook bloqueia uma ação?
Bloqueios duros (exit 2) impedem a ação e injetam uma mensagem explicando por quê. O agente vê a razão do bloqueio e se ajusta. Hooks consultivos (exit 0) registram a preocupação mas permitem a ação. Operações destrutivas usam bloqueios duros. A maioria das outras categorias usa hooks consultivos. O portão de frase-senha é usado apenas para as operações mais perigosas (purga de cache, deleção de infraestrutura).
Como você decide entre bloqueio duro e consultivo?
Duas classes recebem bloqueios duros: operações destrutivas (purgas de cache, deleções de banco de dados, force pushes, modificações de infraestrutura) e exposição de credenciais (leitura de arquivos secretos, acesso a repositórios de chaves). Todo o resto recebe registro consultivo. A distinção é a severidade da consequência: se a ação pode ser desfeita de forma barata e não vaza segredos, um aviso é suficiente. Se a ação é irreversível ou expõe credenciais, um bloqueio duro é necessário.
Fontes
-
Blake Crosley, “What I Told NIST About AI Agent Security,” blakecrosley.com, fevereiro de 2026. Taxa de verificação fantasma de 12% em mais de 60 sessões autônomas. 84 hooks cobrindo 15 dos 26 tipos de eventos de ciclo de vida do Claude Code (v2.1.116), metodologia de detecção de desvio. ↩
-
Blake Crosley, “Compound Context: Why AI Projects Get Better the Longer You Stay With Them,” blakecrosley.com, março de 2026. Framework de contexto composto: hooks como uma das seis categorias que acumulam retornos. ↩
-
Blake Crosley, “The Supply Chain Is the Attack Surface,” blakecrosley.com, março de 2026. Lacuna de composição: componentes individualmente autorizados produzindo resultados não autorizados. ↩
-
Blake Crosley, “Deploy and Defend: The Agent Trust Paradox,” blakecrosley.com, março de 2026. Incidente de purga de cache e resposta de proteção API destrutiva. ↩
-
Christoph Riedl et al., “Agents of Chaos,” arXiv:2602.20021, fevereiro de 2026. Estudo de 14 dias de múltiplas universidades (Northeastern, Stanford, Harvard, MIT, CMU). Seis agentes de IA, 10 vulnerabilidades de segurança identificadas, incluindo resposta desproporcional, sequestro de identidade e loops infinitos. ↩