> ## 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.

# Architektur

> Wie der Hook-Handler, das Laden der Konfiguration und die Richtlinienauswertung intern funktionieren

Dieses Dokument erklärt, wie failproofai intern arbeitet: wie das Hook-System Agent-Tool-Aufrufe abfängt, wie die Konfiguration geladen und zusammengeführt wird, wie Richtlinien ausgewertet werden und wie das Dashboard die Agentenaktivität überwacht.

***

## Übersicht

failproofai besteht aus zwei unabhängigen Subsystemen:

1. **Hook-Handler** – Ein schneller CLI-Subprozess, den Claude Code bei jedem Agent-Tool-Aufruf aufruft. Er wertet Richtlinien aus und gibt eine Entscheidung zurück.
2. **Agent Monitor (Dashboard)** – Eine Next.js-Webanwendung zur Überwachung von Agentensitzungen und zur Verwaltung von Richtlinien.

Beide Subsysteme teilen Konfigurationsdateien in `~/.failproofai/` und im `.failproofai/`-Verzeichnis des Projekts, laufen aber als separate Prozesse und kommunizieren ausschließlich über das Dateisystem.

***

## Hook-Handler

### Integration mit Claude Code

Wenn Sie `failproofai policies --install` ausführen, werden folgende Einträge in `~/.claude/settings.json` geschrieben:

```json theme={null}
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "failproofai --hook PreToolUse"
          }
        ]
      }
    ],
    "PostToolUse": [ ... ]
  }
}
```

Claude Code ruft dann `failproofai --hook PreToolUse` vor jedem Tool-Aufruf als Subprozess auf und übergibt eine JSON-Nutzlast über stdin.

### Nutzlastformat

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/home/user/.claude/projects/myproject/sessions/abc123.jsonl",
  "cwd": "/home/user/myproject",
  "permission_mode": "default",
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": { "command": "sudo apt install nodejs" }
}
```

Bei `PostToolUse`-Ereignissen enthält die Nutzlast zusätzlich `tool_result` mit der Ausgabe des Tools.

Der Handler begrenzt die stdin-Eingabe auf 1 MB. Nutzlasten, die diesen Wert überschreiten, werden verworfen, und alle Richtlinien erlauben die Ausführung implizit.

### Antwortformat

**Ablehnen (PreToolUse):**

```json theme={null}
{
  "hookSpecificOutput": {
    "permissionDecision": "deny",
    "permissionDecisionReason": "Blocked by failproofai: sudo command blocked"
  }
}
```

**Ablehnen (PostToolUse):**

```json theme={null}
{
  "hookSpecificOutput": {
    "additionalContext": "Blocked by failproofai because: API key detected in output"
  }
}
```

**Anweisen (jedes Ereignis außer Stop):**

```json theme={null}
{
  "hookSpecificOutput": {
    "additionalContext": "Instruction from failproofai: Verify tests pass before committing."
  }
}
```

**Stop-Ereignis anweisen:**

* Exit-Code: `2`
* Begründung wird in stderr (nicht stdout) geschrieben

**Erlauben:**

* Exit-Code: `0`
* Leere stdout-Ausgabe

**Erlauben mit Nachricht:**

`allow(message)` ermöglicht es einer Richtlinie, informativen Kontext an Claude zurückzusenden, auch wenn die Operation erlaubt ist. Der Hook-Handler schreibt das folgende JSON auf **stdout** (keine Konfigurationsdatei – dies ist die Antwort des Handlers an Claude Code, genau wie Ablehnen- und Anweisen-Antworten oben):

```json theme={null}
// Written to stdout by the hook handler process
{
  "hookSpecificOutput": {
    "additionalContext": "All CI checks passed on branch 'feat/my-feature'."
  }
}
```

* Exit-Code: `0` (die Operation wird erlaubt)
* Wenn mehrere Richtlinien `allow` mit einer Nachricht zurückgeben, werden ihre Nachrichten mit Zeilenumbrüchen zu einem einzigen `additionalContext`-String zusammengefügt
* Wenn keine Richtlinie eine Nachricht liefert, ist stdout leer (wie bisher)

### Verarbeitungspipeline

`src/hooks/handler.ts` implementiert die vollständige Pipeline:

```text theme={null}
stdin JSON
  → Nutzlast parsen (max. 1 MB)
  → Sitzungsmetadaten extrahieren (session_id, cwd, tool_name, tool_input usw.)
  → readMergedHooksConfig(cwd)    ← Projekt- + lokale + globale Konfiguration zusammenführen
  → aktivierte integrierte Richtlinien mit aufgelösten Parametern registrieren
  → benutzerdefinierte Richtlinien aus customPoliciesPath laden (falls angegeben)
  → benutzerdefinierte Richtlinien in die Richtlinienregistrierung eintragen
  → alle Richtlinien auswerten (erst integrierte, dann benutzerdefinierte)
      → erstes deny bricht sofort ab
      → instruct-Entscheidungen werden gesammelt
      → allow-Nachrichten werden gesammelt
  → JSON-Entscheidung auf stdout schreiben
  → Ereignis in ~/.failproofai/hook-activity.jsonl persistieren
  → beenden
```

Der gesamte Prozess läuft bei typischen Nutzlasten ohne LLM-Aufrufe in unter 100 ms ab.

***

## Konfigurationsladung

`src/hooks/hooks-config.ts` implementiert das Laden der Konfiguration aus drei Bereichen.

```text theme={null}
[1] {cwd}/.failproofai/policies-config.json        ← Projekt  (höchste Priorität)
[2] {cwd}/.failproofai/policies-config.local.json  ← lokal
[3] ~/.failproofai/policies-config.json             ← global   (niedrigste Priorität)
```

Zusammenführungslogik:

* `enabledPolicies` – deduplizierte Vereinigung aus allen drei Dateien
* `policyParams` – pro Richtlinien-Schlüssel gewinnt die erste Datei, die ihn definiert, vollständig
* `customPoliciesPath` – die erste Datei, die diesen Wert definiert, gewinnt
* `llm` – die erste Datei, die diesen Wert definiert, gewinnt

Das Web-Dashboard verwendet `readHooksConfig()` (nur global) zum Lesen und Schreiben, da es nicht mit einem Projekt-cwd aufgerufen wird.

***

## Richtlinienauswertung

`src/hooks/policy-evaluator.ts` führt Richtlinien der Reihe nach aus.

Für jede Richtlinie:

1. Das `params`-Schema der Richtlinie nachschlagen (falls vorhanden).
2. `policyParams[policy.name]` aus der zusammengeführten Konfiguration lesen.
3. Benutzerdefinierte Werte über die Schema-Standardwerte zusammenführen, um `ctx.params` zu erzeugen.
4. `policy.fn(ctx)` mit dem aufgelösten Kontext aufrufen.
5. Wenn das Ergebnis `deny` ist, sofort abbrechen und diese Entscheidung zurückgeben.
6. Wenn das Ergebnis `instruct` ist, die Nachricht sammeln und fortfahren.
7. Wenn das Ergebnis `allow` ist, zur nächsten Richtlinie übergehen.

Nachdem alle Richtlinien ausgeführt wurden:

* Falls ein `deny` zurückgegeben wurde, die Ablehnungsantwort ausgeben.
* Falls `instruct`-Rückgaben gesammelt wurden, eine einzelne Anweisungsantwort mit allen zusammengefügten Nachrichten ausgeben.
* Andernfalls eine Erlauben-Antwort ausgeben (leere stdout-Ausgabe, Exit 0).

***

## Integrierte Richtlinien

`src/hooks/builtin-policies.ts` definiert alle 39 integrierten Richtlinien als `BuiltinPolicyDefinition`-Objekte:

```typescript theme={null}
interface BuiltinPolicyDefinition {
  name: string;
  description: string;
  fn: (ctx: PolicyContext) => PolicyResult;
  match: {
    events: HookEventType[];
    tools?: string[];
  };
  defaultEnabled: boolean;
  category: string;
  beta?: boolean;
  params?: PolicyParamsSchema;
}
```

Richtlinien, die `params` akzeptieren, deklarieren ein `PolicyParamsSchema` mit Typen und Standardwerten für jeden Parameter. Der Richtlinien-Evaluator injiziert aufgelöste Werte in `ctx.params`, bevor er `fn` aufruft. Richtlinienfunktionen lesen `ctx.params` ohne Null-Prüfung, da Standardwerte immer zuerst angewendet werden.

Musterabgleiche innerhalb von Richtlinien verwenden geparste Befehls-Tokens (argv) statt einfachem String-Matching. Dadurch werden Umgehungen durch Shell-Operator-Injection verhindert (z. B. kann ein Muster für `sudo systemctl status *` nicht durch Anhängen von `; rm -rf /` an den Befehl umgangen werden).

***

## Benutzerdefinierte Richtlinien

`src/hooks/custom-hooks-registry.ts` implementiert eine `globalThis`-basierte Registrierung:

```typescript theme={null}
const REGISTRY_KEY = "__failproofai_custom_hooks__";

export const customPolicies = {
  add(hook: CustomHook): void { ... }
};

export function getCustomHooks(): CustomHook[] { ... }
export function clearCustomHooks(): void { ... }  // used in tests
```

`src/hooks/custom-hooks-loader.ts` lädt die Richtliniendatei des Benutzers:

1. `customPoliciesPath` aus der Konfiguration lesen; überspringen, falls nicht vorhanden.
2. Auf absoluten Pfad auflösen; prüfen, ob die Datei existiert.
3. Alle `from "failproofai"`-Importe auf den tatsächlichen dist-Pfad umschreiben, sodass `customPolicies` auf dieselbe `globalThis`-Registrierung zeigt.
4. Transitive lokale Importe rekursiv umschreiben, um ESM-Kompatibilität sicherzustellen.
5. Temporäre `.mjs`-Dateien schreiben und die Einstiegsdatei per `import()` laden.
6. `getCustomHooks()` aufrufen, um registrierte Hooks abzurufen.
7. Alle temporären Dateien in einem `finally`-Block bereinigen.

Bei jedem Fehler (Datei nicht gefunden, Syntaxfehler, Import-Fehler) wird der Fehler in `~/.failproofai/hook.log` protokolliert und der Loader gibt ein leeres Array zurück. Integrierte Richtlinien sind davon nicht betroffen.

Benutzerdefinierte Richtlinien werden nach allen integrierten Richtlinien ausgewertet. Ein `deny` einer benutzerdefinierten Richtlinie unterbricht zwar weitere benutzerdefinierte Richtlinien (alle integrierten wurden zu diesem Zeitpunkt jedoch bereits ausgeführt).

***

## Aktivitätsprotokollierung

Nach jedem Hook-Ereignis fügt der Handler eine JSONL-Zeile an `~/.failproofai/hook-activity.jsonl` an:

```json theme={null}
{
  "timestamp": "2026-04-06T12:34:56.789Z",
  "sessionId": "abc123",
  "eventType": "PreToolUse",
  "toolName": "Bash",
  "policyName": "block-sudo",
  "decision": "deny",
  "reason": "sudo command blocked by failproofai",
  "durationMs": 12
}
```

Pro Richtlinie, die eine Nicht-Erlauben-Entscheidung getroffen hat, wird eine Zeile geschrieben. Erlauben-Entscheidungen werden nicht protokolliert (um die Dateigröße gering zu halten).

***

## Dashboard-Architektur

Das Dashboard ist eine **Next.js 16**-Anwendung, die den App Router mit React Server Components und Server Actions verwendet.

```text theme={null}
app/
  layout.tsx                  ← Root-Layout (Theme, Telemetrie, Navigation)
  projects/page.tsx           ← Server-Komponente: alle Claude-Projekte auflisten
  project/[name]/page.tsx     ← Server-Komponente: Sitzungen in einem Projekt auflisten
  project/[name]/session/
    [sessionId]/page.tsx      ← Server-Komponente: Sitzungsansicht rendern
  policies/page.tsx           ← Client-Komponente: Richtlinienverwaltung + Aktivitätsprotokoll
  actions/
    get-hooks-config.ts       ← Konfiguration + Richtlinienliste lesen
    update-hooks-config.ts    ← Richtlinie aktivieren/deaktivieren
    update-policy-params.ts   ← Richtlinienparameter aktualisieren
    get-hook-activity.ts      ← Aktivitätsprotokoll blättern/durchsuchen
    install-hooks-web.ts      ← Hooks über den Browser installieren/entfernen
  api/
    download/[project]/[session]/route.ts   ← Sitzungsexport pro CLI (JSONL oder JSON)
```

**Datenfluss:**

* Seitenkomponenten rufen `lib/projects.ts` und `lib/log-entries.ts` auf, um Projekt-/Sitzungsdaten direkt aus dem Dateisystem zu lesen (keine API-Schicht für Lesevorgänge).
* Die Policies-Seite verwendet Server Actions für alle Mutationen (Umschalten, Parameteraktualisierung, Installieren/Entfernen).
* Der Sitzungs-Viewer parst das JSONL-Transkriptformat von Claude und rendert eine Zeitleiste mit Nachrichten und Tool-Aufrufen.

**Wichtige Designentscheidungen:**

* Keine Datenbank – alle persistenten Zustände liegen in einfachen Dateien (`~/.failproofai/`, `~/.claude/projects/`).
* Server Actions für Mutationen – keine REST-API für CRUD-Operationen erforderlich.
* React Server Components für Leseseiten – schnelleres initiales Laden, kein Client-Bundle für das Datenabrufen.
* Client-Komponenten nur dort, wo Interaktivität benötigt wird (Richtlinien-Umschalter, Aktivitätssuche, Log-Viewer).

***

## Dateistruktur

```text theme={null}
failproofai/
├── bin/
│   └── failproofai.mjs           # CLI-Router (Hook / Dashboard / Install / usw.)
├── src/hooks/
│   ├── handler.ts                # Hook-Ereignis-Pipeline
│   ├── builtin-policies.ts       # 39 Richtliniendefinitionen
│   ├── policy-evaluator.ts       # Richtlinien-Ausführungsengine
│   ├── policy-registry.ts        # Richtlinienregistrierung und -suche
│   ├── policy-types.ts           # TypeScript-Interfaces
│   ├── hooks-config.ts           # Mehrstufiges Konfigurationsladen
│   ├── custom-hooks-registry.ts  # globalThis-basierte Hook-Registrierung
│   ├── custom-hooks-loader.ts    # ESM-Loader für benutzerdefinierte JS-Hooks
│   ├── manager.ts                # Installations-, Entfernungs- und Listenoperationen
│   ├── install-prompt.ts         # Interaktive Richtlinienauswahlabfrage
│   ├── hook-logger.ts            # Protokollierung in hook.log
│   ├── hook-activity-store.ts    # Aktivität in hook-activity.jsonl persistieren
│   └── llm-client.ts             # LLM-API-Client (für KI-gestützte Richtlinien)
├── app/                          # Next.js-Dashboard (Seiten + Server Actions)
├── lib/                          # Gemeinsame Hilfsprogramme
│   ├── projects.ts               # Claude-Projekte aus dem Dateisystem aufzählen
│   ├── log-entries.ts            # Claude-Transkript-JSONL-Format parsen
│   ├── paths.ts                  # Systempfade auflösen
│   └── ...
├── components/                   # Gemeinsame React-UI-Komponenten
├── contexts/                     # React-Context-Provider (Theme, Auto-Refresh, Telemetrie)
├── examples/                     # Beispieldateien für benutzerdefinierte Hooks
└── __tests__/                    # Unit- und E2E-Tests
```
