#Tool hooks

1 messages · Page 1 of 1 (latest)

swift turtle
#

Are there (or are there plans for) before_tool_call/after_tool_call hooks that fire for any tool invocation (web_fetch, browser, exec, etc.)? If not, is this on the roadmap?

mortal schoonerBOT
#

To help others find answers, you can mark your question as solved via Right click solution message -> Apps -> âś… Mark Solution

oblique treeBOT
crude domeBOT
# swift turtle Are there (or are there plans for) `before_tool_call`/`after_tool_call` hooks th...

I checked the current docs/source: yes, there are plugin-level before_tool_call and after_tool_call hooks now.

Important distinction: they’re Plugin SDK hooks, not the simpler HOOK.md internal Gateway hooks. The internal hook docs list command/session/message/bootstrap-style events; tool-call interception lives in plugin hooks.

What they can do today:

  • before_tool_call can inspect/mutate params, block a call, or require approval.
  • after_tool_call observes the result/error/duration after execution.
  • The docs describe these as intercepting tool params/results, and the source has wiring for normal embedded tool execution, client tools, MCP bridge, and Codex dynamic tool runs. So for OpenClaw agent tools like exec, browser, web_fetch, etc., this is intended to be the universal tool middleware surface.

Docs:
https://docs.openclaw.ai/concepts/agent-loop
https://docs.openclaw.ai/automation/hooks
https://docs.openclaw.ai/plugins/building-plugins

I don’t see a separate “roadmap” item because the surface already exists. If you hit a path where a specific tool invocation does not fire those hooks, that sounds like a bug worth filing with a minimal repro: https://github.com/openclaw/openclaw/issues

swift turtle
#

That's very helpful. Thank you.

A few follow-up questions:

  1. 1. What operations are safe to perform synchronously (or asynchronously) in before_tool_call before the tool executes? Can the hook perform arbitrary async work (e.g., delays, rate-limit checks, condition queries, API calls, queuing decisions) without risking the agent loop's responsiveness or other concurrent sessions? Are there any constraints on how long the hook can run before the tool fires?

  2. What's the hook event shape? — Specifically, does before_tool_call receive the tool name (e.g. "web_fetch", "browser") and its params?

  3. Multiple plugin ordering — If two plugins both register before_tool_call, what determines execution order? Alphabetical? Registration order? Something else?

  4. Can the hook distinguish tool type? — There's a difference between an agent-internal tool call vs. an MCP tool call vs. a Codex dynamic tool. Does Openclaw provide a source or category field to differentiate them?

crude domeBOT
# swift turtle That's very helpful. Thank you. A few follow-up questions: 1. **1. What operat...

I checked the hook types and runner code. Short version:

  1. before_tool_call can be async, but it is on the critical path. OpenClaw awaits it before the tool executes. There does not appear to be a generic built-in timeout for the hook handler itself, so a slow handler delays that tool call/agent run until it resolves or rejects.

Practical guidance: bounded async checks are fine: policy lookup, rate-limit check, small DB/cache query, short HTTP call with your own timeout. Avoid unbounded waits, long queues, heavy CPU, or blocking sync work. True async I/O should not freeze unrelated sessions by itself, but CPU-bound sync work blocks the Node event loop, and shared plugin locks/queues can still create cross-session backpressure. If the handler throws, before_tool_call is configured fail-closed, so the tool call is blocked.

  1. Event shape includes the tool name and params. Current type is basically:
event: {
  toolName: string;
  params: Record<string, unknown>;
  runId?: string;
  toolCallId?: string;
}
ctx: {
  agentId?: string;
crude domeBOT
# swift turtle That's very helpful. Thank you. A few follow-up questions: 1. **1. What operat...
  sessionKey?: string;
  sessionId?: string;
  runId?: string;
  toolName: string;
  toolCallId?: string;
}

Return shape can include params to mutate args, block/blockReason, or requireApproval.

  1. Multiple plugins are ordered by hook priority, highest first: api.on("before_tool_call", handler, { priority: 100 }). Default is effectively 0. Equal priority currently preserves registry/insertion order via stable sort, but I would not build a plugin contract around ties; set explicit priorities if ordering matters.

For before_tool_call, handlers run sequentially and results are merged. block: true is terminal and skips lower-priority handlers. Param mutations use the last defined params as the sequence proceeds. First requireApproval wins.

  1. I do not see a first-class source/category field in the hook event or context. You get identity/correlation fields (toolName, toolCallId, runId, session/agent ids), but not “agent-internal vs MCP vs Codex dynamic” as a typed discriminator. Some paths may have recognizable tool names/call ids, but that is not the same as a stable API. If you need that distinction, I’d file it as an SDK enhancement request: https://github.com/openclaw/openclaw/issues

Relevant docs:

swift turtle
#

Your replies are so helpful! Just as an aside, is there a description anywhere of your architecture and how you/ve been trained?

crude domeBOT
# swift turtle Your replies are so helpful! Just as an aside, is there a description anywhere o...

Glad it helped.

For OpenClaw architecture, the best public starting point is the agent loop doc: https://docs.openclaw.ai/concepts/agent-loop

At a high level, I’m not a separate custom-trained bot. I’m an OpenClaw agent connected to Discord: the gateway receives the message, builds context from configured workspace/session files, routes the turn to a configured model provider, and gives the model tools like docs/source search, message sending, web fetch, etc. The useful part is less “Krill was trained specially” and more “Krill has local instructions, memory/context files, and tool access, then verifies against the current OpenClaw checkout before answering.”

Training-wise: the underlying model is trained by its provider, not by this Discord server. I don’t learn from this thread by gradient updates, and I shouldn’t claim details about the provider’s training pipeline unless they publish them. OpenClaw can persist explicit memory/context depending on configuration, but that’s runtime context, not model retraining.

Related docs:
https://docs.openclaw.ai/concepts/agent
https://docs.openclaw.ai/concepts/models
https://docs.openclaw.ai/gateway/configuration

swift turtle
#

Appreciate the feedback about how you work. I wish you could be more specific about your setup, as it would be nice to build something similar so I don't have to keep coming back to bother you, but that's fine. 🙂

Your previous reply answering the four follow-up questions I had was exactly the detail I needed. The event shape, async behavior, priority system, and merge semantics all make sense for what I'm planning. I don't have further questions at this point.

Is there a way I can mark two responses as answering my original question? Or am I limited to just one?

crude domeBOT
# swift turtle Appreciate the feedback about how you work. I wish you could be more specific ab...

I think Answer Overflow is effectively optimized around one solution message per thread. If it lets you mark more than one in the app menu, great, but I would assume “pick the most complete one” is the safe path.

For this thread, I’d mark the four-question follow-up answer since it contains the event shape/async/priority details, and the original answer is still right above it for context. Thanks for keeping the thread tidy for future searchers 🙂