Panoramica
failproofai ha due sottosistemi indipendenti:- Gestore hook - Un veloce sottoprocesso CLI che Claude Code invoca su ogni chiamata dello strumento dell’agente. Valuta le policy e restituisce una decisione.
- Agent Monitor (Dashboard) - Un’applicazione web Next.js per monitorare le sessioni dell’agente e gestire le policy.
~/.failproofai/ e nella directory .failproofai/ del progetto, ma vengono eseguiti come processi separati e comunicano solo attraverso il filesystem.
Gestore hook
Integrazione con Claude Code
Quando eseguifailproofai policies --install, scrive voci come questa in ~/.claude/settings.json:
failproofai --hook PreToolUse come sottoprocesso prima di ogni chiamata dello strumento, passando un payload JSON su stdin.
Formato del payload
PostToolUse, il payload contiene anche tool_result con l’output dello strumento.
Il gestore impone un limite di stdin di 1 MB. I payload che superano questo limite vengono scartati e tutte le policy consentono implicitamente.
Formato della risposta
Nega (PreToolUse):- Codice di uscita:
2 - Motivo scritto su stderr (non stdout)
- Codice di uscita:
0 - Stdout vuoto
allow(message) consente a una policy di inviare un contesto informativo a Claude anche quando l’operazione è consentita. Il gestore hook scrive il seguente JSON su stdout (non su un file di configurazione — questa è la risposta del gestore a Claude Code, proprio come le risposte deny e instruct sopra):
- Codice di uscita:
0(operazione consentita) - Quando più policy restituiscono
allowcon un messaggio, i loro messaggi vengono uniti con newline in una singola stringaadditionalContext - Se nessuna policy fornisce un messaggio, stdout è vuoto (stesso di prima)
Pipeline di elaborazione
src/hooks/handler.ts implementa la pipeline completa:
Caricamento della configurazione
src/hooks/hooks-config.ts implementa il caricamento della configurazione a tre livelli.
enabledPolicies- unione deduplicate tra tutti e tre i filepolicyParams- per policy, il primo file che lo definisce vince completamentecustomPoliciesPath- il primo file che lo definisce vincellm- il primo file che lo definisce vince
readHooksConfig() (solo globale) per leggere e scrivere, poiché non viene invocato con un cwd di progetto.
Valutazione delle policy
src/hooks/policy-evaluator.ts esegue le policy in ordine.
Per ogni policy:
- Cercare lo schema
paramsdella policy (se ne ha uno). - Leggere
policyParams[policy.name]dalla configurazione unita. - Unire i valori forniti dall’utente sui default dello schema per produrre
ctx.params. - Chiamare
policy.fn(ctx)con il contesto risolto. - Se il risultato è
deny, fermarsi immediatamente e restituire quella decisione. - Se il risultato è
instruct, accumulare il messaggio e continuare. - Se il risultato è
allow, continuare alla policy successiva.
- Se è stato restituito un
deny, emettere la risposta deny. - Se sono stati raccolti ritorni
instruct, emettere una singola risposta instruct con tutti i messaggi uniti. - Altrimenti, emettere una risposta allow (stdout vuoto, uscita 0).
Policy integrate
src/hooks/builtin-policies.ts definisce tutte le 39 policy integrate come oggetti BuiltinPolicyDefinition:
params dichiarano un PolicyParamsSchema con tipi e default per ogni parametro. Il valutatore di policy inietta i valori risolti in ctx.params prima di chiamare fn. Le funzioni di policy leggono ctx.params senza protezione null perché i default vengono sempre applicati per primo.
La corrispondenza di pattern all’interno delle policy utilizza token di comando analizzati (argv), non corrispondenza di stringhe grezze. Questo previene il bypass tramite iniezione di operatori shell (ad es. un pattern per sudo systemctl status * non può essere bypassato aggiungendo ; rm -rf / al comando).
Policy personalizzate
src/hooks/custom-hooks-registry.ts implementa un registro supportato da globalThis:
src/hooks/custom-hooks-loader.ts carica il file di policy dell’utente:
- Leggere
customPoliciesPathdalla configurazione; saltare se assente. - Risolvere al percorso assoluto; controllare che il file esista.
- Riscrivere tutti gli import
from "failproofai"al percorso dist effettivo in modo checustomPoliciessi risolva nello stesso registroglobalThis. - Riscrivere ricorsivamente gli import locali transitivi per garantire la compatibilità ESM.
- Scrivere file
.mjstemporanei eimport()il file di ingresso. - Chiamare
getCustomHooks()per recuperare gli hook registrati. - Pulire tutti i file temporanei in un blocco
finally.
~/.failproofai/hook.log e il loader restituisce un array vuoto. Le policy integrate non sono interessate.
Le policy personalizzate vengono valutate dopo tutte le policy integrate. Un deny di una policy personalizzata ancora cortocircuita ulteriori policy personalizzate (ma tutte le politiche integrate sono già state eseguite a quel punto).
Registrazione dell’attività
Dopo ogni evento hook, il gestore aggiunge una riga JSONL a~/.failproofai/hook-activity.jsonl:
Architettura del dashboard
Il dashboard è un’applicazione Next.js 16 che utilizza l’App Router con React Server Components e Server Actions.- I componenti della pagina chiamano
lib/projects.tselib/log-entries.tsper leggere i dati del progetto/sessione direttamente dal filesystem (nessun livello API per le letture). - La pagina Policies utilizza Server Actions per tutte le mutazioni (toggle, aggiornamento parametri, installazione/rimozione).
- Il visualizzatore della sessione analizza il formato di trascritto JSONL di Claude e visualizza una timeline di messaggi e chiamate ai strumenti.
- Nessun database - tutto lo stato persistente si trova in file semplici (
~/.failproofai/,~/.claude/projects/). - Server Actions per le mutazioni - nessuna API REST necessaria per le operazioni CRUD.
- React Server Components per le pagine di lettura - caricamento iniziale più veloce, nessun bundle client per il recupero dei dati.
- Componenti client solo dove è necessaria l’interattività (toggle policy, ricerca attività, visualizzatore log).

