Registering Hooks
Useapi.registerHook to register a hook handler:
Available Hooks
Agent Lifecycle
before_model_resolve
Fired before resolving the model/provider for an agent run. Use this to override model selection based on the prompt.{ prompt: string }
Return: { modelOverride?: string, providerOverride?: string } or void
before_prompt_build
Fired before building the prompt for an agent run. Session messages are available at this point.{ prompt: string, messages: unknown[] }
Return: { systemPrompt?: string, prependContext?: string } or void
before_agent_start (legacy)
Fired before an agent run starts. Combines bothbefore_model_resolve and before_prompt_build phases.
{ prompt: string, messages?: unknown[] }
Return: { modelOverride?: string, providerOverride?: string, systemPrompt?: string, prependContext?: string } or void
llm_input
Fired before sending a prompt to the LLM. Use for logging, telemetry, or analytics.llm_output
Fired after receiving a response from the LLM.agent_end
Fired after an agent run completes (success or failure).Session Management
session_start
Fired when a new session starts.{ sessionId: string, resumedFrom?: string }
session_end
Fired when a session ends.{ sessionId: string, messageCount: number, durationMs?: number }
before_compaction
Fired before session compaction (history summarization). Useful for archiving session history.after_compaction
Fired after session compaction completes.{ messageCount: number, tokenCount?: number, compactedCount: number, sessionFile?: string }
before_reset
Fired when a session is reset (/new, /reset commands).
{ sessionFile?: string, messages?: unknown[], reason?: string }
Message Flow
message_received
Fired when a message is received from a channel.{ from: string, content: string, timestamp?: number, metadata?: Record<string, unknown> }
Context: { channelId: string, accountId?: string, conversationId?: string }
message_sending
Fired before sending a message to a channel. Can modify or cancel the message.{ to: string, content: string, metadata?: Record<string, unknown> }
Return: { content?: string, cancel?: boolean } or void
Context: { channelId: string, accountId?: string, conversationId?: string }
message_sent
Fired after a message is sent to a channel.{ to: string, content: string, success: boolean, error?: string }
Context: { channelId: string, accountId?: string, conversationId?: string }
Tool Execution
before_tool_call
Fired before a tool is called. Can modify parameters or block the call.{ toolName: string, params: Record<string, unknown> }
Return: { params?: Record<string, unknown>, block?: boolean, blockReason?: string } or void
Context: { agentId?: string, sessionKey?: string, toolName: string }
after_tool_call
Fired after a tool completes.{ toolName: string, params: Record<string, unknown>, result?: unknown, error?: string, durationMs?: number }
Context: { agentId?: string, sessionKey?: string, toolName: string }
tool_result_persist
Fired before writing a tool result to the session transcript. Can modify or drop the message.{ toolName?: string, toolCallId?: string, message: AgentMessage, isSynthetic?: boolean }
Return: { message?: AgentMessage } or void
before_message_write
Fired before writing any message to the session transcript. Can block the write.{ message: AgentMessage, sessionKey?: string, agentId?: string }
Return: { block?: boolean, message?: AgentMessage } or void
Gateway Lifecycle
gateway_start
Fired when the gateway starts.{ port: number }
Context: { port?: number }
gateway_stop
Fired when the gateway stops.{ reason?: string }
Context: { port?: number }
Hook Files (Advanced)
OpenClaw also supports hook files with frontmatter metadata. These are typically used for bundled hooks insrc/hooks/bundled/.
Hook directory structure:
HOOK.md:
handler.ts:
src/hooks/plugin-hooks.ts for details.

