Zum Hauptinhalt springen
Benutzerdefinierte Richtlinien ermöglichen es Ihnen, Regeln für jedes Agentenverhalten zu definieren: Projektkonventionen durchsetzen, Drift verhindern, destruktive Operationen absichern, feststeckende Agenten erkennen oder Slack, Genehmigungsworkflows und mehr integrieren. Sie verwenden dasselbe Hook-Ereignissystem und dieselben allow-, deny- und instruct-Entscheidungen wie eingebaute Richtlinien.

Schnellbeispiel

// 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:
failproofai policies --install --custom ./my-policies.js

Zwei Wege zum Laden benutzerdefinierter Richtlinien

Option 1: Konventionsbasiert (empfohlen)

Legen Sie *policies.{js,mjs,ts}-Dateien in .failproofai/policies/ ab – sie werden automatisch geladen, ohne Flags oder Konfigurationsänderungen. Das funktioniert wie Git-Hooks: Datei ablegen, fertig.
# Projektebene – per Git eingecheckt, 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 – kein Erster-gewinnt-Prinzip pro Scope)
  • Dateien werden innerhalb jedes Verzeichnisses alphabetisch geladen. Präfixe wie 01-, 02- steuern die Reihenfolge
  • Nur Dateien, die *policies.{js,mjs,ts} entsprechen, werden geladen; andere Dateien werden ignoriert
  • Jede Datei wird unabhängig geladen (fail-open pro Datei)
  • Funktioniert zusammen mit explizitem --custom und eingebauten Richtlinien
Konventionsbasierte Richtlinien sind der einfachste Weg, Richtlinien im Team zu teilen. Checken Sie .failproofai/policies/ per Git ein, und jedes Teammitglied erhält sie automatisch.

Option 2: Expliziter Dateipfad

# Mit einer benutzerdefinierten Richtliniendatei installieren
failproofai policies --install --custom ./my-policies.js

# Den Richtliniendateipfad 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-Ereignis neu geladen – es gibt kein Caching zwischen Ereignissen.

Beide Methoden kombinieren

Konventionsbasierte Richtlinien und die explizite --custom-Datei können nebeneinander existieren. Ladereihenfolge:
  1. Explizite customPoliciesPath-Datei (falls konfiguriert)
  2. Projekt-Konventionsdateien ({cwd}/.failproofai/policies/, alphabetisch)
  3. Benutzer-Konventionsdateien (~/.failproofai/policies/, alphabetisch)

API

Import

import { customPolicies, allow, deny, instruct } from "failproofai";

customPolicies.add(hook)

Registriert eine Richtlinie. Kann beliebig oft aufgerufen werden, um mehrere Richtlinien in derselben Datei zu definieren.
customPolicies.add({
  name: string;                         // erforderlich – eindeutiger Bezeichner
  description?: string;                 // wird in der `failproofai policies`-Ausgabe angezeigt
  match?: { events?: HookEventType[] }; // nach Ereignistyp filtern; weglassen für alle Ereignisse
  fn: (ctx: PolicyContext) => PolicyResult | Promise<PolicyResult>;
});

Entscheidungs-Hilfsfunktionen

FunktionWirkungVerwendung
allow()Operation lautlos zulassenDie Aktion ist sicher, keine Meldung erforderlich
deny(message)Operation blockierenDer Agent soll diese Aktion nicht ausführen
instruct(message)Kontext hinzufügen ohne zu blockierenDem Agenten zusätzlichen Kontext geben, um auf Kurs zu bleiben
deny(message) – die Nachricht erscheint gegenüber Claude mit dem Präfix "Blocked by failproofai:". Ein einzelnes deny bricht die gesamte weitere Auswertung ab. instruct(message) – die Nachricht wird dem Claude-Kontext für den aktuellen Tool-Aufruf angehängt. Alle instruct-Nachrichten werden gesammelt und gemeinsam zugestellt.
Sie können jeder deny- oder instruct-Nachricht zusätzliche Hinweise hinzufügen, indem Sie ein hint-Feld in policyParams setzen – ohne Codeänderung. Das funktioniert auch für benutzerdefinierte (custom/), Projekt-Konventions- (.failproofai-project/) und Benutzer-Konventionsrichtlinien (.failproofai-user/). Siehe Konfiguration → hint für Details.

Informative allow-Nachrichten

allow(message) lässt die Operation zu und sendet eine informative Nachricht an Claude zurück. Die Nachricht wird als additionalContext in der stdout-Antwort des Hook-Handlers zugestellt – derselbe Mechanismus wie bei instruct, jedoch semantisch anders: Es handelt sich um eine Statusmeldung, nicht um eine Warnung.
FunktionWirkungVerwendung
allow(message)Zulassen und Kontext an Claude sendenBestä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 in Ordnung ist
  • Fail-open-Erklärungen: allow("GitHub CLI not installed, skipping CI check.") – erklärt Claude, warum eine Prüfung übersprungen wurde, damit er 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 zugestellt
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.");

    // ... Branch-Status prüfen ...
    if (allPushed) {
      return allow("Branch is up to date with remote.");
    }
    return deny("Unpushed changes detected.");
  },
});

PolicyContext-Felder

FeldTypBeschreibung
eventTypestring"PreToolUse", "PostToolUse", "Notification", "Stop"
toolNamestring | undefinedDas aufgerufene Tool (z. B. "Bash", "Write", "Read")
toolInputRecord<string, unknown> | undefinedDie Eingabeparameter des Tools
payloadRecord<string, unknown>Vollständige rohe Ereignis-Payload von Claude Code
sessionSessionMetadata | undefinedSitzungskontext (siehe unten)

SessionMetadata-Felder

FeldTypBeschreibung
sessionIdstringClaude Code-Sitzungsbezeichner
cwdstringArbeitsverzeichnis der Claude Code-Sitzung
transcriptPathstringPfad zur JSONL-Transkriptdatei der Sitzung

Ereignistypen

EreignisWann es ausgelöst wirdInhalt von toolInput
PreToolUseBevor Claude ein Tool ausführtDie Eingabe des Tools (z. B. { command: "..." } für Bash)
PostToolUseNachdem ein Tool abgeschlossen hatDie Eingabe des Tools + tool_result (die Ausgabe)
NotificationWenn Claude eine Benachrichtigung sendet{ message: "...", notification_type: "idle" | "permission_prompt" | ... } – Hooks müssen immer allow() zurückgeben, Benachrichtigungen können nicht blockiert werden
StopWenn die Claude-Sitzung endetLeer

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)
Das erste deny bricht alle nachfolgenden Richtlinien ab. Alle instruct-Nachrichten werden gesammelt und gemeinsam zugestellt.

Transitive Importe

Benutzerdefinierte Richtliniendateien können lokale Module über relative Pfade importieren:
// 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 Importe, die von der Einstiegsdatei aus erreichbar sind, werden aufgelöst. Dies wird implementiert, indem from "failproofai"-Importe auf den tatsächlichen dist-Pfad umgeschrieben und temporäre .mjs-Dateien erstellt werden, um ESM-Kompatibilität sicherzustellen.

Ereignistypfilterung

Verwenden Sie match.events, um einzuschränken, wann eine Richtlinie ausgelöst wird:
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();
  },
});
Lassen Sie match vollständig weg, um bei jedem Ereignistyp auszulösen.

Fehlerbehandlung und Fehlermodi

Benutzerdefinierte Richtlinien sind fail-open: Fehler blockieren niemals eingebaute Richtlinien und bringen den Hook-Handler nicht zum Absturz.
FehlerVerhalten
customPoliciesPath nicht gesetztKeine expliziten benutzerdefinierten Richtlinien werden ausgeführt; Konventionsrichtlinien und eingebaute Richtlinien laufen normal weiter
Datei nicht gefundenWarnung 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 weiterhin geladen
fn wirft zur LaufzeitFehler wird protokolliert; dieser Hook wird als allow behandelt; andere Hooks laufen weiter
fn dauert länger als 10sTimeout wird protokolliert; als allow behandelt
Konventionsverzeichnis fehltKeine Konventionsrichtlinien werden ausgeführt; kein Fehler
Um Fehler in benutzerdefinierten Richtlinien zu debuggen, beobachten Sie die Log-Datei:
tail -f ~/.failproofai/hook.log

Vollständiges Beispiel: mehrere Richtlinien

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

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

// Agenten auf Kurs halten: 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();
  },
});

// Ungeplante Abhängigkeitsänderungen während des Freeze verhindern
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:
DateiInhalt
examples/policies-basic.jsFünf Starter-Richtlinien für häufige Agenten-Fehlermodi
examples/policies-advanced/index.jsFortgeschrittene Muster: transitive Importe, asynchrone Aufrufe, Ausgabe-Bereinigung und Sitzungsende-Hooks
examples/convention-policies/security-policies.mjsKonventionsbasierte Sicherheitsrichtlinien (blockiert .env-Schreibzugriffe, verhindert Git-History-Umschreibung)
examples/convention-policies/workflow-policies.mjsKonventionsbasierte Workflow-Richtlinien (Test-Erinnerungen, Audit-Datei-Schreibzugriffe)

Explizite Dateibeispiele verwenden

failproofai policies --install --custom ./examples/policies-basic.js

Konventionsbasierte Beispiele verwenden

# 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 erforderlich – die Dateien werden beim nächsten Hook-Ereignis automatisch erkannt.