Hooks

Hooks bieten ein erweiterbares, ereignisgesteuertes System, um Aktionen als Reaktion auf Agent-Befehle und Events zu automatisieren. Hooks werden automatisch aus Verzeichnissen erkannt und können per CLI verwaltet werden, ähnlich wie Skills in OpenClaw.

Orientierung

Hooks sind kleine Skripte, die laufen, wenn etwas passiert. Es gibt zwei Arten:

  • Hooks (diese Seite): Laufen innerhalb des Gateways, wenn Agent-Events ausgelöst werden, wie /new, /reset, /stop oder Lifecycle-Events.
  • Webhooks: Externe HTTP-Webhooks, mit denen andere Systeme Arbeit in OpenClaw auslösen können. Siehe Webhook Hooks oder nutze openclaw webhooks für Gmail-Hilfsbefehle.

Hooks können auch in Plugins gebündelt werden; siehe Plugins.

Typische Anwendungsfälle:

  • Einen Memory-Snapshot speichern, wenn du eine Session zurücksetzt
  • Ein Audit-Trail von Befehlen für Fehlerbehebung oder Compliance führen
  • Folge-Automatisierungen auslösen, wenn eine Session startet oder endet
  • Dateien in den Agent-Workspace schreiben oder externe APIs aufrufen, wenn Events feuern

Wenn du eine kleine TypeScript-Funktion schreiben kannst, kannst du auch einen Hook schreiben. Hooks werden automatisch erkannt, und du aktivierst oder deaktivierst sie über die CLI.

Überblick

Das Hook-System erlaubt dir:

  • Session-Kontext beim Ausführen von /new im Memory zu speichern
  • Alle Befehle für Auditing zu protokollieren
  • Benutzerdefinierte Automatisierungen bei Agent-Lifecycle-Events auszulösen
  • Das Verhalten von OpenClaw zu erweitern, ohne den Kerncode zu ändern

Erste Schritte

Mitgelieferte Hooks

OpenClaw wird mit vier mitgelieferten Hooks ausgeliefert, die automatisch erkannt werden:

  • 💾 session-memory: Speichert den Session-Kontext in deinem Agent-Workspace (Standard ~/.openclaw/workspace/memory/), wenn du /new ausführst
  • 📎 bootstrap-extra-files: Injiziert zusätzliche Workspace-Bootstrap-Dateien aus konfigurierten Glob-/Pfad-Mustern während agent:bootstrap
  • 📝 command-logger: Protokolliert alle Befehlsevents in ~/.openclaw/logs/commands.log
  • 🚀 boot-md: Führt BOOT.md beim Gateway-Start aus (erfordert aktivierte interne Hooks)

Verfügbare Hooks auflisten:

openclaw hooks list

Einen Hook aktivieren:

openclaw hooks enable session-memory

Hook-Status prüfen:

openclaw hooks check

Detaillierte Informationen anzeigen:

openclaw hooks info session-memory

Onboarding

Während des Onboardings (openclaw onboard) wirst du aufgefordert, empfohlene Hooks zu aktivieren. Der Assistent erkennt automatisch berechtigte Hooks und stellt sie zur Auswahl.

Hook-Erkennung

Hooks werden automatisch aus drei Verzeichnissen erkannt (in Reihenfolge der Priorität):

  1. Workspace-Hooks: <workspace>/hooks/ (pro Agent, höchste Priorität)
  2. Verwaltete Hooks: ~/.openclaw/hooks/ (benutzerinstalliert, über Workspaces hinweg geteilt)
  3. Mitgelieferte Hooks: <openclaw>/dist/hooks/bundled/ (mit OpenClaw ausgeliefert)

Verwaltete Hook-Verzeichnisse können entweder ein einzelner Hook oder ein Hook-Pack (Paketverzeichnis) sein.

Jeder Hook ist ein Verzeichnis mit:

my-hook/
├── HOOK.md          # Metadaten + Dokumentation
└── handler.ts       # Handler-Implementierung

Hook Packs (npm/Archive)

Hook Packs sind Standard-npm-Pakete, die ein oder mehrere Hooks über openclaw.hooks in package.json exportieren. Installiere sie mit:

openclaw hooks install <path-or-spec>

Npm-Specs sind nur Registry (Paketname + optionale exakte Version oder Dist-Tag). Git/URL/File-Specs und Semver-Ranges werden abgelehnt.

Bare Specs und @latest bleiben auf dem Stable-Track. Wenn npm eines davon auf ein Prerelease auflöst, stoppt OpenClaw und fragt dich, explizit mit einem Prerelease-Tag wie @beta/@rc oder einer exakten Prerelease-Version einzuwilligen.

Beispiel package.json:

{
  "name": "@acme/my-hooks",
  "version": "0.1.0",
  "openclaw": {
    "hooks": ["./hooks/my-hook", "./hooks/other-hook"]
  }
}

Jeder Eintrag zeigt auf ein Hook-Verzeichnis mit HOOK.md und handler.ts (oder index.ts). Hook Packs können Abhängigkeiten mitliefern; sie werden unter ~/.openclaw/hooks/<id> installiert. Jeder openclaw.hooks-Eintrag muss nach Symlink-Auflösung innerhalb des Paketverzeichnisses bleiben; Einträge die ausbrechen werden abgelehnt.

Sicherheitshinweis: openclaw hooks install installiert Abhängigkeiten mit npm install --ignore-scripts (keine Lifecycle-Skripte). Halte Hook-Pack-Abhängigkeitsbäume auf “reines JS/TS” und vermeide Pakete, die auf postinstall-Builds angewiesen sind.

Hook-Struktur

HOOK.md Format

Die HOOK.md-Datei enthält Metadaten im YAML-Frontmatter plus Markdown-Dokumentation:

---
name: my-hook
description: "Short description of what this hook does"
homepage: https://docs.openclaw.ai/automation/hooks#my-hook
metadata:
  { "openclaw": { "emoji": "🔗", "events": ["command:new"], "requires": { "bins": ["node"] } } }
---

# My Hook

Detailed documentation goes here...

## What It Does

- Listens for `/new` commands
- Performs some action
- Logs the result

## Requirements

- Node.js must be installed

## Configuration

No configuration needed.

Metadaten-Felder

Das metadata.openclaw-Objekt unterstützt:

  • emoji: Anzeige-Emoji für die CLI (z.B. "💾")
  • events: Array von Events, auf die gehört wird (z.B. ["command:new", "command:reset"])
  • export: Benannter Export (Standard "default")
  • homepage: Dokumentations-URL
  • requires: Optionale Anforderungen
    • bins: Erforderliche Binaries im PATH (z.B. ["git", "node"])
    • anyBins: Mindestens eines dieser Binaries muss vorhanden sein
    • env: Erforderliche Umgebungsvariablen
    • config: Erforderliche Konfigurationspfade (z.B. ["workspace.dir"])
    • os: Erforderliche Plattformen (z.B. ["darwin", "linux"])
  • always: Berechtigungsprüfungen umgehen (boolean)
  • install: Installationsmethoden (für mitgelieferte Hooks: [{"id":"bundled","kind":"bundled"}])

Handler-Implementierung

Die handler.ts-Datei exportiert eine HookHandler-Funktion:

const myHandler = async (event) => {
  // Nur bei 'new'-Befehl auslösen
  if (event.type !== "command" || event.action !== "new") {
    return;
  }

  console.log(`[my-hook] New command triggered`);
  console.log(`  Session: ${event.sessionKey}`);
  console.log(`  Timestamp: ${event.timestamp.toISOString()}`);

  // Deine Logik hier

  // Optional Nachricht an Benutzer senden
  event.messages.push("✨ My hook executed!");
};

export default myHandler;

Event-Kontext

Jedes Event enthält:

{
  type: 'command' | 'session' | 'agent' | 'gateway' | 'message',
  action: string,              // z.B. 'new', 'reset', 'stop', 'received', 'sent'
  sessionKey: string,          // Session-Bezeichner
  timestamp: Date,             // Zeitpunkt des Events
  messages: string[],          // Nachrichten hier pushen, um sie an den Benutzer zu senden
  context: {
    // Befehlsevents:
    sessionEntry?: SessionEntry,
    sessionId?: string,
    sessionFile?: string,
    commandSource?: string,    // z.B. 'whatsapp', 'telegram'
    senderId?: string,
    workspaceDir?: string,
    bootstrapFiles?: WorkspaceBootstrapFile[],
    cfg?: OpenClawConfig,
    // Message-Events (siehe Abschnitt Message Events für vollständige Details):
    from?: string,             // message:received
    to?: string,               // message:sent
    content?: string,
    channelId?: string,
    success?: boolean,         // message:sent
  }
}

Event-Typen

Befehlsevents

Werden ausgelöst, wenn Agent-Befehle ausgeführt werden:

  • command: Alle Befehlsevents (allgemeiner Listener)
  • command:new: Wenn /new ausgeführt wird
  • command:reset: Wenn /reset ausgeführt wird
  • command:stop: Wenn /stop ausgeführt wird

Session-Events

  • session:compact:before: Direkt bevor die Komprimierung die History zusammenfasst
  • session:compact:after: Nach Abschluss der Komprimierung mit Zusammenfassungs-Metadaten

Interne Hook-Payloads emittieren diese als type: "session" mit action: "compact:before" / action: "compact:after"; Listener abonnieren mit den kombinierten Keys oben. Spezifische Handler-Registrierung nutzt das Literalformat ${type}:${action}. Für diese Events registriere session:compact:before und session:compact:after.

Agent-Events

  • agent:bootstrap: Bevor Workspace-Bootstrap-Dateien injiziert werden (Hooks können context.bootstrapFiles mutieren)

Gateway-Events

Werden beim Gateway-Start ausgelöst:

  • gateway:startup: Nachdem Channels gestartet und Hooks geladen wurden

Message-Events

Werden ausgelöst, wenn Nachrichten empfangen oder gesendet werden:

  • message: Alle Message-Events (allgemeiner Listener)
  • message:received: Wenn eine eingehende Nachricht von einem Channel empfangen wird. Feuert früh in der Verarbeitung vor Media-Understanding. Inhalt kann rohe Platzhalter wie <media:audio> für Medienanhänge enthalten, die noch nicht verarbeitet wurden.
  • message:transcribed: Wenn eine Nachricht vollständig verarbeitet wurde, einschließlich Audio-Transkription und Link-Understanding. Zu diesem Zeitpunkt enthält transcript den vollständigen Transkripttext für Audio-Nachrichten. Nutze diesen Hook, wenn du Zugriff auf transkribierte Audio-Inhalte brauchst.
  • message:preprocessed: Feuert für jede Nachricht, nachdem alles Media- + Link-Understanding abgeschlossen ist, und gibt Hooks Zugriff auf den vollständig angereicherten Body (Transkripte, Bildbeschreibungen, Link-Zusammenfassungen), bevor der Agent ihn sieht.
  • message:sent: Wenn eine ausgehende Nachricht erfolgreich gesendet wurde

Message-Event-Kontext

Message-Events enthalten umfangreichen Kontext über die Nachricht:

// message:received Kontext
{
  from: string,           // Absender-Kennung (Telefonnummer, User-ID etc.)
  content: string,        // Nachrichteninhalt
  timestamp?: number,     // Unix-Zeitstempel beim Empfang
  channelId: string,      // Channel (z.B. "whatsapp", "telegram", "discord")
  accountId?: string,     // Provider-Account-ID für Multi-Account-Setups
  conversationId?: string, // Chat/Konversations-ID
  messageId?: string,     // Nachrichten-ID vom Provider
  metadata?: {            // Zusätzliche Provider-spezifische Daten
    to?: string,
    provider?: string,
    surface?: string,
    threadId?: string,
    senderId?: string,
    senderName?: string,
    senderUsername?: string,
    senderE164?: string,
  }
}

// message:sent Kontext
{
  to: string,             // Empfänger-Kennung
  content: string,        // Gesendeter Nachrichteninhalt
  success: boolean,       // Ob der Versand erfolgreich war
  error?: string,         // Fehlermeldung falls Versand fehlschlug
  channelId: string,      // Channel (z.B. "whatsapp", "telegram", "discord")
  accountId?: string,     // Provider-Account-ID
  conversationId?: string, // Chat/Konversations-ID
  messageId?: string,     // Vom Provider zurückgegebene Nachrichten-ID
  isGroup?: boolean,      // Ob diese ausgehende Nachricht zu einem Gruppen-/Channel-Kontext gehört
  groupId?: string,       // Gruppen-/Channel-Kennung zur Korrelation mit message:received
}

// message:transcribed Kontext
{
  body?: string,          // Roher eingehender Body vor Anreicherung
  bodyForAgent?: string,  // Angereicherter Body, den der Agent sieht
  transcript: string,     // Audio-Transkript-Text
  channelId: string,      // Channel (z.B. "telegram", "whatsapp")
  conversationId?: string,
  messageId?: string,
}

// message:preprocessed Kontext
{
  body?: string,          // Roher eingehender Body
  bodyForAgent?: string,  // Finaler angereicherter Body nach Media/Link-Understanding
  transcript?: string,    // Transkript wenn Audio vorhanden war
  channelId: string,      // Channel (z.B. "telegram", "whatsapp")
  conversationId?: string,
  messageId?: string,
  isGroup?: boolean,
  groupId?: string,
}

Beispiel: Message-Logger-Hook

const isMessageReceivedEvent = (event: { type: string; action: string }) =>
  event.type === "message" && event.action === "received";
const isMessageSentEvent = (event: { type: string; action: string }) =>
  event.type === "message" && event.action === "sent";

const handler = async (event) => {
  if (isMessageReceivedEvent(event as { type: string; action: string })) {
    console.log(`[message-logger] Received from ${event.context.from}: ${event.context.content}`);
  } else if (isMessageSentEvent(event as { type: string; action: string })) {
    console.log(`[message-logger] Sent to ${event.context.to}: ${event.context.content}`);
  }
};

export default handler;

Tool-Result-Hooks (Plugin-API)

Diese Hooks sind keine Event-Stream-Listener; sie erlauben Plugins, Tool-Ergebnisse synchron anzupassen, bevor OpenClaw sie persistiert.

  • tool_result_persist: Tool-Ergebnisse transformieren, bevor sie ins Session-Transkript geschrieben werden. Muss synchron sein; gib das aktualisierte Tool-Result-Payload zurück oder undefined, um es unverändert zu lassen. Siehe Agent Loop.

Plugin-Hook-Events

Komprimierungs-Lifecycle-Hooks, die über den Plugin-Hook-Runner bereitgestellt werden:

  • before_compaction: Läuft vor der Komprimierung mit Count/Token-Metadaten
  • after_compaction: Läuft nach der Komprimierung mit Komprimierungs-Zusammenfassungs-Metadaten

Zukünftige Events

Geplante Event-Typen:

  • session:start: Wenn eine neue Session beginnt
  • session:end: Wenn eine Session endet
  • agent:error: Wenn ein Agent einen Fehler erlebt

Eigene Hooks erstellen

1. Ort wählen

  • Workspace-Hooks (<workspace>/hooks/): Pro Agent, höchste Priorität
  • Verwaltete Hooks (~/.openclaw/hooks/): Über Workspaces hinweg geteilt

2. Verzeichnisstruktur erstellen

mkdir -p ~/.openclaw/hooks/my-hook
cd ~/.openclaw/hooks/my-hook

3. HOOK.md erstellen

---
name: my-hook
description: "Does something useful"
metadata: { "openclaw": { "emoji": "🎯", "events": ["command:new"] } }
---

# My Custom Hook

This hook does something useful when you issue `/new`.

4. handler.ts erstellen

const handler = async (event) => {
  if (event.type !== "command" || event.action !== "new") {
    return;
  }

  console.log("[my-hook] Running!");
  // Deine Logik hier
};

export default handler;

5. Aktivieren und testen

# Prüfen ob Hook erkannt wurde
openclaw hooks list

# Aktivieren
openclaw hooks enable my-hook

# Gateway-Prozess neu starten (Menüleisten-App auf macOS neu starten, oder Dev-Prozess neu starten)

# Event auslösen
# /new über deinen Messaging-Channel senden

Konfiguration

Neues Konfigurationsformat (empfohlen)

{
  "hooks": {
    "internal": {
      "enabled": true,
      "entries": {
        "session-memory": { "enabled": true },
        "command-logger": { "enabled": false }
      }
    }
  }
}

Pro-Hook-Konfiguration

Hooks können benutzerdefinierte Konfiguration haben:

{
  "hooks": {
    "internal": {
      "enabled": true,
      "entries": {
        "my-hook": {
          "enabled": true,
          "env": {
            "MY_CUSTOM_VAR": "value"
          }
        }
      }
    }
  }
}

Zusätzliche Verzeichnisse

Hooks aus zusätzlichen Verzeichnissen laden:

{
  "hooks": {
    "internal": {
      "enabled": true,
      "load": {
        "extraDirs": ["/path/to/more/hooks"]
      }
    }
  }
}

Legacy-Konfigurationsformat (weiterhin unterstützt)

Das alte Konfigurationsformat funktioniert weiterhin für Abwärtskompatibilität:

{
  "hooks": {
    "internal": {
      "enabled": true,
      "handlers": [
        {
          "event": "command:new",
          "module": "./hooks/handlers/my-handler.ts",
          "export": "default"
        }
      ]
    }
  }
}

Hinweis: module muss ein Workspace-relativer Pfad sein. Absolute Pfade und Traversal außerhalb des Workspace werden abgelehnt.

Migration: Nutze das neue Discovery-basierte System für neue Hooks. Legacy-Handler werden nach verzeichnisbasierten Hooks geladen.

CLI-Befehle

Hooks auflisten

# Alle Hooks auflisten
openclaw hooks list

# Nur berechtigte Hooks anzeigen
openclaw hooks list --eligible

# Ausführliche Ausgabe (fehlende Anforderungen anzeigen)
openclaw hooks list --verbose

# JSON-Ausgabe
openclaw hooks list --json

Hook-Informationen

# Detaillierte Infos zu einem Hook anzeigen
openclaw hooks info session-memory

# JSON-Ausgabe
openclaw hooks info session-memory --json

Berechtigung prüfen

# Berechtigungszusammenfassung anzeigen
openclaw hooks check

# JSON-Ausgabe
openclaw hooks check --json

Aktivieren/Deaktivieren

# Hook aktivieren
openclaw hooks enable session-memory

# Hook deaktivieren
openclaw hooks disable command-logger

Referenz der mitgelieferten Hooks

session-memory

Speichert den Session-Kontext im Memory, wenn du /new ausführst.

Events: command:new

Anforderungen: workspace.dir muss konfiguriert sein

Ausgabe: <workspace>/memory/YYYY-MM-DD-slug.md (Standard ~/.openclaw/workspace)

Was es macht:

  1. Nutzt den Pre-Reset-Session-Eintrag, um das richtige Transkript zu finden
  2. Extrahiert die letzten 15 Zeilen des Gesprächs
  3. Nutzt ein LLM, um einen beschreibenden Dateinamen-Slug zu generieren
  4. Speichert Session-Metadaten in einer datierten Memory-Datei

Beispielausgabe:

# Session: 2026-01-16 14:30:00 UTC

- **Session Key**: agent:main:main
- **Session ID**: abc123def456
- **Source**: telegram

Dateinamen-Beispiele:

  • 2026-01-16-vendor-pitch.md
  • 2026-01-16-api-design.md
  • 2026-01-16-1430.md (Fallback-Zeitstempel wenn Slug-Generierung fehlschlägt)

Aktivieren:

openclaw hooks enable session-memory

bootstrap-extra-files

Injiziert zusätzliche Bootstrap-Dateien (zum Beispiel monorepo-lokale AGENTS.md / TOOLS.md) während agent:bootstrap.

Events: agent:bootstrap

Anforderungen: workspace.dir muss konfiguriert sein

Ausgabe: Keine Dateien werden geschrieben; Bootstrap-Kontext wird nur im Speicher geändert.

Konfiguration:

{
  "hooks": {
    "internal": {
      "enabled": true,
      "entries": {
        "bootstrap-extra-files": {
          "enabled": true,
          "paths": ["packages/*/AGENTS.md", "packages/*/TOOLS.md"]
        }
      }
    }
  }
}

Hinweise:

  • Pfade werden relativ zum Workspace aufgelöst.
  • Dateien müssen innerhalb des Workspace bleiben (realpath-geprüft).
  • Nur erkannte Bootstrap-Basisnamen werden geladen.
  • Subagent-Allowlist bleibt erhalten (nur AGENTS.md und TOOLS.md).

Aktivieren:

openclaw hooks enable bootstrap-extra-files

command-logger

Protokolliert alle Befehlsevents in einer zentralen Audit-Datei.

Events: command

Anforderungen: Keine

Ausgabe: ~/.openclaw/logs/commands.log

Was es macht:

  1. Erfasst Event-Details (Befehlsaktion, Zeitstempel, Session-Key, Sender-ID, Quelle)
  2. Hängt an die Log-Datei im JSONL-Format an
  3. Läuft still im Hintergrund

Beispiel-Log-Einträge:

{"timestamp":"2026-01-16T14:30:00.000Z","action":"new","sessionKey":"agent:main:main","senderId":"+1234567890","source":"telegram"}
{"timestamp":"2026-01-16T15:45:22.000Z","action":"stop","sessionKey":"agent:main:main","senderId":"[email protected]","source":"whatsapp"}

Logs anzeigen:

# Letzte Befehle anzeigen
tail -n 20 ~/.openclaw/logs/commands.log

# Mit jq formatiert ausgeben
cat ~/.openclaw/logs/commands.log | jq .

# Nach Aktion filtern
grep '"action":"new"' ~/.openclaw/logs/commands.log | jq .

Aktivieren:

openclaw hooks enable command-logger

boot-md

Führt BOOT.md beim Gateway-Start aus (nachdem Channels gestartet wurden). Interne Hooks müssen dafür aktiviert sein.

Events: gateway:startup

Anforderungen: workspace.dir muss konfiguriert sein

Was es macht:

  1. Liest BOOT.md aus deinem Workspace
  2. Führt die Anweisungen über den Agent-Runner aus
  3. Sendet angeforderte ausgehende Nachrichten über das Message-Tool

Aktivieren:

openclaw hooks enable boot-md

Best Practices

Handler schnell halten

Hooks laufen während der Befehlsverarbeitung. Halte sie leichtgewichtig:

// ✓ Gut – asynchrone Arbeit, gibt sofort zurück
const handler: HookHandler = async (event) => {
  void processInBackground(event); // Fire and forget
};

// ✗ Schlecht – blockiert die Befehlsverarbeitung
const handler: HookHandler = async (event) => {
  await slowDatabaseQuery(event);
  await evenSlowerAPICall(event);
};

Fehler sauber behandeln

Riskante Operationen immer umschließen:

const handler: HookHandler = async (event) => {
  try {
    await riskyOperation(event);
  } catch (err) {
    console.error("[my-handler] Failed:", err instanceof Error ? err.message : String(err));
    // Nicht werfen – andere Handler sollen weiterlaufen
  }
};

Events früh filtern

Sofort zurückkehren, wenn das Event nicht relevant ist:

const handler: HookHandler = async (event) => {
  // Nur 'new'-Befehle behandeln
  if (event.type !== "command" || event.action !== "new") {
    return;
  }

  // Deine Logik hier
};

Spezifische Event-Keys verwenden

Wenn möglich, genaue Events in den Metadaten angeben:

metadata: { "openclaw": { "events": ["command:new"] } } # Spezifisch

Statt:

metadata: { "openclaw": { "events": ["command"] } } # Allgemein – mehr Overhead

Debugging

Hook-Logging aktivieren

Das Gateway protokolliert das Laden von Hooks beim Start:

Registered hook: session-memory -> command:new
Registered hook: bootstrap-extra-files -> agent:bootstrap
Registered hook: command-logger -> command
Registered hook: boot-md -> gateway:startup

Erkennung prüfen

Alle erkannten Hooks auflisten:

openclaw hooks list --verbose

Registrierung prüfen

In deinem Handler loggen, wenn er aufgerufen wird:

const handler: HookHandler = async (event) => {
  console.log("[my-handler] Triggered:", event.type, event.action);
  // Deine Logik
};

Berechtigung überprüfen

Prüfen, warum ein Hook nicht berechtigt ist:

openclaw hooks info my-hook

Auf fehlende Anforderungen in der Ausgabe achten.

Testen

Gateway-Logs

Gateway-Logs überwachen, um Hook-Ausführung zu sehen:

# macOS
./scripts/clawlog.sh -f

# Andere Plattformen
tail -f ~/.openclaw/gateway.log

Hooks direkt testen

Handler isoliert testen:

import { test } from "vitest";
import myHandler from "./hooks/my-hook/handler.js";

test("my handler works", async () => {
  const event = {
    type: "command",
    action: "new",
    sessionKey: "test-session",
    timestamp: new Date(),
    messages: [],
    context: { foo: "bar" },
  };

  await myHandler(event);

  // Nebeneffekte prüfen
});

Architektur

Kernkomponenten

  • src/hooks/types.ts: Typdefinitionen
  • src/hooks/workspace.ts: Verzeichnis-Scanning und Laden
  • src/hooks/frontmatter.ts: HOOK.md-Metadaten-Parsing
  • src/hooks/config.ts: Berechtigungsprüfung
  • src/hooks/hooks-status.ts: Status-Reporting
  • src/hooks/loader.ts: Dynamischer Modul-Loader
  • src/cli/hooks-cli.ts: CLI-Befehle
  • src/gateway/server-startup.ts: Lädt Hooks beim Gateway-Start
  • src/auto-reply/reply/commands-core.ts: Löst Befehlsevents aus

Erkennungsablauf

Gateway-Start

Verzeichnisse scannen (Workspace → verwaltet → mitgeliefert)

HOOK.md-Dateien parsen

Berechtigung prüfen (bins, env, config, os)

Handler von berechtigten Hooks laden

Handler für Events registrieren

Event-Ablauf

Benutzer sendet /new

Befehlsvalidierung

Hook-Event erstellen

Hook auslösen (alle registrierten Handler)

Befehlsverarbeitung fortsetzen

Session zurücksetzen

Fehlerbehebung

Hook wird nicht erkannt

  1. Verzeichnisstruktur prüfen:

    ls -la ~/.openclaw/hooks/my-hook/
    # Sollte zeigen: HOOK.md, handler.ts
  2. HOOK.md-Format prüfen:

    cat ~/.openclaw/hooks/my-hook/HOOK.md
    # Sollte YAML-Frontmatter mit name und metadata haben
  3. Alle erkannten Hooks auflisten:

    openclaw hooks list

Hook nicht berechtigt

Anforderungen prüfen:

openclaw hooks info my-hook

Auf fehlende Einträge achten:

  • Binaries (PATH prüfen)
  • Umgebungsvariablen
  • Konfigurationswerte
  • OS-Kompatibilität

Hook wird nicht ausgeführt

  1. Prüfen ob Hook aktiviert ist:

    openclaw hooks list
    # Sollte ✓ neben aktivierten Hooks zeigen
  2. Gateway-Prozess neu starten, damit Hooks neu geladen werden.

  3. Gateway-Logs auf Fehler prüfen:

    ./scripts/clawlog.sh | grep hook

Handler-Fehler

Auf TypeScript/Import-Fehler prüfen:

# Import direkt testen
node -e "import('./path/to/handler.ts').then(console.log)"

Migrations-Anleitung

Von Legacy-Konfiguration zu Discovery

Vorher:

{
  "hooks": {
    "internal": {
      "enabled": true,
      "handlers": [
        {
          "event": "command:new",
          "module": "./hooks/handlers/my-handler.ts"
        }
      ]
    }
  }
}

Nachher:

  1. Hook-Verzeichnis erstellen:

    mkdir -p ~/.openclaw/hooks/my-hook
    mv ./hooks/handlers/my-handler.ts ~/.openclaw/hooks/my-hook/handler.ts
  2. HOOK.md erstellen:

    ---
    name: my-hook
    description: "My custom hook"
    metadata: { "openclaw": { "emoji": "🎯", "events": ["command:new"] } }
    ---
    
    # My Hook
    
    Does something useful.
  3. Konfiguration aktualisieren:

    {
      "hooks": {
        "internal": {
          "enabled": true,
          "entries": {
            "my-hook": { "enabled": true }
          }
        }
      }
    }
  4. Prüfen und Gateway-Prozess neu starten:

    openclaw hooks list
    # Sollte zeigen: 🎯 my-hook ✓

Vorteile der Migration:

  • Automatische Erkennung
  • CLI-Verwaltung
  • Berechtigungsprüfung
  • Bessere Dokumentation
  • Einheitliche Struktur

Siehe auch