#17667: feat: tool-hooks extension — run shell commands on tool calls
stale
size: M
Cluster:
Plugin Hook Enhancements
## Summary
Adds a new `tool-hooks` extension that lets users run shell commands when specific agent tools are called. Hooks fire on `after_tool_call` and/or `before_tool_call` events, receiving full context via environment variables.
## Motivation
There is currently no way for users to trigger side effects when tools are called — for example:
- **Knowledge graph tracking**: automatically update a memory graph when `memory_search` is used, strengthening connections through actual recall
- **Audit logging**: record tool usage patterns to a file or external service
- **Webhooks**: trigger external systems when specific tools fire
- **Analytics**: track which tools are used most, by which agents, in which sessions
The hook system (`after_tool_call` / `before_tool_call`) already exists in the plugin infrastructure, but there is no built-in way to use it without writing a full TypeScript extension. This extension bridges that gap with simple config-driven shell commands.
## Configuration
```json
{
"plugins": {
"tool-hooks": {
"hooks": [
{
"tool": "memory_search",
"command": "node ~/workspace/memory/brain.js track-query \"$TOOL_PARAMS\"",
"background": true,
"onlyOnSuccess": true
}
]
}
}
}
```
## Features
- **Glob patterns** for tool matching (`"memory_*"`, `"*"`)
- **Environment variables**: `TOOL_NAME`, `TOOL_PARAMS`, `TOOL_RESULT`, `TOOL_DURATION_MS`, `TOOL_ERROR`, `AGENT_ID`, `SESSION_KEY`
- **Background execution** (fire-and-forget, default) or blocking
- **Timeout** protection (default 10s)
- **Success-only** filtering (`onlyOnSuccess`)
- Zero core changes — uses existing plugin hook system
## Files
- `extensions/tool-hooks/index.ts` — plugin implementation
- `extensions/tool-hooks/openclaw.plugin.json` — plugin manifest
- `extensions/tool-hooks/package.json` — package metadata
- `extensions/tool-hooks/README.md` — docs and examples
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Adds a config-driven shell hook system for tool call events (`after_tool_call` / `before_tool_call`). Hook commands run via `sh -c` with tool context exposed as environment variables. Addresses previous review feedback: now correctly uses `api.pluginConfig` instead of `api.config`, and hooks are properly registered.
**Key issue found:**
- The `background` parameter is documented and accepted in config but doesn't actually affect execution — both background and non-background hooks fire-and-forget with `void`, making them functionally identical
**Previous thread concerns acknowledged but not addressed:**
- Shell execution bypasses OpenClaw's `validateHostEnv()` filtering (dangerous env vars like `LD_PRELOAD`, `NODE_OPTIONS` can be inherited from `process.env`)
- No exec-approvals flow (user config is the consent mechanism)
- README examples show `$TOOL_PARAMS` being interpolated in shell commands, which is safe via env vars but could be confusing
<h3>Confidence Score: 3/5</h3>
- Safe to merge with one critical logic bug that breaks documented functionality
- The PR correctly implements the plugin hook system and fixes previous review feedback (`api.pluginConfig` is now used correctly). However, the `background` parameter advertised in docs and config schema doesn't work — both code paths execute identically as fire-and-forget. This breaks the documented blocking vs non-blocking behavior. Security concerns about env var inheritance and shell execution bypass were raised in previous threads but appear to be design trade-offs for a config-driven extension (user explicitly opts in).
- Pay close attention to `extensions/tool-hooks/index.ts` — the background parameter logic needs to be implemented correctly
<sub>Last reviewed commit: 478db58</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#20580: feat(hooks): bridge after_tool_call to internal hook handler system
by CryptoKrad · 2026-02-19
82.9%
#10678: feat(hooks): wire after_tool_call hook into tool execution pipeline
by yassinebkr · 2026-02-06
81.6%
#16028: feat/before-tool-result
by ambushalgorithm · 2026-02-14
80.2%
#22068: Add tool:before/tool:after internal hook events
by yhindy · 2026-02-20
79.5%
#11071: Plugins: add tool_result_received hook for output interception
by ThomasLWang · 2026-02-07
78.1%
#14222: core: add needsApproval to before_tool_call; move AgentShield to ex...
by Eventedge · 2026-02-11
77.5%
#19422: fix: pass session context to plugin tool hooks in toToolDefinitions
by namabile · 2026-02-17
77.4%
#17273: feat: add security-guard extension — agentic safety guardrails
by miloudbelarebia · 2026-02-15
77.4%
#14544: feat: add before_context_send plugin hook
by Windelly · 2026-02-12
77.0%
#18860: feat(agents): expose tools and their schemas via new after_tools_re...
by lan17 · 2026-02-17
76.5%