Claude Pre-/Post-Hook System

Erstellt: 2025-12-23 | Aktualisiert: 2025-12-27

Das Hook-System greift automatisch bei jeder Interaktion mit Claude Code ein und stellt sicher, dass alle Aktionen protokolliert, validiert und abgesichert werden.

Operationale Übersicht: Claude Hooks (Betrieb)

Hook-Typen

Hook-Event Zeitpunkt Zweck
SessionStart Session-Beginn Protokollierung des Session-Starts
UserPromptSubmit Nach User-Eingabe Prompt-Logging
PreToolUse Vor Tool-Ausführung Validierung, Backup, Blockierung
PostToolUse Nach Tool-Ausführung Permissions, Response-Logging
Stop Task-Ende Abschluss-Protokollierung
SessionEnd Session-Ende Session-Abschluss

Konfiguration

Die Hooks werden in /root/.claude/settings.json konfiguriert.

Ablaufdiagramm: Edit/Write Operation

┌─────────────────┐
│  User-Prompt    │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ UserPromptSubmit│──▶ log_to_db.py (Logging)
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│   PreToolUse    │
│   (Edit/Write)  │
└────────┬────────┘
         │
    ┌────┴────┐
    │         │
    ▼         ▼
┌───────┐ ┌───────────┐ ┌────────────┐
│Block- │ │file_backup│ │log_to_db.py│
│DB.py  │ │_hook.py   │ │(Logging)   │
└───┬───┘ └─────┬─────┘ └──────┬─────┘
    │           │              │
    │      Backup erstellt     │
    │           │              │
    └───────────┴──────────────┘
                │
         ┌──────┴──────┐
         │  Tool       │
         │  Execution  │
         └──────┬──────┘
                │
                ▼
┌─────────────────┐
│  PostToolUse    │
│  (Edit/Write)   │
└────────┬────────┘
         │
    ┌────┴────┐
    │         │
    ▼         ▼
┌───────────┐ ┌────────────┐
│fix-permi- │ │log_to_db.py│
│ssions.sh  │ │(Response)  │
└─────┬─────┘ └──────┬─────┘
      │              │
      ▼              │
  Permissions        │
  korrigiert         │
      └──────────────┘

Unterkapitel

Verwandte Themen

Erstellt: 2025-12-23 | Aktualisiert: 2025-12-23

Pre-Hook Ablauf

Der Pre-Hook wird vor jeder Tool-Ausführung aufgerufen und kann die Aktion blockieren, modifizieren oder durchlassen.

Trigger

Pre-Hooks werden bei folgenden Tools ausgelöst:

Ablauf bei Edit/Write

1. Sicherheits-Validierung (Bash)

Bei Bash-Befehlen werden zwei Blocker-Hooks ausgeführt:

Hook Prüft Blockiert
block_direct_db.py MySQL/MariaDB-Zugriffe Direkte DB-Verbindungen mit Passwort
block_direct_task_db.py Task-Tabellen-Zugriffe INSERT/UPDATE/DELETE auf tasks-Tabellen

Empfehlung bei Blockierung: MCP-Tools verwenden (db_select, tasks_create, etc.)

2. File Backup (Edit/Write)

Bei Edit- und Write-Operationen:

file_backup_hook.py
├── Prüft: Liegt Datei in BACKUP_DIRS?
│   ├── /var/www/dev.campus.../src
│   ├── /var/www/dev.campus.../public
│   ├── /var/www/dev.campus.../config
│   └── ... (weitere Verzeichnisse)
│
├── Prüft: Datei < 10 MB?
├── Prüft: Nicht in EXCLUDE_PATTERNS?
│   ├── /vendor/
│   ├── /node_modules/
│   ├── /.git/
│   └── ... (weitere Ausschlüsse)
│
├── Berechnet: SHA256-Hash des Inhalts
├── Vergleicht: Mit letzter Version
│
└── Bei Änderung:
    └── INSERT INTO file_backup_history
        ├── file_path
        ├── file_content (vollständig)
        ├── content_hash
        ├── version (auto-increment pro Datei)
        └── reason: "Claude Code Pre-Hook Backup"

3. Request-Logging

Für alle Tools wird der Request protokolliert:

log_to_db.py
├── Extrahiert: tool_name, tool_input
├── Sanitized: Sensible Daten (Passwörter, Tokens)
├── Schätzt: tokens_input
│
└── INSERT INTO protokoll
    ├── request (JSON)
    ├── request_timestamp
    ├── status: 'pending'
    └── Speichert: pending_request für PostToolUse-Matching

Blockierung

Ein Pre-Hook kann die Ausführung blockieren durch:

Durchlassen

Bei Erfolg gibt der Hook zurück:

{"continue": true}

oder

{"allowed": true}

Geschützte Verzeichnisse

Backups werden erstellt für:

Erstellt: 2025-12-23 | Aktualisiert: 2025-12-23

Post-Hook Ablauf

Der Post-Hook wird nach jeder Tool-Ausführung aufgerufen und führt Aufräumarbeiten sowie Logging durch.

Trigger

Post-Hooks werden bei folgenden Tools ausgelöst:

Ablauf bei Edit/Write

1. Berechtigungskorrektur

Nach jeder Edit/Write-Operation:

fix-permissions.sh
├── chown -R www-data:www-data /var/www/dev.campus...
├── chown -R www-data:www-data /var/www/prod.campus...
├── chmod -R 755 /var/www/dev.campus...
└── chmod -R 755 /var/www/prod.campus...

Warum? Claude Code läuft als root. Ohne Korrektur hätten die Dateien falschen Owner und Apache könnte sie nicht lesen.

2. Response-Logging

Für alle Tools wird die Response protokolliert:

log_to_db.py
├── Sucht: Matching PreToolUse-Request
│   └── Über: session_id + tool_name
│
├── Extrahiert: tool_response
├── Sanitized: Sensible Daten
├── Schätzt: tokens_output
│
└── UPDATE protokoll SET
    ├── response (JSON)
    ├── response_timestamp
    ├── tokens_output
    ├── tokens_total = tokens_input + tokens_output
    ├── duration_ms (berechnet aus Timestamps)
    └── status: 'completed'

Request/Response-Pairing

Das Logging-System verbindet Pre- und Post-Hook-Events:

PreToolUse (Edit "file.php")
├── INSERT protokoll → ID=123
└── Speichert: /tmp/claude_hooks/{session}_{tool}_PreToolUse.json
    └── {"db_id": 123, "timestamp": "..."}

[Tool-Ausführung]

PostToolUse (Edit "file.php")
├── Lädt: /tmp/claude_hooks/{session}_{tool}_PreToolUse.json
├── Findet: db_id=123
├── UPDATE protokoll WHERE id=123
│   └── SET response, duration_ms, status='completed'
└── Löscht: Tracking-Datei

Duration-Berechnung

Die Dauer wird präzise aus den Timestamps berechnet:

duration_ms = TIMESTAMPDIFF(MICROSECOND, request_timestamp, response_timestamp) / 1000

Damit ist die exakte Tool-Ausführungszeit in Millisekunden erfasst.

Fail-Open Prinzip

Bei Fehlern im Post-Hook:

Post-Hooks sind nie blockierend, da die Aktion bereits abgeschlossen ist.

Hook-Scripts

Übersicht aller Scripts, die im Hook-System verwendet werden.

Hauptverzeichnisse

Pfad Zweck
/var/www/tools/ki-protokoll/claude-hook/ Protokollierung, Backup, Workflow-Guards
/var/www/scripts/hooks/ Sicherheits-Blocker
/var/www/scripts/ Utility-Scripts

Script-Übersicht

log_to_db.py

Pfad/var/www/tools/ki-protokoll/claude-hook/log_to_db.py
EventsUserPromptSubmit, PreToolUse, PostToolUse, Stop, SessionStart, SessionEnd
Datenbankki_dev.protokoll
Funktion
  • Protokolliert alle Claude Code Events
  • Request/Response-Pairing mit Duration
  • Token-Schätzung (4 Zeichen = 1 Token)
  • Sensitive Daten werden redacted

file_backup_hook.py

Pfad/var/www/tools/ki-protokoll/claude-hook/file_backup_hook.py
EventsPreToolUse (Edit, Write)
Datenbankki_dev.file_backup_history
Funktion
  • Sichert Datei-Inhalt vor Änderung
  • Versionierung pro Datei
  • Hash-basierte Duplikat-Erkennung
  • Max. 10 MB pro Datei

task_completion_guard.py

Pfad/var/www/tools/ki-protokoll/claude-hook/task_completion_guard.py
EventsPreToolUse (mcp__mcp-tasks__tasks_status)
Datenbankki_dev.task_results
Funktion
  • Blockiert tasks_status(completed) ohne Result
  • Prüft: SELECT COUNT(*) FROM task_results WHERE task_id = ?
  • Exit 2 = Block, Exit 0 = Allow
  • Fail-open bei DB-Fehlern
DokumentationTask-Completion Guard Hook

block_direct_db.py

Pfad/var/www/scripts/hooks/block_direct_db.py
EventsPreToolUse (Bash)
Funktion
  • Blockiert direkte MySQL/MariaDB-Zugriffe
  • Patterns: mysql -p, --password=
  • Empfiehlt: MCP-DB Tools

block_direct_task_db.py

Pfad/var/www/scripts/hooks/block_direct_task_db.py
EventsPreToolUse (Bash)
Funktion
  • Blockiert SQL auf Task-Tabellen
  • Patterns: INSERT/UPDATE/DELETE auf tasks, task_*
  • Empfiehlt: MCP-Tasks Tools

fix-permissions.sh

Pfad/var/www/scripts/fix-permissions.sh
EventsPostToolUse (Edit, Write)
Funktion
  • Setzt Owner auf www-data:www-data
  • Setzt Permissions auf 755
  • Für dev und prod Verzeichnisse

Hook-Konfiguration

Die Hooks werden in /root/.claude/settings.json definiert:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {"type": "command", "command": "/var/www/scripts/hooks/block_direct_db.py"},
          {"type": "command", "command": "/var/www/scripts/hooks/block_direct_task_db.py"}
        ]
      },
      {
        "matcher": "mcp__mcp-tasks__tasks_status",
        "hooks": [
          {"type": "command", "command": ".../task_completion_guard.py", "timeout": 5}
        ]
      },
      {
        "matcher": "Edit|Write",
        "hooks": [
          {"type": "command", "command": ".../file_backup_hook.py", "timeout": 10}
        ]
      },
      {
        "matcher": "",
        "hooks": [
          {"type": "command", "command": ".../log_to_db.py", "timeout": 5}
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {"type": "command", "command": "/var/www/scripts/fix-permissions.sh"}
        ]
      },
      {
        "matcher": "",
        "hooks": [
          {"type": "command", "command": ".../log_to_db.py", "timeout": 10}
        ]
      }
    ]
  }
}

Protokollierung

Alle Claude Code Aktivitäten werden in der Datenbank ki_dev.protokoll protokolliert.

Tabellen-Schema

protokoll

Spalte Typ Beschreibung
idBIGINTPrimary Key
timestampDATETIME(6)Event-Zeitpunkt
request_ipVARCHAR(45)Client-IP (aus SSH_CLIENT)
client_nameVARCHAR(255)User (aus $USER)
requestTEXTRequest-Daten (sanitized)
request_timestampDATETIME(6)Request-Zeitpunkt (Microseconds)
responseTEXTResponse-Daten (sanitized)
response_timestampDATETIME(6)Response-Zeitpunkt
duration_msINT UNSIGNEDDauer in Millisekunden
tokens_inputINT UNSIGNEDGeschätzte Input-Tokens
tokens_outputINT UNSIGNEDGeschätzte Output-Tokens
tokens_totalINT UNSIGNEDGesamt-Tokens
model_nameVARCHAR(255)Verwendetes Modell
statusENUM'pending', 'completed', 'error'
error_messageTEXTFehlermeldung bei status='error'

file_backup_history

Spalte Typ Beschreibung
idINTPrimary Key
file_pathVARCHAR(512)Absoluter Dateipfad
file_contentLONGTEXTVollständiger Dateiinhalt
content_hashCHAR(64)SHA256-Hash
file_sizeINTDateigröße in Bytes
versionINTVersion pro Datei
change_typeENUM'created', 'modified', 'deleted'
changed_atTIMESTAMPBackup-Zeitpunkt
changed_byVARCHAR(100)claude-code-hook
reasonTEXTBackup-Grund
diff_summaryTEXTZusammenfassung der Änderungen
affected_entitiesLONGTEXTBetroffene Code-Entitäten (JSON)

Event-Typen im Request

UserPromptSubmit

{
  "event": "UserPromptSubmit",
  "prompt": "Erstelle eine neue Funktion..."
}

PreToolUse

{
  "event": "PreToolUse",
  "tool_name": "Edit",
  "tool_input": {
    "file_path": "/var/www/.../file.php",
    "old_string": "...",
    "new_string": "..."
  }
}

PostToolUse (Response)

{
  "tool_response": {
    "success": true,
    "message": "File updated"
  }
}

Sicherheit: Data Sanitization

Folgende Daten werden automatisch redacted:

Key-Patterns

Value-Patterns

Truncation

Felder > 10.000 Zeichen werden gekürzt mit Hash-Suffix:

...content... [TRUNCATED-a1b2c3d4]

Abfrage-Beispiele

Letzte Tool-Aufrufe

SELECT 
    timestamp,
    JSON_EXTRACT(request, '$.tool_name') as tool,
    duration_ms,
    status
FROM protokoll 
WHERE JSON_EXTRACT(request, '$.event') = 'PreToolUse'
ORDER BY id DESC 
LIMIT 10;

Token-Verbrauch pro Tag

SELECT 
    DATE(timestamp) as tag,
    SUM(tokens_total) as tokens,
    COUNT(*) as requests
FROM protokoll 
GROUP BY DATE(timestamp)
ORDER BY tag DESC;

Datei-Versionen

SELECT version, changed_at, file_size, content_hash
FROM file_backup_history 
WHERE file_path = '/var/www/.../Controller.php'
ORDER BY version DESC;

Verbesserungsvorschläge für Pre-/Post-Hooks

Basierend auf der Analyse des KI-Protokolls wurden folgende wiederkehrende Korrektur-Muster identifiziert:

Analyse: Häufige Korrekturen durch Supervision

Kategorie Häufigkeit Beispiele
Fatal Errors Hoch Class not found, Undefined method, PDOException
Architektur-Violations Hoch Controller mit direktem PDO-Zugriff, fehlende DI
Code Style Mittel PHP-CS-Fixer Issues, Import-Sortierung
UI/UX Logik Mittel Progress 1500%, falsche Terminologie
404 Errors Mittel Fehlende Routes, falsche Pfade

Vorschlag 1: PHP Syntax Check (Pre-Hook)

Hook-EventPreToolUse (Write)
TriggerNeue PHP-Datei wird erstellt
Aktionphp -l auf neuen Inhalt
Bei FehlerBlockieren mit Syntax-Fehlermeldung
Status⏳ Offen

Vorschlag 2: Class/Use Statement Validator (Pre-Hook)

Hook-EventPreToolUse (Edit, Write)
TriggerPHP-Datei mit new ClassName
AktionPrüft ob use-Statement oder FQCN vorhanden
Bei FehlerWarnung mit fehlenden Imports
Status⏳ Offen

Vorschlag 3: Route Existence Check (Post-Hook)

Hook-EventPostToolUse (Edit auf routes/*.php)
TriggerRoute-Datei wurde geändert
AktionPrüft ob alle Controller-Methoden existieren
Bei FehlerWarnung mit fehlenden Methoden
Status⏳ Offen

Vorschlag 4: Contract Pre-Validation (Pre-Hook)

Hook-EventPreToolUse (Edit auf src/Controller/*.php)
TriggerController-Datei wird bearbeitet
AktionSchnelle Regex-Prüfung der Architecture-Regeln
Bei FehlerBlockieren mit Violation-Details
Status✅ Implementiert
Script/var/www/tools/ki-protokoll/claude-hook/architecture_guard.py
Contractlayered-architecture-pruefung_v1.0

Hinweis: Der Architecture Guard ist seit 2025-12-23 aktiv und blockiert Architektur-Violations wie:

Vorschlag 5: PHPStan Quick Check (Post-Hook)

Hook-EventPostToolUse (Edit, Write auf *.php)
TriggerPHP-Datei wurde geändert
AktionPHPStan Level 5 auf geänderte Datei
Bei FehlerWarnung (nicht blockierend)
Status⏳ Offen

Vorschlag 6: Services.php Sync Check (Post-Hook)

Hook-EventPostToolUse (Write auf src/Controller/*.php)
TriggerNeuer Controller erstellt
AktionPrüft ob Constructor-Dependencies in services.php registriert
Bei FehlerWarnung mit fehlenden Registrierungen
Status⏳ Offen

Implementierungs-Priorität

Priorität Hook Status Begründung
1 (Kritisch) PHP Syntax Check Verhindert Fatal Errors vor Deployment
2 (Kritisch) Architecture Guard Verhindert Layer-Violations sofort
3 (Hoch) Class Import Validator Verhindert "Class not found" Errors
4 (Mittel) Route Existence Check Verhindert 404 bei neuen Routes
5 (Mittel) PHPStan Quick Check Frühe Type-Error Erkennung
6 (Niedrig) DI Sync Check Verhindert Runtime DI-Fehler

Erwarteter Impact

Mit den vorgeschlagenen Hooks würden geschätzt 70-80% der im Protokoll gefundenen Korrekturen bereits vor/während der Code-Erstellung abgefangen:

Task-Completion Guard Hook

Pre-Hook der verhindert, dass Tasks als "completed" markiert werden, ohne dass vorher ein Ergebnis via tasks_result() geschrieben wurde.

Problem

Claude ruft tasks_status(id, "completed") auf, ohne vorher tasks_result() zu rufen. Dies führt zu 77+ Fehlern pro Woche mit der Meldung:

Task kann nicht abgeschlossen werden. Fehlend: Ergebnis (tasks_result)

Lösung

Ein PreToolUse-Hook der VOR dem MCP-Call prüft, ob ein Result existiert und bei Fehlen die Aktion blockiert.

Datei/var/www/tools/ki-protokoll/claude-hook/task_completion_guard.py
TriggerPreToolUse mit Matcher mcp__mcp-tasks__tasks_status
Exit-Codes0 = allow, 2 = block

Technische Details

1. Input-Format (stdin)

{
  "tool_name": "mcp__mcp-tasks__tasks_status",
  "tool_input": {
    "id": 425,
    "status": "completed"
  }
}

2. Prüflogik

  1. Parse JSON von stdin
  2. Prüfe: tool_name == "mcp__mcp-tasks__tasks_status"
  3. Prüfe: status == "completed"
  4. Wenn ja: DB-Abfrage SELECT COUNT(*) FROM task_results WHERE task_id = ?
  5. Wenn count == 0: Block mit Exit-Code 2 + stderr-Nachricht

3. Block-Nachricht

BLOCKIERT: Task kann nicht als 'completed' markiert werden!

GRUND: Kein Ergebnis vorhanden (tasks_result fehlt).

LÖSUNG: Vor tasks_status(id, "completed") MUSS tasks_result() aufgerufen werden:

    tasks_result(
        id=TASK_ID,
        response="Zusammenfassung der erledigten Arbeit...",
        executor="claude",
        executor_type="claude"
    )

Erst danach: tasks_status(id, "completed")

4. Konfiguration in settings.json

{
  "PreToolUse": [
    {
      "matcher": "mcp__mcp-tasks__tasks_status",
      "hooks": [
        {
          "type": "command",
          "command": "/var/www/tools/ki-protokoll/claude-hook/task_completion_guard.py",
          "timeout": 5
        }
      ]
    }
  ]
}

Ablauf

┌─────────────────────────────┐
│ Claude: tasks_status(       │
│   id=425, status="completed"│
│ )                           │
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│ PreToolUse Hook auslösen    │
│ Matcher: mcp__mcp-tasks__   │
│          tasks_status       │
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│ task_completion_guard.py    │
│ - Parse Input               │
│ - Check: status=="completed"│
└─────────────┬───────────────┘
              │
       ┌──────┴──────┐
       │             │
       ▼             ▼
┌─────────────┐ ┌─────────────┐
│ status !=   │ │ status ==   │
│ "completed" │ │ "completed" │
└──────┬──────┘ └──────┬──────┘
       │               │
       ▼               ▼
┌─────────────┐ ┌─────────────────┐
│ exit(0)     │ │ DB-Check:       │
│ → Allow     │ │ task_results    │
└─────────────┘ │ WHERE task_id=? │
                └────────┬────────┘
                         │
                  ┌──────┴──────┐
                  │             │
                  ▼             ▼
           ┌──────────┐  ┌──────────┐
           │ count > 0│  │ count = 0│
           └────┬─────┘  └────┬─────┘
                │             │
                ▼             ▼
           ┌─────────┐  ┌─────────────┐
           │ exit(0) │  │ stderr:     │
           │ → Allow │  │ BLOCKIERT   │
           └─────────┘  │ exit(2)     │
                        │ → Block     │
                        └─────────────┘

Implementierungsplan

Schritt 1: Hook-Script erstellen

Datei: /var/www/tools/ki-protokoll/claude-hook/task_completion_guard.py

#!/usr/bin/env python3
"""
Task Completion Guard Hook

Blockiert tasks_status(completed) wenn kein Result existiert.
Erzwingt korrekten Workflow: tasks_result() vor tasks_status(completed).

Trigger: PreToolUse (mcp__mcp-tasks__tasks_status)
"""

import json
import sys
import os
from pathlib import Path
from dotenv import load_dotenv
import pymysql

# Lade Environment aus .env im Hook-Verzeichnis
load_dotenv(Path(__file__).parent / '.env')

DB_CONFIG = {
    'host': os.environ.get('CLAUDE_DB_HOST', 'localhost'),
    'port': int(os.environ.get('CLAUDE_DB_PORT', '3306')),
    'user': os.environ.get('CLAUDE_DB_USER', 'root'),
    'password': os.environ.get('CLAUDE_DB_PASSWORD', ''),
    'database': 'ki_dev',
    'charset': 'utf8mb4'
}

BLOCK_MESSAGE = """BLOCKIERT: Task kann nicht als 'completed' markiert werden!

GRUND: Kein Ergebnis vorhanden (tasks_result fehlt).

LÖSUNG: Vor tasks_status(id, "completed") MUSS tasks_result() aufgerufen werden:

    tasks_result(
        id={task_id},
        response="Zusammenfassung der erledigten Arbeit...",
        executor="claude",
        executor_type="claude"
    )

Erst danach: tasks_status({task_id}, "completed")"""


def check_result_exists(task_id: int) -> bool:
    """Prüft ob ein Result für den Task existiert."""
    try:
        conn = pymysql.connect(**DB_CONFIG)
        cursor = conn.cursor()
        cursor.execute(
            "SELECT COUNT(*) FROM task_results WHERE task_id = %s",
            (task_id,)
        )
        count = cursor.fetchone()[0]
        conn.close()
        return count > 0
    except Exception as e:
        # Bei DB-Fehler durchlassen (fail-open)
        print(f"DB-Check fehlgeschlagen: {e}", file=sys.stderr)
        return True


def main():
    try:
        input_data = json.load(sys.stdin)
    except json.JSONDecodeError:
        sys.exit(0)
    
    # Nur mcp__mcp-tasks__tasks_status prüfen
    tool_name = input_data.get("tool_name", "")
    if tool_name != "mcp__mcp-tasks__tasks_status":
        sys.exit(0)
    
    # Prüfe ob Status auf "completed" gesetzt wird
    tool_input = input_data.get("tool_input", {})
    status = tool_input.get("status", "")
    task_id = tool_input.get("id")
    
    if status.lower() != "completed":
        sys.exit(0)
    
    if not task_id:
        sys.exit(0)
    
    # Prüfe ob Result existiert
    if not check_result_exists(task_id):
        print(BLOCK_MESSAGE.format(task_id=task_id), file=sys.stderr)
        sys.exit(2)
    
    sys.exit(0)


if __name__ == "__main__":
    main()

Schritt 2: Script ausführbar machen

chmod +x /var/www/tools/ki-protokoll/claude-hook/task_completion_guard.py

Schritt 3: settings.json erweitern

Datei: /root/.claude/settings.json

Füge folgenden Eintrag in "PreToolUse" Array hinzu:

{
  "matcher": "mcp__mcp-tasks__tasks_status",
  "hooks": [
    {
      "type": "command",
      "command": "/var/www/tools/ki-protokoll/claude-hook/task_completion_guard.py",
      "timeout": 5
    }
  ]
}

Schritt 4: Testen

# Test 1: Task ohne Result → sollte blockiert werden (Exit 2)
echo '{"tool_name":"mcp__mcp-tasks__tasks_status","tool_input":{"id":999,"status":"completed"}}' | \
  /var/www/tools/ki-protokoll/claude-hook/task_completion_guard.py
echo "Exit code: $?"

# Test 2: Anderer Status → sollte durchgelassen werden (Exit 0)
echo '{"tool_name":"mcp__mcp-tasks__tasks_status","tool_input":{"id":999,"status":"in_progress"}}' | \
  /var/www/tools/ki-protokoll/claude-hook/task_completion_guard.py
echo "Exit code: $?"

# Test 3: Anderes Tool → sollte durchgelassen werden (Exit 0)
echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | \
  /var/www/tools/ki-protokoll/claude-hook/task_completion_guard.py
echo "Exit code: $?"

Voraussetzungen

Fail-Safe Verhalten

Bei DB-Verbindungsfehlern wird der Hook "fail-open" - d.h. die Aktion wird durchgelassen, um Claude nicht zu blockieren. Die Server-seitige Validierung in MCP-Tasks greift dann als zweite Verteidigung.

Validierung

PrüfpunktStatus
PyMySQL verfügbar✓ PyMySQL 1.1.2 installiert
python-dotenv Pattern✓ Konsistent mit log_storage.py
DB_CONFIG Pattern✓ Identisch zu bestehenden Hooks
Exit-Code Pattern✓ 0=allow, 2=block (wie block_direct_db.py)
Matcher-Syntax✓ Regex-kompatibel für MCP-Tools
Fail-Open Design✓ Bei Fehler durchlassen

Hook-System Python-Erweiterung

Status: ✅ IMPLEMENTIERT (2025-12-28)
Task: #506

Problem

Das Claude Code Hook-System (/var/www/tools/ki-protokoll/claude-hook/) prüfte nur PHP-Dateien. Python-Dateien in der Pipeline (/var/www/scripts/pipeline/) wurden nicht validiert.

Root Cause

# hook_dispatcher.py Zeile 78-80 (vorher)
if not file_path.endswith(".php"):
    sys.exit(0)

Implementierung

Phase 1: Dispatcher (hook_dispatcher.py)

ALLOWED_EXTENSIONS = {".php", ".py"}
PYTHON_CHECK_PATHS = ["/var/www/scripts/pipeline/"]
SKIP_PATHS = ["/venv/", "/__pycache__/", "/tests/", "/vendor/"]

def should_check(file_path: str) -> bool:
    if any(skip in file_path for skip in SKIP_PATHS):
        return False
    ext = Path(file_path).suffix
    if ext not in ALLOWED_EXTENSIONS:
        return False
    if ext == ".php":
        return True
    if ext == ".py":
        return any(file_path.startswith(p) for p in PYTHON_CHECK_PATHS)
    return False

Phase 2: Python-Regeln (pre_rules_python.py)

PP1.1: Hardcoded Model-Namen blockieren

PP1.2: Hardcoded Pipeline-IDs blockieren

Phase 3: Integration (pre_rules.py)

# Regelfilterung nach Dateityp
if file_path.endswith(".php"):
    rules = PHP_RULES
elif file_path.endswith(".py"):
    rules = PYTHON_RULES
else:
    return allow()

Testmatrix (7/7 bestanden)

TestSzenarioErwartetErgebnis
1PP1.1 default="mistral"DENY
2PP1.1 get_pipeline_model()ALLOW
3PP1.1 DEFAULT_MODEL = "mistral"ALLOW
4PP1.2 pipeline_id = 5DENY
5PP1.2 DEFAULT_PIPELINE_ID = 5ALLOW
6Skip /venv/ PfadeALLOW
7PHP P1.1 @responsibilityDENY

Dateien

DateiAktion
hook_dispatcher.pyMODIFIZIERT
quality/pre_rules_python.pyNEU
quality/pre_rules.pyMODIFIZIERT