Events and lifecycle
See Plugin hooks for examples, common hook names, and guard
semantics.
Hook decision semantics
before_install is a plugin-runtime lifecycle hook, not the operator install
policy surface. Use security.installPolicy when an allow/warn/block decision must
cover CLI and Gateway-backed install or update paths.
before_tool_call: returning{ block: true }is terminal. Once any handler sets it, lower-priority handlers are skipped.before_tool_call: returning{ block: false }is treated as no decision (same as omittingblock), not as an override.before_install: returning{ block: true }is terminal. Once any handler sets it, lower-priority handlers are skipped.before_install: returning{ block: false }is treated as no decision (same as omittingblock), not as an override.reply_dispatch: returning{ handled: true, ... }is terminal. Once any handler claims dispatch, lower-priority handlers and the default model dispatch path are skipped.message_sending: returning{ cancel: true }is terminal. Once any handler sets it, lower-priority handlers are skipped.message_sending: returning{ cancel: false }is treated as no decision (same as omittingcancel), not as an override.message_received: use the typedthreadIdfield when you need inbound thread/topic routing. Keepmetadatafor channel-specific extras.message_sending: use typedreplyToId/threadIdrouting fields before falling back to channel-specificmetadata.gateway_start: usectx.config,ctx.workspaceDir, andctx.getCron?.()for gateway-owned startup state instead of relying on internalgateway:startuphooks. Cron may still be loading at this point.cron_reconciled: rebuild a full external cron projection after startup or scheduler reload. It includesreasonand the effectiveenabledstate, includingenabled: false, whilectx.getCron?.()returns the exact reconciled scheduler. Passctx.abortSignalinto durable projection work; it aborts when that scheduler snapshot is superseded or the Gateway closes.cron_changed: observe gateway-owned cron lifecycle changes.scheduledandremovedevents are post-commit reconciliation hints, not an ordered delta log. A scheduled event’sevent.nextRunAtMsis absent when the job has no next wake; a removed event still carries the deleted job snapshot.
cron_changed events,
then reread the full durable view from the scheduler last captured by
cron_reconciled. Do not adopt the scheduler from a cron_changed context: a
detached hint from an older scheduler can overlap a later reload.
Use cron_reconciled as the full-snapshot trigger for durable state loaded at
Gateway startup or scheduler replacement. It is not replayed for a plugin-only
hot reload. Observation handlers run in parallel, and fire-and-forget
dispatches can overlap, so consumers must not depend on event completion order.
Keep OpenClaw as the source of truth for due checks and execution.
For a single-flight adapter with durable replacement, retry/backoff, and clean
shutdown, see Safe external cron projection.