Visão geral
O failproofai possui dois subsistemas independentes:- Hook handler - Um subprocesso CLI rápido que o Claude Code invoca a cada chamada de ferramenta do agente. Avalia as políticas e retorna uma decisão.
- Monitor de Agentes (Dashboard) - Uma aplicação web Next.js para monitorar sessões de agentes e gerenciar políticas.
~/.failproofai/ e no diretório .failproofai/ do projeto, mas são executados como processos separados e se comunicam apenas pelo sistema de arquivos.
Hook handler
Integração com o Claude Code
Quando você executafailproofai policies --install, ele escreve entradas como esta em ~/.claude/settings.json:
failproofai --hook PreToolUse como subprocesso antes de cada chamada de ferramenta, passando um payload JSON via stdin.
Formato do payload
PostToolUse, o payload também contém tool_result com a saída da ferramenta.
O handler impõe um limite de 1 MB para stdin. Payloads que excedam esse tamanho são descartados e todas as políticas permitem implicitamente.
Formato da resposta
Deny (PreToolUse):- Código de saída:
2 - Motivo escrito em stderr (não em stdout)
- Código de saída:
0 - stdout vazio
allow(message) permite que uma política envie contexto informativo de volta ao Claude mesmo quando a operação é permitida. O hook handler escreve o seguinte JSON em stdout (não em um arquivo de configuração — esta é a resposta do handler ao Claude Code, assim como as respostas de deny e instruct acima):
- Código de saída:
0(a operação é permitida) - Quando múltiplas políticas retornam
allowcom uma mensagem, suas mensagens são unidas com quebras de linha em uma única stringadditionalContext - Se nenhuma política fornecer uma mensagem, stdout fica vazio (igual ao comportamento anterior)
Pipeline de processamento
src/hooks/handler.ts implementa o pipeline completo:
Carregamento de configuração
src/hooks/hooks-config.ts implementa o carregamento de configuração em três escopos.
enabledPolicies- união sem duplicatas entre os três arquivospolicyParams- por chave de política, o primeiro arquivo que a define vence inteiramentecustomPoliciesPath- o primeiro arquivo que a define vencellm- o primeiro arquivo que a define vence
readHooksConfig() (somente global) para leitura e escrita, pois não é invocado com um cwd de projeto.
Avaliação de políticas
src/hooks/policy-evaluator.ts executa as políticas em ordem.
Para cada política:
- Busca o esquema de
paramsda política (se houver). - Lê
policyParams[policy.name]da configuração mesclada. - Mescla os valores fornecidos pelo usuário sobre os padrões do esquema para produzir
ctx.params. - Chama
policy.fn(ctx)com o contexto resolvido. - Se o resultado for
deny, interrompe imediatamente e retorna essa decisão. - Se o resultado for
instruct, acumula a mensagem e continua. - Se o resultado for
allow, continua para a próxima política.
- Se algum
denyfoi retornado, emite a resposta de deny. - Se algum retorno
instructfoi coletado, emite uma única resposta instruct com todas as mensagens unidas. - Caso contrário, emite uma resposta allow (stdout vazio, saída 0).
Políticas embutidas
src/hooks/builtin-policies.ts define todas as 26 políticas embutidas como objetos BuiltinPolicyDefinition:
params declaram um PolicyParamsSchema com tipos e valores padrão para cada parâmetro. O avaliador de políticas injeta os valores resolvidos em ctx.params antes de chamar fn. As funções de política leem ctx.params sem verificações de nulo porque os padrões são sempre aplicados primeiro.
A correspondência de padrões dentro das políticas usa tokens de comando analisados (argv), não correspondência de strings brutas. Isso evita bypass por injeção de operadores shell (por exemplo, um padrão para sudo systemctl status * não pode ser ignorado anexando ; rm -rf / ao comando).
Políticas personalizadas
src/hooks/custom-hooks-registry.ts implementa um registro baseado em globalThis:
src/hooks/custom-hooks-loader.ts carrega o arquivo de políticas do usuário:
- Lê
customPoliciesPathda configuração; ignora se ausente. - Resolve para caminho absoluto; verifica se o arquivo existe.
- Reescreve todas as importações
from "failproofai"para o caminho real do dist, de modo quecustomPoliciesresolva para o mesmo registroglobalThis. - Reescreve recursivamente importações locais transitivas para garantir compatibilidade ESM.
- Grava arquivos
.mjstemporários e realizaimport()do arquivo de entrada. - Chama
getCustomHooks()para recuperar os hooks registrados. - Limpa todos os arquivos temporários em um bloco
finally.
~/.failproofai/hook.log e o loader retorna um array vazio. As políticas embutidas não são afetadas.
As políticas personalizadas são avaliadas após todas as políticas embutidas. Um deny de política personalizada ainda interrompe as demais políticas personalizadas (mas todos os embutidos já terão sido executados nesse ponto).
Log de atividade
Após cada evento de hook, o handler anexa uma linha JSONL em~/.failproofai/hook-activity.jsonl:
Arquitetura do dashboard
O dashboard é uma aplicação Next.js 16 usando o App Router com React Server Components e Server Actions.- Os componentes de página chamam
lib/projects.tselib/log-entries.tspara ler dados de projeto/sessão diretamente do sistema de arquivos (sem camada de API para leituras). - A página de Políticas usa Server Actions para todas as mutações (alternar, atualizar parâmetros, instalar/remover).
- O visualizador de sessão analisa o formato de transcrição JSONL do Claude e renderiza uma linha do tempo de mensagens e chamadas de ferramentas.
- Sem banco de dados - todo estado persistente está em arquivos simples (
~/.failproofai/,~/.claude/projects/). - Server Actions para mutações - sem necessidade de API REST para operações CRUD.
- React Server Components para páginas de leitura - carregamento inicial mais rápido, sem bundle no cliente para busca de dados.
- Client components apenas onde interatividade é necessária (alternância de políticas, busca de atividade, visualizador de log).

