Files
ClawSkills/openclaw-plugin-dev/docs/hooks.md
zhi 5a8f490cc2 feat: add openclaw-plugin-dev skill
Plugin development reference and workflows based on real development
experience (Dirigent, ContractorAgent, PrismFacet).

Docs: structure, entry-point, hooks, tools, state, config, debugging
Workflows: create-plugin, add-hook

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 17:25:07 +00:00

2.1 KiB

Hook Registration

Available Hooks

Hook Purpose Dedup Method
before_model_resolve Override model/provider before LLM call WeakSet on event
before_prompt_build Inject into system prompt WeakSet on event
before_agent_start Legacy prompt injection WeakSet on event
agent_end Post-conversation actions Set on runId
message_received React to inbound messages
llm_input / llm_output Observe LLM traffic
before_tool_call / after_tool_call Observe tool execution
gateway_start / gateway_stop Gateway lifecycle globalThis flag

Dedup Patterns

WeakSet (for event-object hooks)

const _G = globalThis as Record<string, unknown>;
const DEDUP_KEY = "_myPluginHookDedup";
if (!(_G[DEDUP_KEY] instanceof WeakSet)) _G[DEDUP_KEY] = new WeakSet<object>();
const dedup = _G[DEDUP_KEY] as WeakSet<object>;

api.on("before_model_resolve", async (event, ctx) => {
  if (dedup.has(event as object)) return;
  dedup.add(event as object);
  // ... handler logic
});

Set with runId (for agent_end)

const DEDUP_KEY = "_myPluginAgentEndDedup";
if (!(_G[DEDUP_KEY] instanceof Set)) _G[DEDUP_KEY] = new Set<string>();
const dedup = _G[DEDUP_KEY] as Set<string>;

api.on("agent_end", async (event, ctx) => {
  const runId = (event as any).runId as string;
  if (runId) {
    if (dedup.has(runId)) return;
    dedup.add(runId);
    if (dedup.size > 500) dedup.delete(dedup.values().next().value!);
  }
  // ... handler logic
});

Prompt Injection Hooks

before_prompt_build and before_agent_start can return prompt mutation fields:

Field Caching Use for
prependSystemContext Cached Static role/identity prompts
appendSystemContext Cached Static supplementary guidance
prependContext Not cached Per-turn dynamic context
systemPrompt Full system prompt replacement (rarely used)

Requires plugins.entries.<id>.hooks.allowPromptInjection: true in openclaw.json.