openclaw/docs/automation/hooks.md

10 KiB

summary read_when title
Hooks: event-driven automation for commands and lifecycle events
You want event-driven automation for /new, /reset, /stop, and agent lifecycle events
You want to build, install, or debug hooks
Hooks

Hooks

Hooks are small scripts that run when something happens inside the Gateway. They are automatically discovered from directories and can be inspected with openclaw hooks.

There are two kinds of hooks in OpenClaw:

  • Internal hooks (this page): run inside the Gateway when agent events fire, like /new, /reset, /stop, or lifecycle events.
  • Webhooks: external HTTP endpoints that let other systems trigger work in OpenClaw. See Webhooks.

Hooks can also be bundled inside plugins. openclaw hooks list shows both standalone hooks and plugin-managed hooks.

Quick start

# List available hooks
openclaw hooks list

# Enable a hook
openclaw hooks enable session-memory

# Check hook status
openclaw hooks check

# Get detailed information
openclaw hooks info session-memory

Event types

Event When it fires
command:new /new command issued
command:reset /reset command issued
command:stop /stop command issued
command Any command event (general listener)
session:compact:before Before compaction summarizes history
session:compact:after After compaction completes
session:patch When session properties are modified
agent:bootstrap Before workspace bootstrap files are injected
gateway:startup After channels start and hooks are loaded
message:received Inbound message from any channel
message:transcribed After audio transcription completes
message:preprocessed After all media and link understanding completes
message:sent Outbound message delivered

Writing hooks

Hook structure

Each hook is a directory containing two files:

my-hook/
├── HOOK.md          # Metadata + documentation
└── handler.ts       # Handler implementation

HOOK.md format

---
name: my-hook
description: "Short description of what this hook does"
metadata:
  { "openclaw": { "emoji": "🔗", "events": ["command:new"], "requires": { "bins": ["node"] } } }
---

# My Hook

Detailed documentation goes here.

Metadata fields (metadata.openclaw):

Field Description
emoji Display emoji for CLI
events Array of events to listen for
export Named export to use (defaults to "default")
os Required platforms (e.g., ["darwin", "linux"])
requires Required bins, anyBins, env, or config paths
always Bypass eligibility checks (boolean)
install Installation methods

Handler implementation

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

  console.log(`[my-hook] New command triggered`);
  // Your logic here

  // Optionally send message to user
  event.messages.push("Hook executed!");
};

export default handler;

Each event includes: type, action, sessionKey, timestamp, messages (push to send to user), and context (event-specific data).

Event context highlights

Command events (command:new, command:reset): context.sessionEntry, context.previousSessionEntry, context.commandSource, context.workspaceDir, context.cfg.

Message events (message:received): context.from, context.content, context.channelId, context.metadata (provider-specific data including senderId, senderName, guildId).

Message events (message:sent): context.to, context.content, context.success, context.channelId.

Message events (message:transcribed): context.transcript, context.from, context.channelId, context.mediaPath.

Message events (message:preprocessed): context.bodyForAgent (final enriched body), context.from, context.channelId.

Bootstrap events (agent:bootstrap): context.bootstrapFiles (mutable array), context.agentId.

Session patch events (session:patch): context.sessionEntry, context.patch (only changed fields), context.cfg. Only privileged clients can trigger patch events.

Compaction events: session:compact:before includes messageCount, tokenCount. session:compact:after adds compactedCount, summaryLength, tokensBefore, tokensAfter.

Hook discovery

Hooks are discovered from these directories, in order of increasing override precedence:

  1. Bundled hooks: shipped with OpenClaw
  2. Plugin hooks: hooks bundled inside installed plugins
  3. Managed hooks: ~/.openclaw/hooks/ (user-installed, shared across workspaces). Extra directories from hooks.internal.load.extraDirs share this precedence.
  4. Workspace hooks: <workspace>/hooks/ (per-agent, disabled by default until explicitly enabled)

Workspace hooks can add new hook names but cannot override bundled, managed, or plugin-provided hooks with the same name.

Hook packs

Hook packs are npm packages that export hooks via openclaw.hooks in package.json. Install with:

openclaw plugins install <path-or-spec>

Npm specs are registry-only (package name + optional exact version or dist-tag). Git/URL/file specs and semver ranges are rejected.

Bundled hooks

Hook Events What it does
session-memory command:new, command:reset Saves session context to <workspace>/memory/
bootstrap-extra-files agent:bootstrap Injects additional bootstrap files from glob patterns
command-logger command Logs all commands to ~/.openclaw/logs/commands.log
boot-md gateway:startup Runs BOOT.md when the gateway starts

Enable any bundled hook:

openclaw hooks enable <hook-name>

session-memory details

Extracts the last 15 user/assistant messages, generates a descriptive filename slug via LLM, and saves to <workspace>/memory/YYYY-MM-DD-slug.md. Requires workspace.dir to be configured.

bootstrap-extra-files config

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

Paths resolve relative to workspace. Only recognized bootstrap basenames are loaded (AGENTS.md, SOUL.md, TOOLS.md, IDENTITY.md, USER.md, HEARTBEAT.md, BOOTSTRAP.md, MEMORY.md).

Plugin hooks

Plugins can register hooks through the Plugin SDK for deeper integration: intercepting tool calls, modifying prompts, controlling message flow, and more. The Plugin SDK exposes 28 hooks covering model resolution, agent lifecycle, message flow, tool execution, subagent coordination, and gateway lifecycle.

For the complete plugin hook reference including before_tool_call, before_agent_reply, before_install, and all other plugin hooks, see Plugin Architecture.

Configuration

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

Per-hook environment variables:

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

Extra hook directories:

{
  "hooks": {
    "internal": {
      "load": {
        "extraDirs": ["/path/to/more/hooks"]
      }
    }
  }
}
The legacy `hooks.internal.handlers` array config format is still supported for backwards compatibility, but new hooks should use the discovery-based system.

CLI reference

# List all hooks (add --eligible, --verbose, or --json)
openclaw hooks list

# Show detailed info about a hook
openclaw hooks info <hook-name>

# Show eligibility summary
openclaw hooks check

# Enable/disable
openclaw hooks enable <hook-name>
openclaw hooks disable <hook-name>

Best practices

  • Keep handlers fast. Hooks run during command processing. Fire-and-forget heavy work with void processInBackground(event).
  • Handle errors gracefully. Wrap risky operations in try/catch; do not throw so other handlers can run.
  • Filter events early. Return immediately if the event type/action is not relevant.
  • Use specific event keys. Prefer "events": ["command:new"] over "events": ["command"] to reduce overhead.

Troubleshooting

Hook not discovered

# Verify directory structure
ls -la ~/.openclaw/hooks/my-hook/
# Should show: HOOK.md, handler.ts

# List all discovered hooks
openclaw hooks list

Hook not eligible

openclaw hooks info my-hook

Check for missing binaries (PATH), environment variables, config values, or OS compatibility.

Hook not executing

  1. Verify the hook is enabled: openclaw hooks list
  2. Restart your gateway process so hooks reload.
  3. Check gateway logs: ./scripts/clawlog.sh | grep hook