OpenClaw Hooks konfigurieren: Automatisierung in Minuten
Orientierung
Abschnitt betitelt „Orientierung“Hooks sind kleine Skripte, die ausgeführt werden, wenn ein bestimmtes Ereignis eintritt. Es gibt zwei Arten:
- Hooks (diese Seite): Diese laufen innerhalb des Gateways ab, wenn Agent-Events ausgelöst werden, wie zum Beispiel
/new,/reset,/stopoder Lifecycle-Events. - Webhooks: Externe HTTP-Webhooks, mit denen andere Systeme Aktionen in OpenClaw auslösen können. Schau dir dazu Webhook Hooks an oder nutze
openclaw webhooksfür Gmail-Hilfsbefehle.
Hooks können auch innerhalb von Plugins gebündelt sein; Details dazu findest du unter Plugin hooks. Der Befehl openclaw hooks list zeigt dir sowohl eigenständige Hooks als auch von Plugins verwaltete Hooks an.
Typische Anwendungsfälle:
- Speichere einen Memory-Snapshot, wenn du eine Session zurücksetzt.
- Erstelle einen Audit-Trail von Befehlen zur Fehlerbehebung oder für Compliance-Zwecke.
- Trigger Follow-up-Automatisierungen, wenn eine Session startet oder endet.
- Schreibe Dateien in den Agent-Workspace oder rufe externe APIs auf, wenn Events gefeuert werden.
Wenn du eine kleine TypeScript-Funktion schreiben kannst, kannst du auch einen Hook schreiben. Managed und Bundled Hooks gelten als vertrauenswürdiger lokaler Code. Workspace-Hooks werden automatisch erkannt, aber OpenClaw lässt sie deaktiviert, bis du sie explizit über das CLI oder die Konfiguration aktivierst.
Überblick
Abschnitt betitelt „Überblick“Das Hooks-System erlaubt dir:
- Session-Kontext im Memory zu speichern, wenn
/newaufgerufen wird. - Alle Befehle für Auditing-Zwecke zu protokollieren.
- Eigene Automatisierungen bei Agent-Lifecycle-Events auszulösen.
- Das Verhalten von OpenClaw zu erweitern, ohne den Core-Code zu ändern.
Erste Schritte
Abschnitt betitelt „Erste Schritte“Bundled Hooks
Abschnitt betitelt „Bundled Hooks“OpenClaw wird mit vier Bundled Hooks ausgeliefert, die automatisch erkannt werden:
- 💾 session-memory: Speichert den Session-Kontext in deinem Agent-Workspace (Standard:
~/.openclaw/workspace/memory/), wenn du/newoder/resetnutzt. - 📎 bootstrap-extra-files: Fügt während
agent:bootstrapzusätzliche Workspace-Bootstrap-Dateien aus konfigurierten Glob/Path-Mustern ein. - 📝 command-logger: Protokolliert alle Befehls-Events in
~/.openclaw/logs/commands.log. - 🚀 boot-md: Führt
BOOT.mdaus, wenn das Gateway startet (erfordert aktivierte interne Hooks).
Verfügbare Hooks auflisten:
openclaw hooks listEinen Hook aktivieren:
openclaw hooks enable session-memoryHook-Status prüfen:
openclaw hooks checkDetaillierte Informationen abrufen:
openclaw hooks info session-memoryOnboarding
Abschnitt betitelt „Onboarding“Während des Onboardings (openclaw onboard) wirst du gefragt, ob du empfohlene Hooks aktivieren möchtest. Der Wizard erkennt automatisch passende Hooks und bietet sie dir zur Auswahl an.
Trust Boundary
Abschnitt betitelt „Trust Boundary“Hooks laufen innerhalb des Gateway-Prozesses. Betrachte Bundled Hooks, Managed Hooks und hooks.internal.load.extraDirs als vertrauenswürdigen lokalen Code. Workspace-Hooks unter <workspace>/hooks/ sind Repo-lokaler Code. Daher verlangt OpenClaw einen expliziten Aktivierungsschritt, bevor sie geladen werden.
Hook-Erkennung
Abschnitt betitelt „Hook-Erkennung“Hooks werden automatisch in den folgenden Verzeichnissen gesucht (in der Reihenfolge steigender Priorität bei Überschreibungen):
- Bundled hooks: Werden mit OpenClaw ausgeliefert; sie befinden sich bei npm-Installationen unter
<openclaw>/dist/hooks/bundled/(oder in einem Geschwisterverzeichnishooks/bundled/bei kompilierten Binärdateien). - Plugin hooks: Hooks, die in installierten Plugins enthalten sind (siehe Plugin hooks).
- Managed hooks:
~/.openclaw/hooks/(vom Benutzer installiert, über Workspaces hinweg geteilt; können Bundled und Plugin Hooks überschreiben). Zusätzliche Hook-Verzeichnisse, die überhooks.internal.load.extraDirskonfiguriert wurden, werden ebenfalls als Managed Hooks behandelt und haben dieselbe Priorität. - Workspace hooks:
<workspace>/hooks/(pro Agent, standardmäßig deaktiviert; können keine Hooks aus anderen Quellen überschreiben).
Workspace-Hooks können neue Hook-Namen für ein Repo hinzufügen, aber sie können keine Bundled, Managed oder Plugin-Hooks mit demselben Namen überschreiben.
Managed Hook-Verzeichnisse können entweder ein einzelner Hook oder ein Hook-Pack (Package-Verzeichnis) sein.
Jeder Hook ist ein Verzeichnis, das Folgendes enthält:
my-hook/├── HOOK.md # Metadata + documentation└── handler.ts # Handler implementationHook Packs (npm/Archive)
Abschnitt betitelt „Hook Packs (npm/Archive)“Hook Packs sind Standard-npm-Pakete, die einen oder mehrere Hooks über openclaw.hooks in der package.json exportieren. Installiere sie mit:
openclaw plugins install <path-or-spec>Npm-Specs sind Registry-only (Paketname + optionale exakte Version oder Dist-Tag). Git/URL/File-Specs und Semver-Bereiche werden abgelehnt.
Bare Specs und @latest bleiben auf dem Stable-Track. Wenn npm eine dieser Versionen zu einem Prerelease auflöst, stoppt OpenClaw und bittet dich, explizit per Prerelease-Tag wie @beta/@rc oder einer exakten Prerelease-Version zuzustimmen.
Beispiel für eine 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, das eine HOOK.md und eine handler.ts (oder index.ts) enthält. Hook Packs können Dependencies mitliefern; diese werden unter ~/.openclaw/hooks/<id> installiert. Jeder openclaw.hooks-Eintrag muss nach der Symlink-Auflösung innerhalb des Paketverzeichnisses bleiben; Einträge, die nach außen führen, werden abgelehnt.
Sicherheitshinweis: openclaw plugins install installiert Hook-Pack-Dependencies mit npm install --ignore-scripts (keine Lifecycle-Scripts). Halte die Dependency-Trees von Hook Packs “pure JS/TS” und vermeide Pakete, die auf postinstall-Builds angewiesen sind.
Hook-Struktur
Abschnitt betitelt „Hook-Struktur“HOOK.md Format
Abschnitt betitelt „HOOK.md Format“Die HOOK.md-Datei enthält Metadaten im YAML-Frontmatter sowie eine Markdown-Dokumentation:
---name: my-hookdescription: "Short description of what this hook does"homepage: https://docs.openclaw.ai/automation/hooks#my-hookmetadata: { "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
Abschnitt betitelt „Metadaten-Felder“Das metadata.openclaw-Objekt unterstützt:
emoji: Anzeige-Emoji für das CLI (z. B."💾")events: Array von Events, auf die gehört werden soll (z. B.["command:new", "command:reset"])export: Benannter Export, der verwendet werden soll (Standard ist"default")homepage: URL zur Dokumentationos: Erforderliche Plattformen (z. B.["darwin", "linux"])requires: Optionale Anforderungenbins: Erforderliche Binaries im PATH (z. B.["git", "node"])anyBins: Mindestens eine dieser Binaries muss vorhanden seinenv: Erforderliche Umgebungsvariablenconfig: Erforderliche Konfigurationspfade (z. B.["workspace.dir"])
always: Eligibility-Checks umgehen (Boolean)install: Installationsmethoden (für gebündelte Hooks:[{"id":"bundled","kind":"bundled"}])
Handler-Implementierung
Abschnitt betitelt „Handler-Implementierung“Die Datei handler.ts exportiert eine HookHandler-Funktion:
const myHandler = async (event) => { // Only trigger on 'new' command 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()}`);
// Your custom logic here
// Optionally send message to user event.messages.push("✨ My hook executed!");};
export default myHandler;Event-Kontext
Abschnitt betitelt „Event-Kontext“Jedes Event enthält:
{ type: 'command' | 'session' | 'agent' | 'gateway' | 'message', action: string, // e.g., 'new', 'reset', 'stop', 'received', 'sent' sessionKey: string, // Session identifier timestamp: Date, // When the event occurred messages: string[], // Push messages here to send to user context: { // Command events (command:new, command:reset): sessionEntry?: SessionEntry, // current session entry previousSessionEntry?: SessionEntry, // pre-reset entry (preferred for session-memory) commandSource?: string, // e.g., 'whatsapp', 'telegram' senderId?: string, workspaceDir?: string, cfg?: OpenClawConfig, // Command events (command:stop only): sessionId?: string, // Agent bootstrap events (agent:bootstrap): bootstrapFiles?: WorkspaceBootstrapFile[], // Message events (see Message Events section for full details): from?: string, // message:received to?: string, // message:sent content?: string, channelId?: string, success?: boolean, // message:sent }}Event-Typen
Abschnitt betitelt „Event-Typen“Command-Events
Abschnitt betitelt „Command-Events“Werden ausgelöst, wenn Agent-Commands erteilt werden:
command: Alle Command-Events (allgemeiner Listener)command:new: Wenn der/new-Befehl erteilt wirdcommand:reset: Wenn der/reset-Befehl erteilt wirdcommand:stop: Wenn der/stop-Befehl erteilt wird
Session-Events
Abschnitt betitelt „Session-Events“session:compact:before: Direkt bevor die Compaction den Verlauf zusammenfasstsession:compact:after: Nachdem die Compaction mit Zusammenfassungs-Metadaten abgeschlossen wurde
Interne Hook-Payloads senden diese als type: "session" mit action: "compact:before" / action: "compact:after"; Listener abonnieren sie mit den oben genannten kombinierten Keys. Die spezifische Handler-Registrierung nutzt das Format ${type}:${action}. Registriere für diese Events session:compact:before und session:compact:after.
Agent-Events
Abschnitt betitelt „Agent-Events“agent:bootstrap: Bevor Workspace-Bootstrap-Dateien injiziert werden (Hooks könnencontext.bootstrapFilesverändern)
Gateway-Events
Abschnitt betitelt „Gateway-Events“Werden beim Start des Gateways ausgelöst:
gateway:startup: Nachdem Channels gestartet und Hooks geladen wurden
Session-Patch-Events
Abschnitt betitelt „Session-Patch-Events“Werden ausgelöst, wenn Session-Eigenschaften geändert werden:
session:patch: Wenn eine Session aktualisiert wird
Session-Event-Kontext
Abschnitt betitelt „Session-Event-Kontext“Session-Events enthalten einen detaillierten Kontext über die Session und die Änderungen:
{ sessionEntry: SessionEntry, // The complete updated session entry patch: { // The patch object (only changed fields) // Session identity & labeling label?: string | null, // Human-readable session label
// AI model configuration model?: string | null, // Model override (e.g., "claude-opus-4-5") thinkingLevel?: string | null, // Thinking level ("off"|"low"|"med"|"high") verboseLevel?: string | null, // Verbose output level reasoningLevel?: string | null, // Reasoning mode override elevatedLevel?: string | null, // Elevated mode override responseUsage?: "off" | "tokens" | "full" | null, // Usage display mode
// Tool execution settings execHost?: string | null, // Exec host (sandbox|gateway|node) execSecurity?: string | null, // Security mode (deny|allowlist|full) execAsk?: string | null, // Approval mode (off|on-miss|always) execNode?: string | null, // Node ID for host=node
// Subagent coordination spawnedBy?: string | null, // Parent session key (for subagents) spawnDepth?: number | null, // Nesting depth (0 = root)
// Communication policies sendPolicy?: "allow" | "deny" | null, // Message send policy groupActivation?: "mention" | "always" | null, // Group chat activation }, cfg: OpenClawConfig // Current gateway config}Sicherheitshinweis: Nur privilegierte Clients (einschließlich der Control UI) können session:patch-Events auslösen. Standard-WebChat-Clients sind für das Patchen von Sessions gesperrt (siehe PR #20800), daher wird der Hook bei diesen Verbindungen nicht ausgelöst.
Die vollständige Typdefinition findest du unter SessionsPatchParamsSchema in src/gateway/protocol/schema/sessions.ts.
Beispiel: Session-Patch-Logger-Hook
Abschnitt betitelt „Beispiel: Session-Patch-Logger-Hook“const handler = async (event) => { if (event.type !== "session" || event.action !== "patch") { return; } const { patch } = event.context; console.log(`[session-patch] Session updated: ${event.sessionKey}`); console.log(`[session-patch] Changes:`, patch);};
export default handler;Message-Events
Abschnitt betitelt „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 beliebigen Channel empfangen wird. Wird früh in der Verarbeitung ausgelöst, noch vor dem Media-Understanding. Der Inhalt kann rohe Platzhalter wie<media:audio>für noch nicht verarbeitete Anhänge enthalten.message:transcribed: Wenn eine Nachricht vollständig verarbeitet wurde, inklusive Audio-Transkription und Link-Understanding. Zu diesem Zeitpunkt enthälttranscriptden vollständigen Text für Audio-Nachrichten. Nutze diesen Hook, wenn du Zugriff auf transkribierte Audio-Inhalte benötigst.message:preprocessed: Wird für jede Nachricht ausgelöst, nachdem das Media- und Link-Understanding abgeschlossen ist. Hooks erhalten 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
Abschnitt betitelt „Message-Event-Kontext“Message-Events enthalten einen detaillierten Kontext zur Nachricht:
// message:received context{ from: string, // Sender identifier (phone number, user ID, etc.) content: string, // Message content timestamp?: number, // Unix timestamp when received channelId: string, // Channel (e.g., "whatsapp", "telegram", "discord") accountId?: string, // Provider account ID for multi-account setups conversationId?: string, // Chat/conversation ID messageId?: string, // Message ID from the provider metadata?: { // Additional provider-specific data to?: string, provider?: string, surface?: string, threadId?: string | number, senderId?: string, senderName?: string, senderUsername?: string, senderE164?: string, guildId?: string, // Discord guild / server ID channelName?: string, // Channel name (e.g., Discord channel name) }}
// message:sent context{ to: string, // Recipient identifier content: string, // Message content that was sent success: boolean, // Whether the send succeeded error?: string, // Error message if sending failed channelId: string, // Channel (e.g., "whatsapp", "telegram", "discord") accountId?: string, // Provider account ID conversationId?: string, // Chat/conversation ID messageId?: string, // Message ID returned by the provider isGroup?: boolean, // Whether this outbound message belongs to a group/channel context groupId?: string, // Group/channel identifier for correlation with message:received}
// message:transcribed context{ from?: string, // Sender identifier to?: string, // Recipient identifier body?: string, // Raw inbound body before enrichment bodyForAgent?: string, // Enriched body visible to the agent transcript: string, // Audio transcript text timestamp?: number, // Unix timestamp when received channelId: string, // Channel (e.g., "telegram", "whatsapp") conversationId?: string, messageId?: string, senderId?: string, // Sender user ID senderName?: string, // Sender display name senderUsername?: string, provider?: string, // Provider name surface?: string, // Surface name mediaPath?: string, // Path to the media file that was transcribed mediaType?: string, // MIME type of the media}
// message:preprocessed context{ from?: string, // Sender identifier to?: string, // Recipient identifier body?: string, // Raw inbound body bodyForAgent?: string, // Final enriched body after media/link understanding transcript?: string, // Transcript when audio was present timestamp?: number, // Unix timestamp when received channelId: string, // Channel (e.g., "telegram", "whatsapp") conversationId?: string, messageId?: string, senderId?: string, // Sender user ID senderName?: string, // Sender display name senderUsername?: string, provider?: string, // Provider name surface?: string, // Surface name mediaPath?: string, // Path to the media file mediaType?: string, // MIME type of the media isGroup?: boolean, groupId?: string,}Beispiel: Message-Logger-Hook
Abschnitt betitelt „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)
Abschnitt betitelt „Tool-Result-Hooks (Plugin-API)“Diese Hooks sind keine Event-Stream-Listener; sie ermöglichen es Plugins, Tool-Ergebnisse synchron anzupassen, bevor OpenClaw sie speichert.
tool_result_persist: Transformiert Tool-Ergebnisse, bevor sie in das Session-Transkript geschrieben werden. Muss synchron sein; gib das aktualisierte Tool-Result-Payload zurück oderundefined, um es unverändert zu lassen. Siehe Agent Loop.
Plugin-Hook-Events
Abschnitt betitelt „Plugin-Hook-Events“Compaction-Lifecycle-Hooks, die über den Plugin-Hook-Runner bereitgestellt werden:
before_compaction: Läuft vor der Compaction mit Count/Token-Metadatenafter_compaction: Läuft nach der Compaction mit Compaction-Summary-Metadaten
Zukünftige Events
Abschnitt betitelt „Zukünftige Events“Geplante Event-Typen:
session:start: Wenn eine neue Session beginntsession:end: Wenn eine Session endetagent:error: Wenn ein Agent auf einen Fehler stößt
Eigene Hooks erstellen
Abschnitt betitelt „Eigene Hooks erstellen“1. Ort wählen
Abschnitt betitelt „1. Ort wählen“- Workspace-Hooks (
<workspace>/hooks/): Pro Agent; können neue Hook-Namen hinzufügen, aber keine gebündelten, verwalteten oder Plugin-Hooks mit demselben Namen überschreiben - Managed-Hooks (
~/.openclaw/hooks/): Werden über Workspaces hinweg geteilt; können gebündelte und Plugin-Hooks überschreiben
2. Verzeichnisstruktur erstellen
Abschnitt betitelt „2. Verzeichnisstruktur erstellen“mkdir -p ~/.openclaw/hooks/my-hookcd ~/.openclaw/hooks/my-hook3. HOOK.md erstellen
Abschnitt betitelt „3. HOOK.md erstellen“---name: my-hookdescription: "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
Abschnitt betitelt „4. handler.ts erstellen“const handler = async (event) => { if (event.type !== "command" || event.action !== "new") { return; }
console.log("[my-hook] Running!"); // Your logic here};
export default handler;5. Aktivieren und Testen
Abschnitt betitelt „5. Aktivieren und Testen“# Verify hook is discoveredopenclaw hooks list
# Enable itopenclaw hooks enable my-hook
# Restart your gateway process (menu bar app restart on macOS, or restart your dev process)
# Trigger the event# Send /new via your messaging channelKonfiguration
Abschnitt betitelt „Konfiguration“Neues Konfigurationsformat (Empfohlen)
Abschnitt betitelt „Neues Konfigurationsformat (Empfohlen)“{ "hooks": { "internal": { "enabled": true, "entries": { "session-memory": { "enabled": true }, "command-logger": { "enabled": false } } } }}Konfiguration pro Hook
Abschnitt betitelt „Konfiguration pro Hook“Hooks können eine eigene Konfiguration haben:
{ "hooks": { "internal": { "enabled": true, "entries": { "my-hook": { "enabled": true, "env": { "MY_CUSTOM_VAR": "value" } } } } }}Zusätzliche Verzeichnisse
Abschnitt betitelt „Zusätzliche Verzeichnisse“Du kannst Hooks aus weiteren Verzeichnissen laden. Diese werden wie verwaltete Hooks behandelt und folgen derselben Priorität beim Überschreiben:
{ "hooks": { "internal": { "enabled": true, "load": { "extraDirs": ["/path/to/more/hooks"] } } }}Altes Konfigurationsformat (Wird weiterhin unterstützt)
Abschnitt betitelt „Altes Konfigurationsformat (Wird weiterhin unterstützt)“Das alte Format funktioniert aus Gründen der Abwärtskompatibilität immer noch:
{ "hooks": { "internal": { "enabled": true, "handlers": [ { "event": "command:new", "module": "./hooks/handlers/my-handler.ts", "export": "default" } ] } }}Hinweis: module muss ein Pfad relativ zum Workspace sein. Absolute Pfade oder Pfade außerhalb des Workspace werden abgelehnt.
Migration: Nutze für neue Hooks das neue, auf Discovery basierende System. Legacy-Handler werden nach den verzeichnisbasierten Hooks geladen.
CLI-Befehle
Abschnitt betitelt „CLI-Befehle“Hooks auflisten
Abschnitt betitelt „Hooks auflisten“# List all hooksopenclaw hooks list
# Show only eligible hooksopenclaw hooks list --eligible
# Verbose output (show missing requirements)openclaw hooks list --verbose
# JSON outputopenclaw hooks list --jsonHook-Informationen
Abschnitt betitelt „Hook-Informationen“# Show detailed info about a hookopenclaw hooks info session-memory
# JSON outputopenclaw hooks info session-memory --jsonBerechtigung prüfen
Abschnitt betitelt „Berechtigung prüfen“# Show eligibility summaryopenclaw hooks check
# JSON outputopenclaw hooks check --jsonAktivieren/Deaktivieren
Abschnitt betitelt „Aktivieren/Deaktivieren“# Enable a hookopenclaw hooks enable session-memory
# Disable a hookopenclaw hooks disable command-loggerReferenz der mitgelieferten Hooks
Abschnitt betitelt „Referenz der mitgelieferten Hooks“session-memory
Abschnitt betitelt „session-memory“Speichert den Session-Kontext im Speicher, wenn du /new oder /reset ausführst.
Events: command:new, command:reset
Voraussetzungen: workspace.dir muss konfiguriert sein
Output: <workspace>/memory/YYYY-MM-DD-slug.md (Standard ist ~/.openclaw/workspace)
Was der Hook macht:
- Er nutzt den Session-Eintrag vor dem Reset, um das richtige Transkript zu finden.
- Er extrahiert die letzten 15 Nachrichten von User und Assistant aus der Konversation (konfigurierbar).
- Er verwendet ein LLM, um einen aussagekräftigen Slug für den Dateinamen zu erstellen.
- Er speichert die Session-Metadaten in einer datierten Memory-Datei.
Beispiel-Output:
# Session: 2026-01-16 14:30:00 UTC
- **Session Key**: agent:main:main- **Session ID**: abc123def456- **Source**: telegram
## Conversation Summary
user: Can you help me design the API?assistant: Sure! Let's start with the endpoints...Beispiele für Dateinamen:
2026-01-16-vendor-pitch.md2026-01-16-api-design.md2026-01-16-1430.md(Fallback-Zeitstempel, falls die Slug-Generierung fehlschlägt)
Aktivieren:
openclaw hooks enable session-memorybootstrap-extra-files
Abschnitt betitelt „bootstrap-extra-files“Fügt während agent:bootstrap zusätzliche Bootstrap-Dateien ein (zum Beispiel lokale AGENTS.md oder TOOLS.md aus einem Monorepo).
Events: agent:bootstrap
Voraussetzungen: workspace.dir muss konfiguriert sein
Output: Es werden keine Dateien geschrieben; der Bootstrap-Kontext wird nur im Arbeitsspeicher angepasst.
Konfiguration:
{ "hooks": { "internal": { "enabled": true, "entries": { "bootstrap-extra-files": { "enabled": true, "paths": ["packages/*/AGENTS.md", "packages/*/TOOLS.md"] } } } }}Konfigurationsoptionen:
paths(string[]): Glob- oder Pfadmuster, die vom Workspace aus aufgelöst werden.patterns/files(string[]): Aliase fürpaths.
Hinweise:
- Pfade werden relativ zum Workspace aufgelöst.
- Dateien müssen innerhalb des Workspace bleiben (Prüfung via realpath).
- Nur bekannte Bootstrap-Dateinamen werden geladen (
AGENTS.md,SOUL.md,TOOLS.md,IDENTITY.md,USER.md,HEARTBEAT.md,BOOTSTRAP.md,MEMORY.md,memory.md). - Für Subagent- oder Cron-Sessions gilt eine eingeschränkte Allowlist (
AGENTS.md,TOOLS.md,SOUL.md,IDENTITY.md,USER.md).
Aktivieren:
openclaw hooks enable bootstrap-extra-filescommand-logger
Abschnitt betitelt „command-logger“Loggt alle Command-Events in eine zentrale Audit-Datei.
Events: command
Voraussetzungen: Keine
Output: ~/.openclaw/logs/commands.log
Was der Hook macht:
- Er erfasst Event-Details wie Command-Aktion, Zeitstempel, Session Key, Sender-ID und Quelle.
- Er hängt diese Daten im JSONL-Format an die Log-Datei an.
- Er läuft lautlos im Hintergrund.
- Er ermöglicht eine einfache spätere Analyse der Systemnutzung.
Beispiel für 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":"user@example.com","source":"whatsapp"}Logs ansehen:
# View recent commandstail -n 20 ~/.openclaw/logs/commands.log
# Pretty-print with jqcat ~/.openclaw/logs/commands.log | jq .
# Filter by actiongrep '"action":"new"' ~/.openclaw/logs/commands.log | jq .Aktivieren:
openclaw hooks enable command-loggerboot-md
Abschnitt betitelt „boot-md“Führt die BOOT.md aus, wenn das Gateway startet (nachdem die Channels bereit sind). Damit dies funktioniert, müssen interne Hooks aktiviert sein.
Events: gateway:startup
Voraussetzungen: workspace.dir muss konfiguriert sein
Was der Hook macht:
- Er liest die
BOOT.mdaus deinem Workspace und führt die Anweisungen über den Agent Runner aus. - Er sendet alle angeforderten ausgehenden Nachrichten über das Message Tool.
Aktivieren:
openclaw hooks enable boot-mdBewährte Methoden
Abschnitt betitelt „Bewährte Methoden“Handler schnell halten
Abschnitt betitelt „Handler schnell halten“Hooks werden während der Befehlsverarbeitung ausgeführt. Halte sie leichtgewichtig:
// ✓ Good - async work, returns immediatelyconst handler: HookHandler = async (event) => { void processInBackground(event); // Fire and forget};
// ✗ Bad - blocks command processingconst handler: HookHandler = async (event) => { await slowDatabaseQuery(event); await evenSlowerAPICall(event);};Fehler sauber abfangen
Abschnitt betitelt „Fehler sauber abfangen“Umschließe riskante Operationen immer mit Try-Catch:
const handler: HookHandler = async (event) => { try { await riskyOperation(event); } catch (err) { console.error("[my-handler] Failed:", err instanceof Error ? err.message : String(err)); // Don't throw - let other handlers run }};Events früh filtern
Abschnitt betitelt „Events früh filtern“Beende den Handler frühzeitig, wenn das Event nicht relevant ist:
const handler: HookHandler = async (event) => { // Only handle 'new' commands if (event.type !== "command" || event.action !== "new") { return; }
// Deine Logik hier};Spezifische Event-Keys nutzen
Abschnitt betitelt „Spezifische Event-Keys nutzen“Gib in den Metadaten nach Möglichkeit exakte Events an:
metadata: { "openclaw": { "events": ["command:new"] } } # SpezifischStattdessen solltest du dies vermeiden:
metadata: { "openclaw": { "events": ["command"] } } # General - more overheadDebugging
Abschnitt betitelt „Debugging“Hook-Logging aktivieren
Abschnitt betitelt „Hook-Logging aktivieren“Das Gateway loggt das Laden von Hooks direkt beim Startup. So siehst du sofort, was registriert wurde:
Registered hook: session-memory -> command:newRegistered hook: bootstrap-extra-files -> agent:bootstrapRegistered hook: command-logger -> commandRegistered hook: boot-md -> gateway:startupDiscovery prüfen
Abschnitt betitelt „Discovery prüfen“Falls ein Hook nicht auftaucht, kannst du alle entdeckten Hooks mit diesem Befehl auflisten:
openclaw hooks list --verboseRegistrierung prüfen
Abschnitt betitelt „Registrierung prüfen“Um sicherzugehen, dass dein Handler wirklich läuft, kannst du einen einfachen Log-Befehl einbauen:
const handler: HookHandler = async (event) => { console.log("[my-handler] Triggered:", event.type, event.action); // Your logic};Eignung verifizieren
Abschnitt betitelt „Eignung verifizieren“Wenn ein Hook zwar da ist, aber nicht ausgeführt wird, hilft dieser Befehl:
openclaw hooks info my-hookSuche in der Ausgabe nach fehlenden Anforderungen (Requirements), die die Ausführung verhindern könnten.
Testing
Abschnitt betitelt „Testing“Gateway-Logs
Abschnitt betitelt „Gateway-Logs“Du kannst die Gateway-Logs in Echtzeit überwachen, um die Hook-Ausführung zu verfolgen:
# macOS./scripts/clawlog.sh -f
# Other platformstail -f ~/.openclaw/gateway.logHooks direkt testen
Abschnitt betitelt „Hooks direkt testen“Am besten testest du deine Handler isoliert. So stellst du sicher, dass die Logik stimmt, ohne das gesamte System zu starten:
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);
// Assert side effects});Architektur
Abschnitt betitelt „Architektur“Hier erfährst du, wie die Hooks unter der Haube funktionieren. Das System ist modular aufgebaut, damit die Entdeckung und Ausführung deiner Erweiterungen stabil funktioniert.
Kernkomponenten
Abschnitt betitelt „Kernkomponenten“src/hooks/types.ts: Typdefinitionensrc/hooks/workspace.ts: Verzeichnisse scannen und ladensrc/hooks/frontmatter.ts: HOOK.md Metadaten-Parsingsrc/hooks/config.ts: Berechtigungsprüfungsrc/hooks/hooks-status.ts: Statusberichtesrc/hooks/loader.ts: Dynamischer Module-Loadersrc/cli/hooks-cli.ts: CLI-Befehlesrc/gateway/server-startup.ts: Lädt Hooks beim Gateway-Startsrc/auto-reply/reply/commands-core.ts: Löst Command-Events aus
Discovery Flow
Abschnitt betitelt „Discovery Flow“Gateway startup ↓Scan directories (bundled → plugin → managed + extra dirs → workspace) ↓Parse HOOK.md files ↓Sort by override precedence (bundled < plugin < managed < workspace) ↓Check eligibility (bins, env, config, os) ↓Load handlers from eligible hooks ↓Register handlers for eventsEvent Flow
Abschnitt betitelt „Event Flow“User sends /new ↓Command validation ↓Create hook event ↓Trigger hook (all registered handlers) ↓Command processing continues ↓Session resetFehlerbehebung
Abschnitt betitelt „Fehlerbehebung“Wenn ein Hook nicht so funktioniert, wie du es erwartest, helfen dir diese Schritte dabei, das Problem schnell zu finden.
Hook wird nicht gefunden
Abschnitt betitelt „Hook wird nicht gefunden“-
Prüf die Verzeichnisstruktur:
Terminal-Fenster ls -la ~/.openclaw/hooks/my-hook/# Should show: HOOK.md, handler.ts -
Verifizier das HOOK.md Format:
Terminal-Fenster cat ~/.openclaw/hooks/my-hook/HOOK.md# Should have YAML frontmatter with name and metadata -
Liste alle gefundenen Hooks auf:
Terminal-Fenster openclaw hooks list
Hook ist nicht berechtigt
Abschnitt betitelt „Hook ist nicht berechtigt“Prüf die Anforderungen:
openclaw hooks info my-hookAchte auf fehlende:
- Binaries (prüf den PATH)
- Umgebungsvariablen
- Config-Werte
- OS-Kompatibilität
Hook wird nicht ausgeführt
Abschnitt betitelt „Hook wird nicht ausgeführt“-
Verifizier, dass der Hook aktiviert ist:
Terminal-Fenster openclaw hooks list# Should show ✓ next to enabled hooks -
Starte deinen Gateway-Prozess neu, damit die Hooks neu geladen werden.
-
Prüf die Gateway-Logs auf Fehler:
Terminal-Fenster ./scripts/clawlog.sh | grep hook
Handler-Fehler
Abschnitt betitelt „Handler-Fehler“Prüf auf TypeScript- oder Import-Fehler:
# Test import directlynode -e "import('./path/to/handler.ts').then(console.log)"Migrationsleitfaden
Abschnitt betitelt „Migrationsleitfaden“Von der Legacy-Konfiguration zur Discovery
Abschnitt betitelt „Von der Legacy-Konfiguration zur Discovery“Vorher:
{ "hooks": { "internal": { "enabled": true, "handlers": [ { "event": "command:new", "module": "./hooks/handlers/my-handler.ts" } ] } }}Nachher:
-
Erstelle das Hook-Verzeichnis:
Terminal-Fenster mkdir -p ~/.openclaw/hooks/my-hookmv ./hooks/handlers/my-handler.ts ~/.openclaw/hooks/my-hook/handler.ts -
Erstelle die HOOK.md:
---name: my-hookdescription: "My custom hook"metadata: { "openclaw": { "emoji": "🎯", "events": ["command:new"] } }---# My HookDoes something useful. -
Aktualisiere die Konfiguration:
{"hooks": {"internal": {"enabled": true,"entries": {"my-hook": { "enabled": true }}}}} -
Überprüfe die Hooks und starte deinen Gateway-Prozess neu:
Terminal-Fenster openclaw hooks list# Should show: 🎯 my-hook ✓
Vorteile der Migration:
- Automatische Discovery
- CLI-Management
- Prüfung der Voraussetzungen
- Bessere Dokumentation
- Konsistente Struktur
Siehe auch
Abschnitt betitelt „Siehe auch“OpenClaw Expert
Noch festgefahren?
Wenn diese Seite nicht hilft, frage OpenClaw Expert nach Schritt-fuer-Schritt-Loesungen.