> ## Documentation Index
> Fetch the complete documentation index at: https://docs.befailproof.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Politiques personnalisées

> Écrivez vos propres politiques en JavaScript - appliquer des conventions, prévenir la dérive, détecter les échecs, s'intégrer avec des systèmes externes

Les politiques personnalisées vous permettent d'écrire des règles pour n'importe quel comportement d'agent : appliquer des conventions de projet, prévenir la dérive, bloquer les opérations destructives, détecter les agents bloqués, ou s'intégrer avec Slack, des workflows d'approbation, et plus encore. Elles utilisent le même système d'événements de hook et les mêmes décisions `allow`, `deny`, `instruct` que les politiques intégrées.

***

## Exemple rapide

```js theme={null}
// my-policies.js
import { customPolicies, allow, deny, instruct } from "failproofai";

customPolicies.add({
  name: "no-production-writes",
  description: "Block writes to paths containing 'production'",
  match: { events: ["PreToolUse"] },
  fn: async (ctx) => {
    if (ctx.toolName !== "Write" && ctx.toolName !== "Edit") return allow();
    const path = ctx.toolInput?.file_path ?? "";
    if (path.includes("production")) {
      return deny("Writes to production paths are blocked");
    }
    return allow();
  },
});
```

Installation :

```bash theme={null}
failproofai policies --install --custom ./my-policies.js
```

***

## Deux façons de charger des politiques personnalisées

### Option 1 : Par convention (recommandée)

Déposez des fichiers `*policies.{js,mjs,ts}` dans `.failproofai/policies/` et ils sont chargés automatiquement — aucun indicateur ni modification de configuration nécessaire. Cela fonctionne comme les hooks git : déposez un fichier, ça marche tout de suite.

```
# Niveau projet — commité dans git, partagé avec l'équipe
.failproofai/policies/security-policies.mjs
.failproofai/policies/workflow-policies.mjs

# Niveau utilisateur — personnel, s'applique à tous les projets
~/.failproofai/policies/my-policies.mjs
```

**Fonctionnement :**

* Les répertoires du projet et de l'utilisateur sont tous les deux analysés (union — pas de premier-scope-wins)
* Les fichiers sont chargés par ordre alphabétique dans chaque répertoire. Préfixez avec `01-`, `02-` pour contrôler l'ordre
* Seuls les fichiers correspondant à `*policies.{js,mjs,ts}` sont chargés ; les autres fichiers sont ignorés
* Chaque fichier est chargé indépendamment (fail-open par fichier)
* Fonctionne en parallèle avec les fichiers `--custom` explicites et les politiques intégrées

<Tip>
  Les politiques de convention sont le moyen le plus simple d'établir un standard de qualité pour votre organisation. Commitez `.failproofai/policies/` dans git et chaque membre de l'équipe reçoit automatiquement les mêmes règles — aucune configuration individuelle nécessaire. Au fur et à mesure que votre équipe découvre de nouveaux modes d'échec, ajoutez une politique et poussez-la. Ces politiques deviennent avec le temps un standard de qualité vivant qui s'améliore à chaque contribution.
</Tip>

### Option 2 : Chemin de fichier explicite

```bash theme={null}
# Installer avec un fichier de politiques personnalisées
failproofai policies --install --custom ./my-policies.js

# Remplacer le chemin du fichier de politiques
failproofai policies --install --custom ./new-policies.js

# Supprimer le chemin des politiques personnalisées de la configuration
failproofai policies --uninstall --custom
```

Le chemin absolu résolu est stocké dans `policies-config.json` sous la clé `customPoliciesPath`. Le fichier est rechargé à chaque événement de hook - il n'y a pas de mise en cache entre les événements.

### Utiliser les deux ensemble

Les politiques de convention et le fichier `--custom` explicite peuvent coexister. Ordre de chargement :

1. Fichier `customPoliciesPath` explicite (si configuré)
2. Fichiers de convention du projet (`{cwd}/.failproofai/policies/`, alphabétique)
3. Fichiers de convention de l'utilisateur (`~/.failproofai/policies/`, alphabétique)

***

## API

### Import

```js theme={null}
import { customPolicies, allow, deny, instruct } from "failproofai";
```

### `customPolicies.add(hook)`

Enregistre une politique. Appelez cette fonction autant de fois que nécessaire pour plusieurs politiques dans le même fichier.

```ts theme={null}
customPolicies.add({
  name: string;                         // requis - identifiant unique
  description?: string;                 // affiché dans la sortie de `failproofai policies`
  match?: { events?: HookEventType[] }; // filtre par type d'événement ; omis pour correspondre à tous
  fn: (ctx: PolicyContext) => PolicyResult | Promise<PolicyResult>;
});
```

### Fonctions d'aide aux décisions

| Fonction            | Effet                                | Utiliser quand                                                             |
| ------------------- | ------------------------------------ | -------------------------------------------------------------------------- |
| `allow()`           | Autorise l'opération silencieusement | L'action est sûre, aucun message nécessaire                                |
| `deny(message)`     | Bloque l'opération                   | L'agent ne doit pas effectuer cette action                                 |
| `instruct(message)` | Ajoute du contexte sans bloquer      | Fournir à l'agent un contexte supplémentaire pour rester sur la bonne voie |

`deny(message)` - le message apparaît à Claude préfixé par `"Blocked by failproofai:"`. Un seul `deny` court-circuite toute évaluation ultérieure.

`instruct(message)` - le message est ajouté au contexte de Claude pour l'appel d'outil en cours. Tous les messages `instruct` sont accumulés et délivrés ensemble.

<Tip>
  Vous pouvez ajouter des instructions supplémentaires à n'importe quel message `deny` ou `instruct` en ajoutant un champ `hint` dans `policyParams` — aucune modification de code nécessaire. Cela fonctionne également pour les politiques personnalisées (`custom/`), les politiques de convention de projet (`.failproofai-project/`) et les politiques de convention utilisateur (`.failproofai-user/`). Voir [Configuration → hint](/fr/configuration#hint-cross-cutting) pour plus de détails.
</Tip>

### Messages allow informationnels

`allow(message)` autorise l'opération **et** envoie un message informationnel à Claude. Le message est délivré sous forme d'`additionalContext` dans la réponse stdout du gestionnaire de hook — le même mécanisme utilisé par `instruct`, mais sémantiquement différent : c'est une mise à jour de statut, pas un avertissement.

| Fonction         | Effet                                   | Utiliser quand                                                                               |
| ---------------- | --------------------------------------- | -------------------------------------------------------------------------------------------- |
| `allow(message)` | Autorise et envoie du contexte à Claude | Confirmer qu'une vérification a réussi, ou expliquer pourquoi une vérification a été ignorée |

Cas d'usage :

* **Confirmations de statut :** `allow("All CI checks passed.")` — indique à Claude que tout est en ordre
* **Explications fail-open :** `allow("GitHub CLI not installed, skipping CI check.")` — indique à Claude pourquoi une vérification a été ignorée pour qu'il dispose du contexte complet
* **Accumulation de plusieurs messages :** si plusieurs politiques retournent chacune `allow(message)`, tous les messages sont joints avec des sauts de ligne et délivrés ensemble

```js theme={null}
customPolicies.add({
  name: "confirm-branch-status",
  match: { events: ["Stop"] },
  fn: async (ctx) => {
    const cwd = ctx.session?.cwd;
    if (!cwd) return allow("No working directory, skipping branch check.");

    // ... check branch status ...
    if (allPushed) {
      return allow("Branch is up to date with remote.");
    }
    return deny("Unpushed changes detected.");
  },
});
```

### Champs de `PolicyContext`

| Champ       | Type                                   | Description                                                         |
| ----------- | -------------------------------------- | ------------------------------------------------------------------- |
| `eventType` | `string`                               | `"PreToolUse"`, `"PostToolUse"`, `"Notification"`, `"Stop"`         |
| `toolName`  | `string \| undefined`                  | L'outil appelé (ex. `"Bash"`, `"Write"`, `"Read"`)                  |
| `toolInput` | `Record<string, unknown> \| undefined` | Les paramètres d'entrée de l'outil                                  |
| `payload`   | `Record<string, unknown>`              | Charge utile brute complète de l'événement provenant de Claude Code |
| `session`   | `SessionMetadata \| undefined`         | Contexte de session (voir ci-dessous)                               |

### Champs de `SessionMetadata`

| Champ            | Type     | Description                                                 |
| ---------------- | -------- | ----------------------------------------------------------- |
| `sessionId`      | `string` | Identifiant de session Claude Code                          |
| `cwd`            | `string` | Répertoire de travail de la session Claude Code             |
| `transcriptPath` | `string` | Chemin vers le fichier de transcription JSONL de la session |

### Types d'événements

| Événement      | Quand il se déclenche                | Contenu de `toolInput`                                                                                                                                                       |
| -------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PreToolUse`   | Avant que Claude exécute un outil    | L'entrée de l'outil (ex. `{ command: "..." }` pour Bash)                                                                                                                     |
| `PostToolUse`  | Après la complétion d'un outil       | L'entrée de l'outil + `tool_result` (la sortie)                                                                                                                              |
| `Notification` | Quand Claude envoie une notification | `{ message: "...", notification_type: "idle" \| "permission_prompt" \| ... }` - les hooks doivent toujours retourner `allow()`, ils ne peuvent pas bloquer les notifications |
| `Stop`         | Quand la session Claude se termine   | Vide                                                                                                                                                                         |

***

## Ordre d'évaluation

Les politiques sont évaluées dans cet ordre :

1. Politiques intégrées (dans l'ordre de définition)
2. Politiques personnalisées explicites depuis `customPoliciesPath` (dans l'ordre des `.add()`)
3. Politiques de convention du projet `.failproofai/policies/` (fichiers alphabétiques, ordre des `.add()` à l'intérieur)
4. Politiques de convention de l'utilisateur `~/.failproofai/policies/` (fichiers alphabétiques, ordre des `.add()` à l'intérieur)

<Note>
  Le premier `deny` court-circuite toutes les politiques suivantes. Tous les messages `instruct` sont accumulés et délivrés ensemble.
</Note>

***

## Imports transitifs

Les fichiers de politiques personnalisées peuvent importer des modules locaux en utilisant des chemins relatifs :

```js theme={null}
// my-policies.js
import { isBlockedPath } from "./utils.js";
import { checkApproval } from "./approval-client.js";

customPolicies.add({
  name: "approval-gate",
  fn: async (ctx) => {
    if (ctx.toolName !== "Bash") return allow();
    const approved = await checkApproval(ctx.toolInput?.command, ctx.session?.sessionId);
    return approved ? allow() : deny("Approval required for this command");
  },
});
```

Tous les imports relatifs accessibles depuis le fichier d'entrée sont résolus. Ceci est implémenté en réécrivant les imports `from "failproofai"` vers le chemin dist réel et en créant des fichiers `.mjs` temporaires pour assurer la compatibilité ESM.

***

## Filtrage par type d'événement

Utilisez `match.events` pour limiter le déclenchement d'une politique :

```js theme={null}
customPolicies.add({
  name: "require-summary-on-stop",
  match: { events: ["Stop"] },
  fn: async (ctx) => {
    // Se déclenche uniquement à la fin de la session
    // ctx.session.transcriptPath contient le journal complet de la session
    return allow();
  },
});
```

Omettez entièrement `match` pour se déclencher à chaque type d'événement.

***

## Gestion des erreurs et modes de défaillance

Les politiques personnalisées sont **fail-open** : les erreurs ne bloquent jamais les politiques intégrées ni ne font planter le gestionnaire de hook.

| Défaillance                           | Comportement                                                                                                                            |
| ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `customPoliciesPath` non défini       | Aucune politique personnalisée explicite ne s'exécute ; les politiques de convention et les politiques intégrées continuent normalement |
| Fichier introuvable                   | Avertissement enregistré dans `~/.failproofai/hook.log` ; les politiques intégrées continuent                                           |
| Erreur de syntaxe/import (explicite)  | Erreur enregistrée dans `~/.failproofai/hook.log` ; les politiques personnalisées explicites ignorées                                   |
| Erreur de syntaxe/import (convention) | Erreur enregistrée ; ce fichier ignoré, les autres fichiers de convention se chargent quand même                                        |
| `fn` lève une exception à l'exécution | Erreur enregistrée ; ce hook traité comme `allow` ; les autres hooks continuent                                                         |
| `fn` prend plus de 10s                | Timeout enregistré ; traité comme `allow`                                                                                               |
| Répertoire de convention manquant     | Aucune politique de convention ne s'exécute ; aucune erreur                                                                             |

<Tip>
  Pour déboguer les erreurs de politiques personnalisées, surveillez le fichier de log :

  ```bash theme={null}
  tail -f ~/.failproofai/hook.log
  ```
</Tip>

***

## Exemple complet : plusieurs politiques

```js theme={null}
// my-policies.js
import { customPolicies, allow, deny, instruct } from "failproofai";

// Empêcher l'agent d'écrire dans le répertoire secrets/
customPolicies.add({
  name: "block-secrets-dir",
  description: "Prevent agent from writing to secrets/ directory",
  match: { events: ["PreToolUse"] },
  fn: async (ctx) => {
    if (!["Write", "Edit"].includes(ctx.toolName ?? "")) return allow();
    const path = ctx.toolInput?.file_path ?? "";
    if (path.includes("secrets/")) return deny("Writing to secrets/ is not permitted");
    return allow();
  },
});

// Maintenir l'agent sur la bonne voie : vérifier les tests avant de commiter
customPolicies.add({
  name: "remind-test-before-commit",
  description: "Keep the agent on track: verify tests pass before committing",
  match: { events: ["PreToolUse"] },
  fn: async (ctx) => {
    if (ctx.toolName !== "Bash") return allow();
    const cmd = ctx.toolInput?.command ?? "";
    if (/git\s+commit/.test(cmd)) {
      return instruct("Verify all tests pass before committing. Run `bun test` if you haven't already.");
    }
    return allow();
  },
});

// Prévenir les changements de dépendances non planifiés pendant le gel
customPolicies.add({
  name: "dependency-freeze",
  description: "Prevent unplanned dependency changes during freeze period",
  match: { events: ["PreToolUse"] },
  fn: async (ctx) => {
    if (ctx.toolName !== "Bash") return allow();
    const cmd = ctx.toolInput?.command ?? "";
    const isInstall = /^(npm install|yarn add|bun add|pnpm add)\s+\S/.test(cmd);
    if (isInstall && process.env.DEPENDENCY_FREEZE === "1") {
      return deny("Package installs are frozen. Unset DEPENDENCY_FREEZE to allow.");
    }
    return allow();
  },
});

export { customPolicies };
```

***

## Exemples

Le répertoire `examples/` contient des fichiers de politiques prêts à l'emploi :

| Fichier                                              | Contenu                                                                                                                  |
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `examples/policies-basic.js`                         | Cinq politiques de démarrage couvrant les modes d'échec courants des agents                                              |
| `examples/policies-advanced/index.js`                | Modèles avancés : imports transitifs, appels asynchrones, épuration des sorties et hooks de fin de session               |
| `examples/convention-policies/security-policies.mjs` | Politiques de sécurité basées sur la convention (bloquer les écritures .env, empêcher la réécriture de l'historique git) |
| `examples/convention-policies/workflow-policies.mjs` | Politiques de workflow basées sur la convention (rappels de tests, audit des écritures de fichiers)                      |

### Utiliser les exemples de fichiers explicites

```bash theme={null}
failproofai policies --install --custom ./examples/policies-basic.js
```

### Utiliser les exemples basés sur la convention

```bash theme={null}
# Copier au niveau du projet
mkdir -p .failproofai/policies
cp examples/convention-policies/*.mjs .failproofai/policies/

# Ou copier au niveau utilisateur
mkdir -p ~/.failproofai/policies
cp examples/convention-policies/*.mjs ~/.failproofai/policies/
```

Aucune commande d'installation nécessaire — les fichiers sont récupérés automatiquement lors du prochain événement de hook.
