> ## Documentation Index
> Fetch the complete documentation index at: https://exosphere-auto-translate-docs-20260626-1023.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Benutzerdefinierte Richtlinien

> Schreibe eigene Richtlinien in JavaScript – Konventionen durchsetzen, Drift verhindern, Fehler erkennen, externe Systeme integrieren

Benutzerdefinierte Richtlinien ermöglichen es dir, Regeln für beliebiges Agentenverhalten zu schreiben: Projektkonventionen durchsetzen, Drift verhindern, destruktive Operationen absichern, feststeckende Agenten erkennen oder Integrationen mit Slack, Freigabe-Workflows und mehr umsetzen. Sie verwenden dasselbe Hook-Event-System und dieselben Entscheidungen `allow`, `deny`, `instruct` wie die eingebauten Richtlinien.

***

## Schnellbeispiel

```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();
  },
});
```

Installieren:

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

***

## Zwei Wege, benutzerdefinierte Richtlinien zu laden

### Option 1: Konventionsbasiert (empfohlen)

Lege `*policies.{js,mjs,ts}`-Dateien in `.failproofai/policies/` ab und sie werden automatisch geladen – keine Flags oder Konfigurationsänderungen erforderlich. Das funktioniert wie Git-Hooks: Datei ablegen, fertig.

```
# Projektebene — wird in Git eingecheckt und mit dem Team geteilt
.failproofai/policies/security-policies.mjs
.failproofai/policies/workflow-policies.mjs

# Benutzerebene — persönlich, gilt für alle Projekte
~/.failproofai/policies/my-policies.mjs
```

**So funktioniert es:**

* Sowohl Projekt- als auch Benutzerverzeichnisse werden durchsucht (Vereinigung – nicht nach dem Prinzip „erstes Scope gewinnt")
* Dateien werden alphabetisch innerhalb jedes Verzeichnisses geladen. Mit dem Präfix `01-`, `02-` lässt sich die Reihenfolge steuern
* Nur Dateien, die auf `*policies.{js,mjs,ts}` passen, werden geladen; andere Dateien werden ignoriert
* Jede Datei wird unabhängig geladen (fail-open pro Datei)
* Funktioniert zusammen mit expliziten `--custom`- und eingebauten Richtlinien

<Tip>
  Konventionsrichtlinien sind der einfachste Weg, einen Qualitätsstandard für deine Organisation aufzubauen. Checke `.failproofai/policies/` in Git ein, und jedes Teammitglied erhält automatisch dieselben Regeln – kein individuelles Setup nötig. Wenn dein Team neue Fehlerquellen entdeckt, füge eine Richtlinie hinzu und pushe sie. Im Laufe der Zeit entsteht so ein lebendiger Qualitätsstandard, der sich mit jedem Beitrag weiterentwickelt.
</Tip>

### Option 2: Expliziter Dateipfad

```bash theme={null}
# Mit einer benutzerdefinierten Richtliniendatei installieren
failproofai policies --install --custom ./my-policies.js

# Den Pfad zur Richtliniendatei ersetzen
failproofai policies --install --custom ./new-policies.js

# Den benutzerdefinierten Richtlinienpfad aus der Konfiguration entfernen
failproofai policies --uninstall --custom
```

Der aufgelöste absolute Pfad wird in `policies-config.json` als `customPoliciesPath` gespeichert. Die Datei wird bei jedem Hook-Event neu geladen – es gibt kein Caching zwischen Events.

### Beide Methoden kombinieren

Konventionsrichtlinien und die explizite `--custom`-Datei können nebeneinander existieren. Ladereihenfolge:

1. Explizite `customPoliciesPath`-Datei (falls konfiguriert)
2. Projektbezogene Konventionsdateien (`{cwd}/.failproofai/policies/`, alphabetisch)
3. Benutzerbezogene Konventionsdateien (`~/.failproofai/policies/`, alphabetisch)

***

## API

### Import

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

### `customPolicies.add(hook)`

Registriert eine Richtlinie. Kann mehrfach aufgerufen werden, um mehrere Richtlinien in derselben Datei zu definieren.

```ts theme={null}
customPolicies.add({
  name: string;                         // erforderlich – eindeutiger Bezeichner
  description?: string;                 // wird in der Ausgabe von `failproofai policies` angezeigt
  match?: { events?: HookEventType[] }; // nach Event-Typ filtern; weglassen, um alle zu treffen
  fn: (ctx: PolicyContext) => PolicyResult | Promise<PolicyResult>;
});
```

### Entscheidungs-Hilfsfunktionen

| Funktion            | Wirkung                               | Wann verwenden                                                    |
| ------------------- | ------------------------------------- | ----------------------------------------------------------------- |
| `allow()`           | Operation lautlos zulassen            | Die Aktion ist sicher, keine Nachricht nötig                      |
| `deny(message)`     | Operation blockieren                  | Der Agent soll diese Aktion nicht ausführen                       |
| `instruct(message)` | Kontext hinzufügen ohne zu blockieren | Dem Agenten zusätzlichen Kontext geben, um ihn auf Kurs zu halten |

`deny(message)` – die Nachricht erscheint bei Claude mit dem Präfix `"Blocked by failproofai:"`. Ein einziges `deny` bricht die gesamte weitere Auswertung ab.

`instruct(message)` – die Nachricht wird dem Kontext von Claude für den aktuellen Tool-Aufruf hinzugefügt. Alle `instruct`-Nachrichten werden gesammelt und gemeinsam übermittelt.

<Tip>
  Du kannst jeder `deny`- oder `instruct`-Nachricht zusätzliche Hinweise hinzufügen, indem du ein `hint`-Feld in `policyParams` angibst – ohne Codeänderung. Das funktioniert auch für benutzerdefinierte (`custom/`), projektbezogene Konventionsrichtlinien (`.failproofai-project/`) und benutzerbezogene Konventionsrichtlinien (`.failproofai-user/`). Weitere Details unter [Konfiguration → hint](/de/configuration#hint-cross-cutting).
</Tip>

### Informationelle Allow-Nachrichten

`allow(message)` lässt die Operation **durch** und sendet gleichzeitig eine informationelle Nachricht an Claude. Die Nachricht wird als `additionalContext` in der stdout-Antwort des Hook-Handlers übermittelt – derselbe Mechanismus wie bei `instruct`, aber semantisch anders: Es ist ein Statusupdate, keine Warnung.

| Funktion         | Wirkung                               | Wann verwenden                                                                                      |
| ---------------- | ------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `allow(message)` | Zulassen und Kontext an Claude senden | Bestätigen, dass eine Prüfung bestanden wurde, oder erklären, warum eine Prüfung übersprungen wurde |

Anwendungsfälle:

* **Statusbestätigungen:** `allow("All CI checks passed.")` – teilt Claude mit, dass alles grün ist
* **Fail-Open-Erklärungen:** `allow("GitHub CLI not installed, skipping CI check.")` – erklärt Claude, warum eine Prüfung übersprungen wurde, damit es den vollen Kontext hat
* **Mehrere Nachrichten werden gesammelt:** Wenn mehrere Richtlinien jeweils `allow(message)` zurückgeben, werden alle Nachrichten mit Zeilenumbrüchen verbunden und gemeinsam übermittelt

```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.");
  },
});
```

### `PolicyContext`-Felder

| Feld        | Typ                                    | Beschreibung                                                |
| ----------- | -------------------------------------- | ----------------------------------------------------------- |
| `eventType` | `string`                               | `"PreToolUse"`, `"PostToolUse"`, `"Notification"`, `"Stop"` |
| `toolName`  | `string \| undefined`                  | Das aufgerufene Tool (z. B. `"Bash"`, `"Write"`, `"Read"`)  |
| `toolInput` | `Record<string, unknown> \| undefined` | Die Eingabeparameter des Tools                              |
| `payload`   | `Record<string, unknown>`              | Vollständige rohe Event-Payload von Claude Code             |
| `session`   | `SessionMetadata \| undefined`         | Sitzungskontext (siehe unten)                               |

### `SessionMetadata`-Felder

| Feld             | Typ      | Beschreibung                               |
| ---------------- | -------- | ------------------------------------------ |
| `sessionId`      | `string` | Claude Code-Sitzungskennung                |
| `cwd`            | `string` | Arbeitsverzeichnis der Claude Code-Sitzung |
| `transcriptPath` | `string` | Pfad zur JSONL-Transkriptdatei der Sitzung |

### Event-Typen

| Event          | Wann es ausgelöst wird                   | Inhalt von `toolInput`                                                                                                                                                   |
| -------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `PreToolUse`   | Bevor Claude ein Tool ausführt           | Die Eingabe des Tools (z. B. `{ command: "..." }` für Bash)                                                                                                              |
| `PostToolUse`  | Nachdem ein Tool abgeschlossen ist       | Die Eingabe des Tools + `tool_result` (die Ausgabe)                                                                                                                      |
| `Notification` | Wenn Claude eine Benachrichtigung sendet | `{ message: "...", notification_type: "idle" \| "permission_prompt" \| ... }` – Hooks müssen immer `allow()` zurückgeben, sie können Benachrichtigungen nicht blockieren |
| `Stop`         | Wenn die Claude-Sitzung endet            | Leer                                                                                                                                                                     |

***

## Auswertungsreihenfolge

Richtlinien werden in dieser Reihenfolge ausgewertet:

1. Eingebaute Richtlinien (in Definitionsreihenfolge)
2. Explizite benutzerdefinierte Richtlinien aus `customPoliciesPath` (in `.add()`-Reihenfolge)
3. Konventionsrichtlinien aus dem Projekt `.failproofai/policies/` (Dateien alphabetisch, `.add()`-Reihenfolge innerhalb)
4. Konventionsrichtlinien aus dem Benutzerverzeichnis `~/.failproofai/policies/` (Dateien alphabetisch, `.add()`-Reihenfolge innerhalb)

<Note>
  Das erste `deny` bricht die Auswertung aller nachfolgenden Richtlinien ab. Alle `instruct`-Nachrichten werden gesammelt und gemeinsam übermittelt.
</Note>

***

## Transitive Imports

Benutzerdefinierte Richtliniendateien können lokale Module über relative Pfade importieren:

```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");
  },
});
```

Alle relativen Imports, die von der Einstiegsdatei aus erreichbar sind, werden aufgelöst. Dies wird durch Umschreiben von `from "failproofai"`-Importen auf den tatsächlichen dist-Pfad und Erstellen temporärer `.mjs`-Dateien implementiert, um ESM-Kompatibilität sicherzustellen.

***

## Event-Typ-Filterung

Mit `match.events` lässt sich einschränken, wann eine Richtlinie ausgelöst wird:

```js theme={null}
customPolicies.add({
  name: "require-summary-on-stop",
  match: { events: ["Stop"] },
  fn: async (ctx) => {
    // Wird nur ausgelöst, wenn die Sitzung endet
    // ctx.session.transcriptPath enthält das vollständige Sitzungsprotokoll
    return allow();
  },
});
```

`match` vollständig weglassen, um bei jedem Event-Typ auszulösen.

***

## Fehlerbehandlung und Ausfallverhalten

Benutzerdefinierte Richtlinien sind **fail-open**: Fehler blockieren niemals eingebaute Richtlinien und bringen den Hook-Handler nicht zum Absturz.

| Fehlerfall                         | Verhalten                                                                                                                                  |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `customPoliciesPath` nicht gesetzt | Keine expliziten benutzerdefinierten Richtlinien werden ausgeführt; Konventionsrichtlinien und eingebaute Richtlinien laufen normal weiter |
| Datei nicht gefunden               | Warnung wird in `~/.failproofai/hook.log` protokolliert; eingebaute Richtlinien laufen weiter                                              |
| Syntax-/Importfehler (explizit)    | Fehler wird in `~/.failproofai/hook.log` protokolliert; explizite benutzerdefinierte Richtlinien werden übersprungen                       |
| Syntax-/Importfehler (Konvention)  | Fehler wird protokolliert; diese Datei wird übersprungen, andere Konventionsdateien werden weiter geladen                                  |
| `fn` wirft zur Laufzeit            | Fehler wird protokolliert; dieser Hook wird als `allow` behandelt; andere Hooks laufen weiter                                              |
| `fn` dauert länger als 10 Sekunden | Timeout wird protokolliert; wird als `allow` behandelt                                                                                     |
| Konventionsverzeichnis fehlt       | Keine Konventionsrichtlinien werden ausgeführt; kein Fehler                                                                                |

<Tip>
  Um Fehler in benutzerdefinierten Richtlinien zu debuggen, beobachte die Log-Datei:

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

***

## Vollständiges Beispiel: mehrere Richtlinien

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

// Verhindert, dass der Agent in das Verzeichnis secrets/ schreibt
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();
  },
});

// Hält den Agenten auf Kurs: Tests vor dem Commit prüfen
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();
  },
});

// Verhindert ungeplante Abhängigkeitsänderungen während eines Freeze
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 };
```

***

## Beispiele

Das Verzeichnis `examples/` enthält sofort ausführbare Richtliniendateien:

| Datei                                                | Inhalt                                                                                                               |
| ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `examples/policies-basic.js`                         | Fünf Einstiegsrichtlinien für häufige Agentenausfälle                                                                |
| `examples/policies-advanced/index.js`                | Fortgeschrittene Muster: transitive Imports, asynchrone Aufrufe, Output-Bereinigung und Sitzungsende-Hooks           |
| `examples/convention-policies/security-policies.mjs` | Konventionsbasierte Sicherheitsrichtlinien (blockiert .env-Schreibzugriffe, verhindert Umschreiben der Git-Historie) |
| `examples/convention-policies/workflow-policies.mjs` | Konventionsbasierte Workflow-Richtlinien (Test-Erinnerungen, Audit-Dateioperationen)                                 |

### Explizite Dateibeispiele verwenden

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

### Konventionsbasierte Beispiele verwenden

```bash theme={null}
# Auf Projektebene kopieren
mkdir -p .failproofai/policies
cp examples/convention-policies/*.mjs .failproofai/policies/

# Oder auf Benutzerebene kopieren
mkdir -p ~/.failproofai/policies
cp examples/convention-policies/*.mjs ~/.failproofai/policies/
```

Kein Installationsbefehl nötig – die Dateien werden beim nächsten Hook-Event automatisch erkannt.
