title: Architettura description: “Come funzionano internamente il gestore hook, il caricamento della configurazione e la valutazione delle policy” icon: sitemap
Questo documento spiega come failproofai funziona internamente: come il sistema di hook intercetta le chiamate agli strumenti dell’agente, come viene caricata e unita la configurazione, come vengono valutate le policy e come il dashboard monitora l’attività dell’agente.Panoramica
failproofai ha due sottosistemi indipendenti:- Gestore hook - Un veloce sottoprocesso CLI che Claude Code richiama per ogni chiamata allo 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, vengono scritte voci come questa in ~/.claude/settings.json:
failproofai --hook PreToolUse come sottoprocesso prima di ogni chiamata allo strumento, passando un payload JSON su stdin.
Formato del payload
PostToolUse, il payload contiene anche tool_result con l’output dello strumento.
Il gestore applica un limite di 1 MB per stdin. 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 un file di configurazione — questa è la risposta del gestore a Claude Code, proprio come le risposte deny e instruct precedenti):
- Codice di uscita:
0(l’operazione è consentita) - Quando più policy restituiscono
allowcon un messaggio, i loro messaggi vengono uniti con interruzioni di riga in una singola stringaadditionalContext - Se nessuna policy fornisce un messaggio, stdout è vuoto (come 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 in tre ambiti.
enabledPolicies- unione deduplicate tra tutti e tre i filepolicyParams- per chiave di policy, il primo file che la definisce vince completamentecustomPoliciesPath- il primo file che la definisce vincellm- il primo file che la definisce vince
readHooksConfig() (solo globale) per la lettura e la scrittura, poiché non viene richiamato con un cwd di progetto.
Valutazione delle policy
src/hooks/policy-evaluator.ts esegue le policy in ordine.
Per ogni policy:
- Cerca lo schema
paramsdella policy (se ne ha uno). - Leggi
policyParams[policy.name]dalla configurazione unita. - Unisci i valori forniti dall’utente sui valori predefiniti dello schema per produrre
ctx.params. - Chiama
policy.fn(ctx)con il contesto risolto. - Se il risultato è
deny, fermarti immediatamente e restituisci quella decisione. - Se il risultato è
instruct, accumula il messaggio e continua. - Se il risultato è
allow, continua alla policy successiva.
- Se è stata restituita una qualsiasi
deny, emetti la risposta deny. - Se sono state raccolte risposte
instruct, emetti una singola risposta instruct con tutti i messaggi uniti. - Altrimenti, emetti una risposta allow (stdout vuoto, exit 0).
Policy integrate
src/hooks/builtin-policies.ts definisce tutte le 39 policy integrate come oggetti BuiltinPolicyDefinition:
params dichiarano uno PolicyParamsSchema con tipi e valori predefiniti 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 protezioni null perché i valori predefiniti vengono sempre applicati prima.
La corrispondenza dei pattern all’interno delle policy utilizza token di comando analizzati (argv), non la 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:
- Leggi
customPoliciesPathdalla configurazione; salta se assente. - Risolvi al percorso assoluto; controlla che il file esista.
- Riscrivi tutti gli import
from "failproofai"al percorso dist effettivo in modo checustomPoliciessi risolva nello stesso registroglobalThis. - Riscrivi ricorsivamente gli import locali transitivi per assicurare la compatibilità ESM.
- Scrivi file
.mjstemporanei e esegui l’import del file di entry. - Chiama
getCustomHooks()per recuperare gli hook registrati. - Pulisci tutti i file temp in un blocco
finally.
~/.failproofai/hook.log e il caricatore restituisce un array vuoto. Le policy integrate non sono interessate.
Le policy personalizzate vengono valutate dopo tutte le policy integrate. Una policy personalizzata deny interrompe ancora ulteriormente le policy personalizzate (ma a quel punto tutte le policy integrate sono già state eseguite).
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 App Router con React Server Components e Server Actions.- I componenti della pagina chiamano
lib/projects.tselib/log-entries.tsper leggere i dati di progetto/sessione direttamente dal filesystem (nessun livello API per le letture). - La pagina Policies utilizza Server Actions per tutte le mutazioni (attiva/disattiva, aggiornamento params, installa/rimuovi).
- Il visualizzatore di sessione analizza il formato di trascrizione JSONL di Claude e renderizza una timeline di messaggi e chiamate allo strumento.
- Nessun database - tutto lo stato persistente è in file ordinari (
~/.failproofai/,~/.claude/projects/). - Server Actions per mutazioni - nessuna API REST necessaria per operazioni CRUD.
- React Server Components per pagine di lettura - caricamento iniziale più veloce, nessun bundle client per il recupero dati.
- Componenti client solo dove è necessaria l’interattività (attiva/disattiva policy, ricerca attività, visualizzatore log).

