openclaw-event-server-plugin 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +473 -0
- package/config.example.json +203 -0
- package/dist/broadcast/index.d.ts +3 -0
- package/dist/broadcast/index.d.ts.map +1 -0
- package/dist/broadcast/index.js +19 -0
- package/dist/broadcast/index.js.map +1 -0
- package/dist/broadcast/queue.d.ts +63 -0
- package/dist/broadcast/queue.d.ts.map +1 -0
- package/dist/broadcast/queue.js +259 -0
- package/dist/broadcast/queue.js.map +1 -0
- package/dist/broadcast/webhook.d.ts +30 -0
- package/dist/broadcast/webhook.d.ts.map +1 -0
- package/dist/broadcast/webhook.js +184 -0
- package/dist/broadcast/webhook.js.map +1 -0
- package/dist/broadcast/websocketServer.d.ts +90 -0
- package/dist/broadcast/websocketServer.d.ts.map +1 -0
- package/dist/broadcast/websocketServer.js +403 -0
- package/dist/broadcast/websocketServer.js.map +1 -0
- package/dist/config/config-types.d.ts +280 -0
- package/dist/config/config-types.d.ts.map +1 -0
- package/dist/config/config-types.js +3 -0
- package/dist/config/config-types.js.map +1 -0
- package/dist/config/default-config.d.ts +3 -0
- package/dist/config/default-config.d.ts.map +1 -0
- package/dist/config/default-config.js +136 -0
- package/dist/config/default-config.js.map +1 -0
- package/dist/config/env.d.ts +6 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +160 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/event-types.d.ts +5 -0
- package/dist/config/event-types.d.ts.map +1 -0
- package/dist/config/event-types.js +54 -0
- package/dist/config/event-types.js.map +1 -0
- package/dist/config/handler.d.ts +9 -0
- package/dist/config/handler.d.ts.map +1 -0
- package/dist/config/handler.js +17 -0
- package/dist/config/handler.js.map +1 -0
- package/dist/config/helpers.d.ts +5 -0
- package/dist/config/helpers.d.ts.map +1 -0
- package/dist/config/helpers.js +40 -0
- package/dist/config/helpers.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +19 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/merge.d.ts +6 -0
- package/dist/config/merge.d.ts.map +1 -0
- package/dist/config/merge.js +108 -0
- package/dist/config/merge.js.map +1 -0
- package/dist/config/schema-hook-bridge.d.ts +594 -0
- package/dist/config/schema-hook-bridge.d.ts.map +1 -0
- package/dist/config/schema-hook-bridge.js +423 -0
- package/dist/config/schema-hook-bridge.js.map +1 -0
- package/dist/config/schema.d.ts +915 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +323 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/types.d.ts +9 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +28 -0
- package/dist/config/types.js.map +1 -0
- package/dist/config/validate-hook-bridge.d.ts +3 -0
- package/dist/config/validate-hook-bridge.d.ts.map +1 -0
- package/dist/config/validate-hook-bridge.js +246 -0
- package/dist/config/validate-hook-bridge.js.map +1 -0
- package/dist/config/validate.d.ts +17 -0
- package/dist/config/validate.d.ts.map +1 -0
- package/dist/config/validate.js +194 -0
- package/dist/config/validate.js.map +1 -0
- package/dist/events/index.d.ts +4 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +20 -0
- package/dist/events/index.js.map +1 -0
- package/dist/events/redaction.d.ts +5 -0
- package/dist/events/redaction.d.ts.map +1 -0
- package/dist/events/redaction.js +46 -0
- package/dist/events/redaction.js.map +1 -0
- package/dist/events/signing.d.ts +8 -0
- package/dist/events/signing.d.ts.map +1 -0
- package/dist/events/signing.js +35 -0
- package/dist/events/signing.js.map +1 -0
- package/dist/events/types.d.ts +125 -0
- package/dist/events/types.d.ts.map +1 -0
- package/dist/events/types.js +9 -0
- package/dist/events/types.js.map +1 -0
- package/dist/hooks/agent-hooks.d.ts +59 -0
- package/dist/hooks/agent-hooks.d.ts.map +1 -0
- package/dist/hooks/agent-hooks.js +116 -0
- package/dist/hooks/agent-hooks.js.map +1 -0
- package/dist/hooks/command-hooks.d.ts +13 -0
- package/dist/hooks/command-hooks.d.ts.map +1 -0
- package/dist/hooks/command-hooks.js +26 -0
- package/dist/hooks/command-hooks.js.map +1 -0
- package/dist/hooks/event-factory.d.ts +21 -0
- package/dist/hooks/event-factory.d.ts.map +1 -0
- package/dist/hooks/event-factory.js +31 -0
- package/dist/hooks/event-factory.js.map +1 -0
- package/dist/hooks/gateway-hooks.d.ts +14 -0
- package/dist/hooks/gateway-hooks.d.ts.map +1 -0
- package/dist/hooks/gateway-hooks.js +43 -0
- package/dist/hooks/gateway-hooks.js.map +1 -0
- package/dist/hooks/index.d.ts +10 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +26 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/message-hooks.d.ts +33 -0
- package/dist/hooks/message-hooks.d.ts.map +1 -0
- package/dist/hooks/message-hooks.js +208 -0
- package/dist/hooks/message-hooks.js.map +1 -0
- package/dist/hooks/session-hooks.d.ts +89 -0
- package/dist/hooks/session-hooks.d.ts.map +1 -0
- package/dist/hooks/session-hooks.js +253 -0
- package/dist/hooks/session-hooks.js.map +1 -0
- package/dist/hooks/status-reducer.d.ts +30 -0
- package/dist/hooks/status-reducer.d.ts.map +1 -0
- package/dist/hooks/status-reducer.js +157 -0
- package/dist/hooks/status-reducer.js.map +1 -0
- package/dist/hooks/subagent-hooks.d.ts +37 -0
- package/dist/hooks/subagent-hooks.d.ts.map +1 -0
- package/dist/hooks/subagent-hooks.js +79 -0
- package/dist/hooks/subagent-hooks.js.map +1 -0
- package/dist/hooks/subagent-tracker.d.ts +33 -0
- package/dist/hooks/subagent-tracker.d.ts.map +1 -0
- package/dist/hooks/subagent-tracker.js +73 -0
- package/dist/hooks/subagent-tracker.js.map +1 -0
- package/dist/hooks/tool-hooks.d.ts +132 -0
- package/dist/hooks/tool-hooks.d.ts.map +1 -0
- package/dist/hooks/tool-hooks.js +215 -0
- package/dist/hooks/tool-hooks.js.map +1 -0
- package/dist/index.d.ts +929 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +236 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/event-file-logger.d.ts +21 -0
- package/dist/logging/event-file-logger.d.ts.map +1 -0
- package/dist/logging/event-file-logger.js +167 -0
- package/dist/logging/event-file-logger.js.map +1 -0
- package/dist/logging/index.d.ts +3 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +19 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/runtime-logger.d.ts +12 -0
- package/dist/logging/runtime-logger.d.ts.map +1 -0
- package/dist/logging/runtime-logger.js +45 -0
- package/dist/logging/runtime-logger.js.map +1 -0
- package/dist/runtime/hook-bridge-actions.d.ts +9 -0
- package/dist/runtime/hook-bridge-actions.d.ts.map +1 -0
- package/dist/runtime/hook-bridge-actions.js +248 -0
- package/dist/runtime/hook-bridge-actions.js.map +1 -0
- package/dist/runtime/hook-bridge-dispatch-engine.d.ts +42 -0
- package/dist/runtime/hook-bridge-dispatch-engine.d.ts.map +1 -0
- package/dist/runtime/hook-bridge-dispatch-engine.js +233 -0
- package/dist/runtime/hook-bridge-dispatch-engine.js.map +1 -0
- package/dist/runtime/hook-bridge-tool-guard.d.ts +16 -0
- package/dist/runtime/hook-bridge-tool-guard.d.ts.map +1 -0
- package/dist/runtime/hook-bridge-tool-guard.js +236 -0
- package/dist/runtime/hook-bridge-tool-guard.js.map +1 -0
- package/dist/runtime/hook-bridge-utils.d.ts +11 -0
- package/dist/runtime/hook-bridge-utils.d.ts.map +1 -0
- package/dist/runtime/hook-bridge-utils.js +116 -0
- package/dist/runtime/hook-bridge-utils.js.map +1 -0
- package/dist/runtime/hook-bridge.d.ts +33 -0
- package/dist/runtime/hook-bridge.d.ts.map +1 -0
- package/dist/runtime/hook-bridge.js +359 -0
- package/dist/runtime/hook-bridge.js.map +1 -0
- package/dist/runtime/internal-handlers.d.ts +20 -0
- package/dist/runtime/internal-handlers.d.ts.map +1 -0
- package/dist/runtime/internal-handlers.js +225 -0
- package/dist/runtime/internal-handlers.js.map +1 -0
- package/dist/runtime/register-gateway-hooks.d.ts +4 -0
- package/dist/runtime/register-gateway-hooks.d.ts.map +1 -0
- package/dist/runtime/register-gateway-hooks.js +27 -0
- package/dist/runtime/register-gateway-hooks.js.map +1 -0
- package/dist/runtime/register-session-hooks.d.ts +4 -0
- package/dist/runtime/register-session-hooks.d.ts.map +1 -0
- package/dist/runtime/register-session-hooks.js +88 -0
- package/dist/runtime/register-session-hooks.js.map +1 -0
- package/dist/runtime/register-subagent-hooks.d.ts +4 -0
- package/dist/runtime/register-subagent-hooks.d.ts.map +1 -0
- package/dist/runtime/register-subagent-hooks.js +143 -0
- package/dist/runtime/register-subagent-hooks.js.map +1 -0
- package/dist/runtime/register-tool-hooks.d.ts +4 -0
- package/dist/runtime/register-tool-hooks.d.ts.map +1 -0
- package/dist/runtime/register-tool-hooks.js +348 -0
- package/dist/runtime/register-tool-hooks.js.map +1 -0
- package/dist/runtime/runtime-events.d.ts +14 -0
- package/dist/runtime/runtime-events.d.ts.map +1 -0
- package/dist/runtime/runtime-events.js +166 -0
- package/dist/runtime/runtime-events.js.map +1 -0
- package/dist/runtime/typed-hooks.d.ts +9 -0
- package/dist/runtime/typed-hooks.d.ts.map +1 -0
- package/dist/runtime/typed-hooks.js +14 -0
- package/dist/runtime/typed-hooks.js.map +1 -0
- package/dist/runtime/types.d.ts +91 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +3 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/runtime/utils.d.ts +47 -0
- package/dist/runtime/utils.d.ts.map +1 -0
- package/dist/runtime/utils.js +166 -0
- package/dist/runtime/utils.js.map +1 -0
- package/dist/tools/replay-tool-guard.d.ts +3 -0
- package/dist/tools/replay-tool-guard.d.ts.map +1 -0
- package/dist/tools/replay-tool-guard.js +96 -0
- package/dist/tools/replay-tool-guard.js.map +1 -0
- package/openclaw.plugin.json +847 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 OpenClaw Community
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
# OpenClaw Event Server Plugin
|
|
2
|
+
|
|
3
|
+
Most teams using OpenClaw hit the same wall: important agent activity is hard to operationalize because it lives in logs, scattered channels, or manual checks. This plugin solves that by turning agent behavior into clean, real-time events (WebSocket or webhook) that your automations can consume immediately, plus configurable Tool Guard controls to block risky tool calls and require human approval when needed. In practice, you install it, point events to your systems, and define guard rules.
|
|
4
|
+
|
|
5
|
+
Use cases:
|
|
6
|
+
- Send Slack alerts when tool calls fail or agents error.
|
|
7
|
+
- Feed `agent.status` and `agent.activity` into dashboards for live visibility.
|
|
8
|
+
- Trigger downstream jobs from session lifecycle events (`session.start`, `session.end`).
|
|
9
|
+
- Require human approval for risky tools (`web_search`, `web_fetch`, `browser`, `exec` with `sudo`).
|
|
10
|
+
- Write normalized events to long-term storage for audit, compliance, or analytics.
|
|
11
|
+
- Wake a sleeping parent agent when their sub agent stalls, finishes or times out
|
|
12
|
+
- Cost guardrails: monitor high-frequency tool loops and block when token/tool usage crosses per-session budgets.
|
|
13
|
+
- Knowledge capture: when a run succeeds after multiple failures, auto-log the successful tool sequence to docs/wiki.
|
|
14
|
+
- subsequent agent setup. Bot A finishes a writing a youtube script and goes idle, event server triggers an alert to Bot B to review script and make adjustments, OR if bot A fails or stalls, retries Bot A.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
User senarios:
|
|
18
|
+
- Live content studio control room: a creator runs multiple agents for research, scripting, clipping, and posting. Event Server becomes the “producer dashboard” that shows who is working, who is stuck, and when a draft is ready. Tool Guard adds a human checkpoint before anything publishes or sends outreach.
|
|
19
|
+
- Founder daily ops autopilot: a small business owner uses agents for inbox triage, lead follow-up, and report generation. Event streams turn this into a visible operations timeline, so they can see bottlenecks and response speed. Tool Guard keeps high-risk actions (sending, spending, exporting) human-approved.
|
|
20
|
+
- Streamer has an openclaw agent monitoring his chat and uses it to manage interactivity in his live stream, Event server is feeding status updates and if the agent dies, stalls or goes inactive, calls a script to spawn a new agent with little to no downtime.
|
|
21
|
+
- Creative memory engine: every finished run emits structured “what worked” events into a reusable idea bank. Over time, creators build a searchable playbook of winning hooks, formats, and campaign patterns.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
How does it actually work?
|
|
25
|
+
Openclaw Event Server Plugin is built around 3 things:
|
|
26
|
+
1. Event server; This simply finds all the various events throughout openclaw and presents them in an easy to consume format.
|
|
27
|
+
2. Hook Bridge; execute a script file or webhook when an event is captured
|
|
28
|
+
3. Tool Guard; Openclaw ships with exec approval by default, but it does not have anything for other tools, this plugin fills that gap and allows users to create approval workflows or block possibly dangerous tool calls
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
It emits:
|
|
33
|
+
- Raw internal hook events (`message:*`, `command:*`, `agent:*`, `gateway:startup`)
|
|
34
|
+
- Raw plugin hook events (`before_tool_call`, `after_tool_call`, `tool_result_persist`, session/subagent/gateway typed hooks)
|
|
35
|
+
- Synthetic events (`agent.activity`, `agent.status`, `agent.sub_agent_spawn`)
|
|
36
|
+
|
|
37
|
+
## Transport
|
|
38
|
+
|
|
39
|
+
- WebSocket broadcast server (default ports: `9011,9012,9013,9014,9015,9016`)
|
|
40
|
+
- HTTP webhooks with retry/queue support
|
|
41
|
+
|
|
42
|
+
## Event Model
|
|
43
|
+
|
|
44
|
+
All emitted events use one canonical envelope so consumers can parse every event type consistently.
|
|
45
|
+
|
|
46
|
+
All emitted events use a canonical envelope:
|
|
47
|
+
|
|
48
|
+
- `eventId`
|
|
49
|
+
- `schemaVersion`
|
|
50
|
+
- `timestamp`
|
|
51
|
+
- `type`
|
|
52
|
+
- `eventCategory`
|
|
53
|
+
- `eventName`
|
|
54
|
+
- `source`
|
|
55
|
+
- `agentId`, `sessionId`, `sessionKey`, `runId`, `toolCallId` (when available)
|
|
56
|
+
- `correlationId`
|
|
57
|
+
- `result`/`error` (when relevant)
|
|
58
|
+
- `data`
|
|
59
|
+
- `metadata`
|
|
60
|
+
|
|
61
|
+
### Supported event types
|
|
62
|
+
|
|
63
|
+
Synthetic event types are computed by this plugin and are not native upstream gateway events.
|
|
64
|
+
|
|
65
|
+
- Message: `message.received`, `message.transcribed`, `message.preprocessed`, `message.sent`
|
|
66
|
+
- Tool: `tool.called`, `tool.guard.matched`, `tool.guard.allowed`, `tool.guard.blocked`, `tool.completed`, `tool.error`, `tool.result_persist`
|
|
67
|
+
- Command: `command.new`, `command.reset`, `command.stop`
|
|
68
|
+
- Session: `session.start`, `session.end`
|
|
69
|
+
- Subagent: `subagent.spawning`, `subagent.spawned`, `subagent.ended`
|
|
70
|
+
- Subagent synthetic: `subagent.idle`
|
|
71
|
+
- Agent: `agent.bootstrap`, `agent.error`, `agent.session_start`, `agent.session_end`
|
|
72
|
+
- Gateway: `gateway.startup`, `gateway.start`, `gateway.stop`
|
|
73
|
+
- Synthetic: `agent.activity`, `agent.status`, `agent.sub_agent_spawn`
|
|
74
|
+
- Legacy aliases preserved for compatibility: `session.spawned`, `session.completed`, `session.error`
|
|
75
|
+
|
|
76
|
+
## Install
|
|
77
|
+
|
|
78
|
+
Choose one install path:
|
|
79
|
+
|
|
80
|
+
1. Install from npm (recommended for most users; no local build needed):
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
openclaw plugins install openclaw-event-server-plugin
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
2. Install from local source (for contributors/dev):
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npm install
|
|
90
|
+
npm run build
|
|
91
|
+
openclaw plugins install -l /absolute/path/to/openclaw_event_server_plugin
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
When installing from local source, `dist/` must be built before installation.
|
|
95
|
+
|
|
96
|
+
## Compatibility
|
|
97
|
+
|
|
98
|
+
Compatibility is pinned to a known OpenClaw hook surface and enforced by contract tests.
|
|
99
|
+
|
|
100
|
+
- Pinned hook-surface fixture: OpenClaw commit `7b5e64ef2e369258e2a4a613b7a62db3c21e5160`.
|
|
101
|
+
- Compatibility is enforced by fixture-driven contract tests (`tests/contract/openclaw-hook-surface.test.ts`).
|
|
102
|
+
- Additional versions can be documented by adding new hook-surface fixtures when validated.
|
|
103
|
+
|
|
104
|
+
## Configure
|
|
105
|
+
|
|
106
|
+
Use this as the primary runtime config for transport, retries, logging, security, filtering, redaction, status timing, and automation behavior.
|
|
107
|
+
|
|
108
|
+
In `~/.openclaw/openclaw.json`:
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"plugins": {
|
|
113
|
+
"entries": {
|
|
114
|
+
"event-server-plugin": {
|
|
115
|
+
"enabled": true,
|
|
116
|
+
"config": {
|
|
117
|
+
"webhooks": [
|
|
118
|
+
{
|
|
119
|
+
"url": "https://example.com/events",
|
|
120
|
+
"method": "POST"
|
|
121
|
+
}
|
|
122
|
+
],
|
|
123
|
+
"queue": {
|
|
124
|
+
"maxSize": 1000,
|
|
125
|
+
"flushIntervalMs": 5000,
|
|
126
|
+
"persistToDisk": false
|
|
127
|
+
},
|
|
128
|
+
"status": {
|
|
129
|
+
"workingWindowMs": 30000,
|
|
130
|
+
"sleepingWindowMs": 600000,
|
|
131
|
+
"tickIntervalMs": 5000,
|
|
132
|
+
"subagentIdleWindowMs": 300000
|
|
133
|
+
},
|
|
134
|
+
"redaction": {
|
|
135
|
+
"enabled": false,
|
|
136
|
+
"replacement": "[REDACTED]",
|
|
137
|
+
"fields": ["content", "params", "token", "authorization"]
|
|
138
|
+
},
|
|
139
|
+
"eventLog": {
|
|
140
|
+
"enabled": true,
|
|
141
|
+
"path": ".event-server/events.ndjson",
|
|
142
|
+
"maxFileSizeMb": 30,
|
|
143
|
+
"format": "full-json",
|
|
144
|
+
"minLevel": "debug",
|
|
145
|
+
"includeRuntimeLogs": true
|
|
146
|
+
},
|
|
147
|
+
"security": {
|
|
148
|
+
"ws": {
|
|
149
|
+
"bindAddress": "127.0.0.1",
|
|
150
|
+
"requireAuth": false,
|
|
151
|
+
"authToken": "",
|
|
152
|
+
"allowedOrigins": [],
|
|
153
|
+
"allowedIps": []
|
|
154
|
+
},
|
|
155
|
+
"hmac": {
|
|
156
|
+
"enabled": false,
|
|
157
|
+
"secretFilePath": ".event-plugin-hmac.secret",
|
|
158
|
+
"algorithm": "sha256"
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
"retry": {
|
|
162
|
+
"maxAttempts": 3,
|
|
163
|
+
"initialDelayMs": 1000,
|
|
164
|
+
"maxDelayMs": 30000,
|
|
165
|
+
"backoffMultiplier": 2
|
|
166
|
+
},
|
|
167
|
+
"filters": {
|
|
168
|
+
"includeTypes": [],
|
|
169
|
+
"excludeTypes": []
|
|
170
|
+
},
|
|
171
|
+
"hookBridge": {
|
|
172
|
+
"enabled": false,
|
|
173
|
+
"dryRun": false,
|
|
174
|
+
"allowedActionDirs": ["/absolute/path/to/hooks"],
|
|
175
|
+
"localScriptDefaults": {
|
|
176
|
+
"timeoutMs": 10000,
|
|
177
|
+
"maxPayloadBytes": 65536
|
|
178
|
+
},
|
|
179
|
+
"actions": {
|
|
180
|
+
"sudo-alert": {
|
|
181
|
+
"type": "webhook",
|
|
182
|
+
"url": "https://example.com/hook/sudo-alert",
|
|
183
|
+
"method": "POST"
|
|
184
|
+
},
|
|
185
|
+
"wake-parent": {
|
|
186
|
+
"type": "local_script",
|
|
187
|
+
"path": "/absolute/path/to/hooks/wake-parent.sh",
|
|
188
|
+
"args": []
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
"rules": [
|
|
192
|
+
{
|
|
193
|
+
"id": "notify-sudo",
|
|
194
|
+
"when": {
|
|
195
|
+
"eventType": "tool.called",
|
|
196
|
+
"toolName": "exec",
|
|
197
|
+
"contains": {
|
|
198
|
+
"data.params.command": "sudo"
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
"action": "sudo-alert",
|
|
202
|
+
"cooldownMs": 60000
|
|
203
|
+
}
|
|
204
|
+
],
|
|
205
|
+
"toolGuard": {
|
|
206
|
+
"enabled": false,
|
|
207
|
+
"dryRun": false,
|
|
208
|
+
"timeoutMs": 15000,
|
|
209
|
+
"onError": "allow",
|
|
210
|
+
"rules": [
|
|
211
|
+
{
|
|
212
|
+
"id": "approve-exec",
|
|
213
|
+
"when": {
|
|
214
|
+
"toolName": "exec"
|
|
215
|
+
},
|
|
216
|
+
"action": "wake-parent"
|
|
217
|
+
}
|
|
218
|
+
]
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Environment Variables
|
|
229
|
+
|
|
230
|
+
Use environment variables for quick overrides in containers, CI, and one-off debugging.
|
|
231
|
+
|
|
232
|
+
- `EVENT_PLUGIN_WEBHOOKS` comma-separated webhook URLs
|
|
233
|
+
- `EVENT_PLUGIN_AUTH_TOKEN` bearer token applied to env-defined webhooks
|
|
234
|
+
- `EVENT_PLUGIN_DEBUG` enable debug logging
|
|
235
|
+
- `EVENT_PLUGIN_INCLUDE_TYPES` comma-separated include filters
|
|
236
|
+
- `EVENT_PLUGIN_EXCLUDE_TYPES` comma-separated exclude filters
|
|
237
|
+
- `EVENT_PLUGIN_ENABLED` enable/disable plugin
|
|
238
|
+
- `EVENT_PLUGIN_WS_PORTS` comma-separated WS fallback order
|
|
239
|
+
- `EVENT_PLUGIN_DISABLE_WS` disable WS server
|
|
240
|
+
- `EVENT_PLUGIN_DISABLE_STATUS_TICKER` disable periodic synthetic status ticks (tests/CI)
|
|
241
|
+
- `EVENT_PLUGIN_TOOL_GUARD_TRACE` set `1`/`true` to emit verbose Tool Guard evaluation/action traces
|
|
242
|
+
- `EVENT_PLUGIN_STATUS_WORKING_WINDOW_MS` override working activity window
|
|
243
|
+
- `EVENT_PLUGIN_STATUS_SLEEPING_WINDOW_MS` override sleeping window
|
|
244
|
+
- `EVENT_PLUGIN_STATUS_TICK_INTERVAL_MS` override status ticker interval
|
|
245
|
+
- `EVENT_PLUGIN_STATUS_SUBAGENT_IDLE_WINDOW_MS` override `subagent.idle` threshold
|
|
246
|
+
- `EVENT_PLUGIN_REDACTION_ENABLED` enable payload redaction (default `false`)
|
|
247
|
+
- `EVENT_PLUGIN_REDACTION_REPLACEMENT` replacement text for redacted values
|
|
248
|
+
- `EVENT_PLUGIN_REDACTION_FIELDS` comma-separated key names to redact recursively
|
|
249
|
+
- `EVENT_PLUGIN_EVENT_LOG_ENABLED` enable/disable NDJSON file logging
|
|
250
|
+
- `EVENT_PLUGIN_EVENT_LOG_PATH` override log file path
|
|
251
|
+
- `EVENT_PLUGIN_EVENT_LOG_MAX_FILE_MB` max NDJSON log size in MB before truncation rollover (default `30`)
|
|
252
|
+
- `EVENT_PLUGIN_EVENT_LOG_FORMAT` `full-json` or `summary`
|
|
253
|
+
- `EVENT_PLUGIN_EVENT_LOG_MIN_LEVEL` `debug|info|warn|error` for runtime log records
|
|
254
|
+
- `EVENT_PLUGIN_EVENT_LOG_RUNTIME` include runtime log entries in file output
|
|
255
|
+
- `EVENT_PLUGIN_WS_BIND_ADDRESS` WS bind address (default `127.0.0.1`)
|
|
256
|
+
- `EVENT_PLUGIN_WS_REQUIRE_AUTH` require WS token auth
|
|
257
|
+
- `EVENT_PLUGIN_WS_AUTH_TOKEN` shared WS token
|
|
258
|
+
- `EVENT_PLUGIN_WS_ALLOWED_ORIGINS` comma-separated allowlist for WS `Origin` header
|
|
259
|
+
- `EVENT_PLUGIN_WS_ALLOWED_IPS` comma-separated WS client IP allowlist
|
|
260
|
+
- `EVENT_PLUGIN_HMAC_ENABLED` enable event HMAC signing
|
|
261
|
+
- `EVENT_PLUGIN_HMAC_SECRET` inline shared HMAC secret
|
|
262
|
+
- `EVENT_PLUGIN_HMAC_SECRET_FILE` file path for shared HMAC secret
|
|
263
|
+
- `EVENT_PLUGIN_HMAC_ALGORITHM` `sha256` or `sha512`
|
|
264
|
+
|
|
265
|
+
## Agent Status Semantics
|
|
266
|
+
|
|
267
|
+
`agent.status` is derived across all known sessions for each agent.
|
|
268
|
+
|
|
269
|
+
Example: if a parent agent starts a session and then appears quiet, status can still be `working` while a subagent is actively processing.
|
|
270
|
+
|
|
271
|
+
- `working`: activity in last `status.workingWindowMs` (default 30s)
|
|
272
|
+
- `idle`: no activity for > `status.workingWindowMs` and <= `status.sleepingWindowMs`
|
|
273
|
+
- `sleeping`: no activity for > `status.sleepingWindowMs` (default 10m)
|
|
274
|
+
- `offline`: marked offline (for example gateway stop/offline agent error classification)
|
|
275
|
+
- `error`: agent-level error latch
|
|
276
|
+
|
|
277
|
+
`tool.error` does not automatically force `agent.status=error`.
|
|
278
|
+
|
|
279
|
+
## Redaction
|
|
280
|
+
|
|
281
|
+
Payload redaction is opt-in and disabled by default. When enabled, the plugin redacts configured key names recursively across `data`, `metadata`, and nested payload objects before broadcasting to WebSocket and HTTP webhooks.
|
|
282
|
+
|
|
283
|
+
## Subagent Tracking
|
|
284
|
+
|
|
285
|
+
Subagent lifecycle and workload can be tracked independently:
|
|
286
|
+
|
|
287
|
+
- `subagent.spawned` carries parent + child identity fields.
|
|
288
|
+
- Tool events include `subagentKey`, `parentAgentId`, `parentSessionKey` when tool calls are associated with a child session.
|
|
289
|
+
- `subagent.idle` is emitted when a spawned child session has no observed activity for `status.subagentIdleWindowMs`.
|
|
290
|
+
- `agent.activity` for `subagent.idle` is emitted only when parent/child `agentId` is known; the plugin does not emit synthetic `"unknown"` agent identities.
|
|
291
|
+
|
|
292
|
+
This enables Mission Control tree views (parent agent with per-subagent status/tool lanes) while preserving top-level `agent.status` aggregation.
|
|
293
|
+
|
|
294
|
+
## Event Logging
|
|
295
|
+
|
|
296
|
+
`eventLog` writes NDJSON to disk from inside the plugin runtime.
|
|
297
|
+
|
|
298
|
+
- `format=full-json` (default): complete canonical event envelope in each line.
|
|
299
|
+
- `format=summary`: reduced envelope fields for lower volume.
|
|
300
|
+
- runtime records can be included and filtered by `minLevel`.
|
|
301
|
+
- `maxFileSizeMb=30` (default): logger truncates and continues once the file reaches the size cap.
|
|
302
|
+
|
|
303
|
+
Default path is `.event-server/events.ndjson`.
|
|
304
|
+
|
|
305
|
+
Relative `eventLog.path` values are resolved at runtime in this order:
|
|
306
|
+
- `OPENCLAW_STATE_DIR` (if set)
|
|
307
|
+
- directory containing `OPENCLAW_CONFIG_PATH` (if set)
|
|
308
|
+
- `~/.openclaw/`
|
|
309
|
+
|
|
310
|
+
This keeps default config portable while avoiding service working-directory issues.
|
|
311
|
+
|
|
312
|
+
## Security
|
|
313
|
+
|
|
314
|
+
Recommended defaults for community deployments:
|
|
315
|
+
|
|
316
|
+
- WS binds to localhost (`127.0.0.1`) by default.
|
|
317
|
+
- WS auth can be enabled with a shared token.
|
|
318
|
+
- Optional origin/IP allowlists for WS clients.
|
|
319
|
+
- Optional HMAC event signing (`hmac.enabled=false` by default).
|
|
320
|
+
- Native TLS/WSS termination is not provided by this plugin; run it behind a reverse proxy
|
|
321
|
+
(for example Nginx/Caddy/Traefik) for production HTTPS/WSS.
|
|
322
|
+
|
|
323
|
+
For local setups, keep the shared HMAC secret in `.event-plugin-hmac.secret`. Set `security.hmac.enabled=true` (or `EVENT_PLUGIN_HMAC_ENABLED=true`) to enable event signing.
|
|
324
|
+
|
|
325
|
+
## Contributing
|
|
326
|
+
|
|
327
|
+
If you want to contribute code, docs, or examples:
|
|
328
|
+
|
|
329
|
+
- Read [CONTRIBUTING.md](CONTRIBUTING.md) for workflow and PR expectations.
|
|
330
|
+
- Read [SECURITY.md](SECURITY.md) for responsible vulnerability reporting.
|
|
331
|
+
|
|
332
|
+
## Hook Bridge Automation
|
|
333
|
+
|
|
334
|
+
`hookBridge` enables event-driven automations directly from canonical plugin events. It can execute a local script or call a webhook when a matching event occurs.
|
|
335
|
+
|
|
336
|
+
- Match rules by `eventType`, identity fields, nested field checks, idle thresholds, and parent status.
|
|
337
|
+
- Dispatch actions as:
|
|
338
|
+
- `webhook` (`POST|PUT|PATCH` with JSON payload)
|
|
339
|
+
- `local_script` (fixed script path + args, event payload over stdin)
|
|
340
|
+
- Suppress repeated triggers with per-rule `cooldownMs`.
|
|
341
|
+
|
|
342
|
+
Local script actions are restricted to `allowedActionDirs` and run with `shell=false`.
|
|
343
|
+
Default runtime limits for local scripts are configured in `localScriptDefaults`.
|
|
344
|
+
|
|
345
|
+
### Tool Guard (Optional human in the middle)
|
|
346
|
+
|
|
347
|
+
`hookBridge.toolGuard` adds synchronous `before_tool_call` policy checks using the same `actions` registry.
|
|
348
|
+
By default it is disabled and does not affect tool execution.
|
|
349
|
+
|
|
350
|
+
- `enabled=false` (default): no blocking behavior.
|
|
351
|
+
- `rules`: ordered checks for tool-call context:
|
|
352
|
+
- `toolName`, `contains`, `equals`, `matchesRegex`, `notMatchesRegex`
|
|
353
|
+
- `requiredPaths`, `typeChecks`, `inList`, `notInList`
|
|
354
|
+
- `domainAllowlist` / `domainBlocklist` (optional `domainPath`, default `data.params.url`)
|
|
355
|
+
- agent/session fields
|
|
356
|
+
- `onError`:
|
|
357
|
+
- `allow` (default) fail-open on script/webhook error or timeout
|
|
358
|
+
- `block` fail-closed
|
|
359
|
+
- `dryRun=true`: evaluates/logs decisions but never blocks.
|
|
360
|
+
- `priority`: higher-priority rules evaluate first (ties keep config order).
|
|
361
|
+
- `stopOnMatch`: stop evaluating additional rules when a rule matches but returns no decision
|
|
362
|
+
(rules that return a decision already short-circuit).
|
|
363
|
+
- `retryBackoffMs`: force backoff when a blocked call is retried repeatedly.
|
|
364
|
+
- `approvalCacheTtlMs`: cache allow decisions for repeat calls.
|
|
365
|
+
- `scopeKeyBy`: `tool` or `tool_and_params` for retry/cache keys.
|
|
366
|
+
- `redaction` (default off): optional redaction for `tool.guard.*` event `data.params`.
|
|
367
|
+
- Each rule can either:
|
|
368
|
+
- call an `action` (webhook/local script), or
|
|
369
|
+
- use an inline static `decision` for simple validation/guidance.
|
|
370
|
+
|
|
371
|
+
Guard action response contract (webhook response body or local script stdout):
|
|
372
|
+
|
|
373
|
+
```json
|
|
374
|
+
{ "block": true, "blockReason": "Manual approval required" }
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
or
|
|
378
|
+
|
|
379
|
+
```json
|
|
380
|
+
{ "params": { "mode": "safe" } }
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
Invalid decision payloads are ignored. A valid decision must include either:
|
|
384
|
+
- `block` as a boolean, or
|
|
385
|
+
- `params` as an object.
|
|
386
|
+
|
|
387
|
+
For true blocking behavior (recommended for approvals):
|
|
388
|
+
- Set `hookBridge.toolGuard.onError` to `block` (fail-closed).
|
|
389
|
+
- Use a decision script that defaults to block on timeout/error.
|
|
390
|
+
- Require explicit human approvers (`OPENCLAW_APPROVAL_ALLOWED_USER_IDS` or profile `allowedUserIds`) so bot reactions/replies cannot auto-approve.
|
|
391
|
+
|
|
392
|
+
Example invalid payload (ignored):
|
|
393
|
+
|
|
394
|
+
```json
|
|
395
|
+
{ "blockReason": "manual approval required" }
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
Templated guidance is supported in `blockReasonTemplate` (or `blockReason`):
|
|
399
|
+
- `{{toolName}}`, `{{eventType}}`, `{{agentId}}`, `{{sessionId}}`, `{{sessionKey}}`, `{{runId}}`, `{{toolCallId}}`
|
|
400
|
+
- `{{path:data.params.url}}` for dotted-path lookups
|
|
401
|
+
|
|
402
|
+
Example malformed-call filter without scripting:
|
|
403
|
+
|
|
404
|
+
```json
|
|
405
|
+
{
|
|
406
|
+
"id": "web-fetch-url-must-be-https",
|
|
407
|
+
"priority": 100,
|
|
408
|
+
"when": {
|
|
409
|
+
"toolName": "web_fetch",
|
|
410
|
+
"notMatchesRegex": {
|
|
411
|
+
"data.params.url": "^https://"
|
|
412
|
+
}
|
|
413
|
+
},
|
|
414
|
+
"decision": {
|
|
415
|
+
"block": true,
|
|
416
|
+
"blockReasonTemplate": "Malformed {{toolName}} URL: {{path:data.params.url}}. Use: {{toolName}} \"https://...\""
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Tool Guard Replay
|
|
422
|
+
|
|
423
|
+
You can replay captured tool calls against `toolGuard` policies before rollout:
|
|
424
|
+
|
|
425
|
+
From a local source checkout:
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
npm run build
|
|
429
|
+
jq '.plugins.entries["event-server-plugin"].config' ~/.openclaw/openclaw.json > /tmp/event-plugin-config.json
|
|
430
|
+
npm run toolguard:replay -- --config /tmp/event-plugin-config.json --input ./calls.ndjson
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
Input format supports:
|
|
434
|
+
- JSON array of tool call objects
|
|
435
|
+
- NDJSON (one tool call object per line)
|
|
436
|
+
|
|
437
|
+
Each call object fields:
|
|
438
|
+
- `toolName` (required)
|
|
439
|
+
- `params` (object)
|
|
440
|
+
- optional `agentId`, `sessionId`, `sessionKey`, `runId`, `toolCallId`
|
|
441
|
+
|
|
442
|
+
### Tool Guard Bundles
|
|
443
|
+
|
|
444
|
+
Starter bundles are included under `examples/tool-guard-bundles/`:
|
|
445
|
+
- `network-egress.json`
|
|
446
|
+
- `shell-guard.json`
|
|
447
|
+
- `sudo-slack-approval-allow.json` (sends Slack approval requests for `sudo` calls, then allows execution)
|
|
448
|
+
- `web-browse-human-approval.json` (requires explicit human approval for `web_search`, `web_fetch`, and `browser`; posts a Slack approval request and waits for approve/reject reply or reaction)
|
|
449
|
+
- annotated versions for bot/user guidance are also included as `*.annotated.jsonc`
|
|
450
|
+
|
|
451
|
+
Example local scripts for `local_script` actions are under `examples/tool-guard-bundles/scripts/`:
|
|
452
|
+
- `sudo-slack-approval-and-allow.sh`
|
|
453
|
+
- `web-browse-slack-human-approval.sh` (interactive Slack approvals via replies/reactions; requires longer `toolGuard.timeoutMs`)
|
|
454
|
+
- script is fail-closed by default (`OPENCLAW_APPROVAL_REQUIRE_ALLOWED_USERS=true`)
|
|
455
|
+
- rejects approvals from bot users
|
|
456
|
+
- supports `web_search`, `web_fetch`, `browser` (or any tool when used in a matching rule)
|
|
457
|
+
|
|
458
|
+
Optional approval channel profiles example:
|
|
459
|
+
- `toolguard-approval-profiles.example.json` (copy to `~/.openclaw/toolguard-approval-profiles.json` and edit)
|
|
460
|
+
- include `allowedUserIds` to restrict who can approve/reject
|
|
461
|
+
|
|
462
|
+
## Development
|
|
463
|
+
|
|
464
|
+
```bash
|
|
465
|
+
npm run lint
|
|
466
|
+
npm run build
|
|
467
|
+
npm test -- --runInBand
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
## Notes
|
|
471
|
+
|
|
472
|
+
- The plugin is intentionally "dumb" for event forwarding: payload transformation is minimal.
|
|
473
|
+
- Downstream consumers should own filtering/aggregation beyond canonical normalization.
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
{
|
|
2
|
+
"enabled": true,
|
|
3
|
+
"webhooks": [
|
|
4
|
+
{
|
|
5
|
+
"url": "https://your-webhook-endpoint.com/events",
|
|
6
|
+
"method": "POST",
|
|
7
|
+
"headers": {
|
|
8
|
+
"Content-Type": "application/json"
|
|
9
|
+
},
|
|
10
|
+
"authToken": "your-auth-token-here",
|
|
11
|
+
"includeFullPayload": true
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"filters": {
|
|
15
|
+
"includeTypes": [],
|
|
16
|
+
"excludeTypes": [],
|
|
17
|
+
"channelId": "",
|
|
18
|
+
"toolName": "",
|
|
19
|
+
"sessionId": ""
|
|
20
|
+
},
|
|
21
|
+
"retry": {
|
|
22
|
+
"maxAttempts": 3,
|
|
23
|
+
"initialDelayMs": 1000,
|
|
24
|
+
"maxDelayMs": 30000,
|
|
25
|
+
"backoffMultiplier": 2
|
|
26
|
+
},
|
|
27
|
+
"queue": {
|
|
28
|
+
"maxSize": 1000,
|
|
29
|
+
"flushIntervalMs": 5000,
|
|
30
|
+
"persistToDisk": false,
|
|
31
|
+
"persistPath": ""
|
|
32
|
+
},
|
|
33
|
+
"logging": {
|
|
34
|
+
"debug": false,
|
|
35
|
+
"logSuccess": false,
|
|
36
|
+
"logErrors": true,
|
|
37
|
+
"logQueue": false
|
|
38
|
+
},
|
|
39
|
+
"status": {
|
|
40
|
+
"workingWindowMs": 30000,
|
|
41
|
+
"sleepingWindowMs": 600000,
|
|
42
|
+
"tickIntervalMs": 5000,
|
|
43
|
+
"subagentIdleWindowMs": 300000
|
|
44
|
+
},
|
|
45
|
+
"redaction": {
|
|
46
|
+
"enabled": false,
|
|
47
|
+
"replacement": "[REDACTED]",
|
|
48
|
+
"fields": [
|
|
49
|
+
"content",
|
|
50
|
+
"newContent",
|
|
51
|
+
"originalContent",
|
|
52
|
+
"transcript",
|
|
53
|
+
"normalizedText",
|
|
54
|
+
"params",
|
|
55
|
+
"arguments",
|
|
56
|
+
"token",
|
|
57
|
+
"apiKey",
|
|
58
|
+
"api_key",
|
|
59
|
+
"authorization",
|
|
60
|
+
"authToken",
|
|
61
|
+
"password",
|
|
62
|
+
"secret"
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
"eventLog": {
|
|
66
|
+
"enabled": true,
|
|
67
|
+
"path": ".event-server/events.ndjson",
|
|
68
|
+
"maxFileSizeMb": 30,
|
|
69
|
+
"format": "full-json",
|
|
70
|
+
"minLevel": "debug",
|
|
71
|
+
"includeRuntimeLogs": true
|
|
72
|
+
},
|
|
73
|
+
"security": {
|
|
74
|
+
"ws": {
|
|
75
|
+
"bindAddress": "127.0.0.1",
|
|
76
|
+
"requireAuth": false,
|
|
77
|
+
"authToken": "",
|
|
78
|
+
"allowedOrigins": [],
|
|
79
|
+
"allowedIps": []
|
|
80
|
+
},
|
|
81
|
+
"hmac": {
|
|
82
|
+
"enabled": false,
|
|
83
|
+
"secret": "",
|
|
84
|
+
"secretFilePath": ".event-plugin-hmac.secret",
|
|
85
|
+
"algorithm": "sha256"
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"correlationIdHeader": "X-Correlation-ID",
|
|
89
|
+
"webhookTimeoutMs": 10000,
|
|
90
|
+
"hookBridge": {
|
|
91
|
+
"enabled": false,
|
|
92
|
+
"dryRun": false,
|
|
93
|
+
"allowedActionDirs": ["/absolute/path/to/hooks"],
|
|
94
|
+
"localScriptDefaults": {
|
|
95
|
+
"timeoutMs": 10000,
|
|
96
|
+
"maxPayloadBytes": 65536
|
|
97
|
+
},
|
|
98
|
+
"actions": {
|
|
99
|
+
"sudo-alert-webhook": {
|
|
100
|
+
"type": "webhook",
|
|
101
|
+
"url": "https://example.com/hook/sudo-alert",
|
|
102
|
+
"method": "POST",
|
|
103
|
+
"headers": {
|
|
104
|
+
"X-Source": "openclaw-event-server-plugin"
|
|
105
|
+
},
|
|
106
|
+
"timeoutMs": 10000
|
|
107
|
+
},
|
|
108
|
+
"wake-parent-local": {
|
|
109
|
+
"type": "local_script",
|
|
110
|
+
"path": "/absolute/path/to/hooks/wake-parent.sh",
|
|
111
|
+
"args": [],
|
|
112
|
+
"timeoutMs": 10000,
|
|
113
|
+
"maxPayloadBytes": 65536
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
"rules": [
|
|
117
|
+
{
|
|
118
|
+
"id": "notify-sudo-usage",
|
|
119
|
+
"enabled": true,
|
|
120
|
+
"when": {
|
|
121
|
+
"eventType": "tool.called",
|
|
122
|
+
"toolName": "exec",
|
|
123
|
+
"contains": {
|
|
124
|
+
"data.params.command": "sudo"
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
"action": "sudo-alert-webhook",
|
|
128
|
+
"cooldownMs": 60000,
|
|
129
|
+
"coalesce": {
|
|
130
|
+
"enabled": false
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"id": "wake-parent-on-subagent-idle",
|
|
135
|
+
"enabled": true,
|
|
136
|
+
"when": {
|
|
137
|
+
"eventType": "subagent.idle",
|
|
138
|
+
"idleForMsGte": 300000,
|
|
139
|
+
"parentStatus": "sleeping"
|
|
140
|
+
},
|
|
141
|
+
"action": "wake-parent-local",
|
|
142
|
+
"cooldownMs": 120000
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
"toolGuard": {
|
|
146
|
+
"enabled": false,
|
|
147
|
+
"dryRun": false,
|
|
148
|
+
"timeoutMs": 15000,
|
|
149
|
+
"onError": "allow",
|
|
150
|
+
"scopeKeyBy": "tool_and_params",
|
|
151
|
+
"retryBackoffMs": 10000,
|
|
152
|
+
"retryBackoffReason": "Retry blocked. Back off briefly before retrying this tool call.",
|
|
153
|
+
"approvalCacheTtlMs": 60000,
|
|
154
|
+
"stopOnMatchDefault": false,
|
|
155
|
+
"redaction": {
|
|
156
|
+
"enabled": false,
|
|
157
|
+
"replacement": "[REDACTED]",
|
|
158
|
+
"fields": ["token", "authorization", "apiKey", "password", "secret"]
|
|
159
|
+
},
|
|
160
|
+
"rules": [
|
|
161
|
+
{
|
|
162
|
+
"id": "web-browse-url-must-be-https",
|
|
163
|
+
"priority": 100,
|
|
164
|
+
"enabled": true,
|
|
165
|
+
"when": {
|
|
166
|
+
"toolName": "web_browse",
|
|
167
|
+
"notMatchesRegex": {
|
|
168
|
+
"data.params.url": "^https://"
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
"decision": {
|
|
172
|
+
"block": true,
|
|
173
|
+
"blockReason": "Malformed web_browse URL. Use: web_browse \"https://...\""
|
|
174
|
+
},
|
|
175
|
+
"cooldownMs": 0
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"id": "human-approve-exec",
|
|
179
|
+
"priority": 10,
|
|
180
|
+
"enabled": false,
|
|
181
|
+
"when": {
|
|
182
|
+
"toolName": "exec"
|
|
183
|
+
},
|
|
184
|
+
"action": "wake-parent-local",
|
|
185
|
+
"cooldownMs": 0
|
|
186
|
+
}
|
|
187
|
+
]
|
|
188
|
+
},
|
|
189
|
+
"runtime": {
|
|
190
|
+
"maxPendingEvents": 1000,
|
|
191
|
+
"concurrency": 8,
|
|
192
|
+
"dropPolicy": "drop_oldest"
|
|
193
|
+
},
|
|
194
|
+
"telemetry": {
|
|
195
|
+
"highWatermarks": [70, 90, 100],
|
|
196
|
+
"slowActionMs": 2000,
|
|
197
|
+
"failureRateWindowMs": 60000,
|
|
198
|
+
"failureRateThresholdPct": 20,
|
|
199
|
+
"failureRateMinSamples": 10,
|
|
200
|
+
"saturationWindowMs": 10000
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|