Vue d’ensemble
failproofai comporte deux sous-systèmes indépendants :- Gestionnaire de hooks - Un sous-processus CLI rapide que Claude Code invoque à chaque appel d’outil d’agent. Il évalue les politiques et retourne une décision.
- Moniteur d’agent (Tableau de bord) - Une application web Next.js pour surveiller les sessions d’agent et gérer les politiques.
~/.failproofai/ et le répertoire .failproofai/ du projet, mais s’exécutent en tant que processus séparés et ne communiquent qu’à travers le système de fichiers.
Gestionnaire de hooks
Intégration avec Claude Code
Lorsque vous exécutezfailproofai policies --install, des entrées comme celle-ci sont écrites dans ~/.claude/settings.json :
failproofai --hook PreToolUse en tant que sous-processus avant chaque appel d’outil, en transmettant un payload JSON sur stdin.
Format du payload
PostToolUse, le payload contient également tool_result avec la sortie de l’outil.
Le gestionnaire impose une limite de 1 Mo sur stdin. Les payloads dépassant cette limite sont ignorés et toutes les politiques autorisent implicitement.
Format de la réponse
Refus (PreToolUse) :- Code de sortie :
2 - Raison écrite sur stderr (pas sur stdout)
- Code de sortie :
0 - stdout vide
allow(message) permet à une politique d’envoyer un contexte informatif à Claude même lorsque l’opération est autorisée. Le gestionnaire de hooks écrit le JSON suivant sur stdout (pas dans un fichier de configuration — il s’agit de la réponse du gestionnaire à Claude Code, tout comme les réponses de refus et d’instruction ci-dessus) :
- Code de sortie :
0(l’opération est autorisée) - Lorsque plusieurs politiques retournent
allowavec un message, leurs messages sont joints par des sauts de ligne en une seule chaîneadditionalContext - Si aucune politique ne fournit de message, stdout est vide (comme auparavant)
Pipeline de traitement
src/hooks/handler.ts implémente le pipeline complet :
Chargement de la configuration
src/hooks/hooks-config.ts implémente le chargement de configuration à trois portées.
enabledPolicies- union dédupliquée sur les trois fichierspolicyParams- par clé de politique, le premier fichier qui la définit l’emporte entièrementcustomPoliciesPath- le premier fichier qui le définit l’emportellm- le premier fichier qui le définit l’emporte
readHooksConfig() (global uniquement) pour la lecture et l’écriture, car il n’est pas invoqué avec un répertoire de travail de projet.
Évaluation des politiques
src/hooks/policy-evaluator.ts exécute les politiques dans l’ordre.
Pour chaque politique :
- Rechercher le schéma
paramsde la politique (si elle en possède un). - Lire
policyParams[policy.name]depuis la configuration fusionnée. - Fusionner les valeurs fournies par l’utilisateur sur les valeurs par défaut du schéma pour produire
ctx.params. - Appeler
policy.fn(ctx)avec le contexte résolu. - Si le résultat est
deny, s’arrêter immédiatement et retourner cette décision. - Si le résultat est
instruct, accumuler le message et continuer. - Si le résultat est
allow, passer à la politique suivante.
- Si un
denya été retourné, émettre la réponse de refus. - Si des retours
instructont été collectés, émettre une seule réponse d’instruction avec tous les messages joints. - Sinon, émettre une réponse d’autorisation (stdout vide, code de sortie 0).
Politiques intégrées
src/hooks/builtin-policies.ts définit les 26 politiques intégrées sous forme d’objets BuiltinPolicyDefinition :
params déclarent un PolicyParamsSchema avec les types et les valeurs par défaut de chaque paramètre. L’évaluateur de politiques injecte les valeurs résolues dans ctx.params avant d’appeler fn. Les fonctions de politique lisent ctx.params sans vérification de nullité, car les valeurs par défaut sont toujours appliquées en premier.
La correspondance de motifs à l’intérieur des politiques utilise des tokens de commande analysés (argv), et non une correspondance de chaînes brutes. Cela empêche le contournement via l’injection d’opérateurs shell (par exemple, un motif pour sudo systemctl status * ne peut pas être contourné en ajoutant ; rm -rf / à la commande).
Politiques personnalisées
src/hooks/custom-hooks-registry.ts implémente un registre basé sur globalThis :
src/hooks/custom-hooks-loader.ts charge le fichier de politique de l’utilisateur :
- Lire
customPoliciesPathdepuis la configuration ; ignorer si absent. - Résoudre le chemin absolu ; vérifier que le fichier existe.
- Réécrire tous les imports
from "failproofai"vers le chemin dist réel afin quecustomPoliciesrésolve vers le même registreglobalThis. - Réécrire récursivement les imports locaux transitifs pour assurer la compatibilité ESM.
- Écrire des fichiers
.mjstemporaires etimport()le fichier d’entrée. - Appeler
getCustomHooks()pour récupérer les hooks enregistrés. - Nettoyer tous les fichiers temporaires dans un bloc
finally.
~/.failproofai/hook.log et le chargeur retourne un tableau vide. Les politiques intégrées ne sont pas affectées.
Les politiques personnalisées sont évaluées après toutes les politiques intégrées. Un deny d’une politique personnalisée court-circuite quand même les politiques personnalisées suivantes (mais toutes les politiques intégrées ont déjà été exécutées à ce stade).
Journalisation de l’activité
Après chaque événement de hook, le gestionnaire ajoute une ligne JSONL dans~/.failproofai/hook-activity.jsonl :
Architecture du tableau de bord
Le tableau de bord est une application Next.js 16 utilisant l’App Router avec des React Server Components et des Server Actions.- Les composants de page appellent
lib/projects.tsetlib/log-entries.tspour lire les données de projet/session directement depuis le système de fichiers (pas de couche API pour les lectures). - La page Politiques utilise des Server Actions pour toutes les mutations (activation/désactivation, mise à jour des paramètres, installation/suppression).
- Le visualiseur de session analyse le format de transcript JSONL de Claude et affiche une chronologie des messages et des appels d’outils.
- Pas de base de données - tout l’état persistant est dans des fichiers simples (
~/.failproofai/,~/.claude/projects/). - Server Actions pour les mutations - aucune API REST nécessaire pour les opérations CRUD.
- React Server Components pour les pages de lecture - chargement initial plus rapide, pas de bundle client pour la récupération des données.
- Composants client uniquement là où l’interactivité est nécessaire (bascules de politique, recherche d’activité, visualiseur de journal).

