Tools
Plugin Lifecycle Hooks
OpenClaw plugin for lifecycle hooks and behavioral enforcement (@fractal-ai scope)
Install
npm install @fractal-ai/plugin-lifecycle-hooks
Configuration Example
version: "1"
hooks:
# Block destructive rm commands (main agent + sub-agents)
- point: [turn:tool:pre, subagent:tool:pre]
match:
tool: exec
commandPattern: "^rm\\s"
action: block
onFailure:
action: block
notifyUser: true
message: "๐ซ Use `trash <path>` instead of `rm`."
# Log all turns to per-topic JSONL files
- point: turn:post
match:
topicId: "*" # Match any topic
action: log
target: "memory/topics/topic-{topicId}.jsonl"
onFailure:
action: continue
README
# @fractal-ai/plugin-lifecycle-hooks
> โ ๏ธ **IMPORTANT โ READ BEFORE USE**
>
> This plugin **modifies how OpenClaw processes agent turns** and can enforce security-sensitive policies (blocking commands, gating execution, injecting context). Misconfiguration may block your agent pipeline entirely.
>
> **Written by AI.** While most hook actions and configurations have been live-tested in production, you should **validate all critical tasks and security rules yourself** before relying on them. Review your YAML config carefully โ especially `block` actions โ and test in a non-production environment first.
[](https://www.npmjs.com/package/@fractal-ai/plugin-lifecycle-hooks)
[](https://opensource.org/licenses/MIT)
[](https://nodejs.org)
**Enforced lifecycle hook gates for OpenClaw agent pipelines.**
Define safety policies, observability rules, and execution gates in a simple YAML file. Hooks fire at every major pipeline transition โ and actually **block execution** until they complete.
---
## What It Does
OpenClaw's existing plugin hooks are fire-and-forget โ the pipeline doesn't wait for them. This plugin replaces that with a **gate engine**: hooks block execution, complete their action, and only then allow the pipeline to continue.
This makes it possible to:
- โ
**Enforce hard safety policies** (not just log them)
- โ
**Inject context before sub-agents start**
- โ
**Push structured data to external systems** at exactly the right moment
- โ
**Block dangerous commands** before they execute
- โ
**Auto-log turns to persistent memory** without manual intervention
---
## Quick Start
### 1. Install the Plugin
```bash
npm install @fractal-ai/plugin-lifecycle-hooks
```
### 2. Create `HOOKS.yaml` in Your Workspace Root
```yaml
version: "1"
hooks:
# Block destructive rm commands (main agent + sub-agents)
- point: [turn:tool:pre, subagent:tool:pre]
match:
tool: exec
commandPattern: "^rm\\s"
action: block
onFailure:
action: block
notifyUser: true
message: "๐ซ Use `trash <path>` instead of `rm`."
# Log all turns to per-topic JSONL files
- point: turn:post
match:
topicId: "*" # Match any topic
action: log
target: "memory/topics/topic-{topicId}.jsonl"
onFailure:
action: continue
```
### 3. Restart the OpenClaw Gateway
```bash
openclaw gateway restart
```
See [docs/QUICKSTART.md](./docs/QUICKSTART.md) for detailed setup instructions.
---
## Core Concepts
### Hook Points
Every major transition in the OpenClaw pipeline is hookable:
| Hook Point | When It Fires | Example Use |
|------------|---------------|-------------|
| `turn:pre` | Prompt received, before agent starts | Log incoming prompt, inject context |
| `turn:post` | Agent response finalized | Summarize turn to topic file |
| `turn:tool:pre` | Before a tool call (main agent) | Block `rm`, require confirmation |
| `turn:tool:post` | After a tool call resolves | Log results, validate output |
| `subagent:spawn:pre` | Main agent about to spawn sub-agent | Inject shared context, log spawn |
| `subagent:pre` | Sub-agent starting its session | Apply sub-agent-specific rules |
| `subagent:post` | Sub-agent completed | Force write to log, relay results |
| `subagent:tool:pre` | Before a tool call (sub-agent) | Same `rm` guard as main agent |
| `subagent:tool:post` | After a sub-agent tool call | Audit log |
| `heartbeat:pre` | Before a heartbeat cycle | Prepare health check data |
| `heartbeat:post` | After a heartbeat cycle | Push metrics to dashboard |
| `cron:pre` | Before a cron job fires | Log job start, validate conditions |
| `cron:post` | After a cron job completes | Track success rates, alert failures |
**Multiple points on one hook:**
```yaml
point: [turn:tool:pre, subagent:tool:pre]
```
---
## Actions Reference
### ๐ซ `block` โ Block Dangerous Operations
Immediately halt the pipeline with an optional message to the user.
**Example: Block `rm` commands**
```yaml
hooks:
- point: [turn:tool:pre, subagent:tool:pre]
match:
tool: exec
commandPattern: "^rm\\s"
action: block
onFailure:
action: block
notifyUser: true
message: "๐ซ Use `trash` instead of `rm`."
```
**When to use:**
- Prevent destructive commands (`rm -rf`, `dd`, `chmod 777`)
- Enforce delegation policies (e.g., "npm install must run in sub-agent")
- Block privileged operations (`sudo`, `docker run --privileged`)
**Key fields:**
- `action: block` โ Action type
- `onFailure.notifyUser` โ Send notification to user (optional)
- `onFailure.message` โ Custom message (optional)
---
### ๐ `log` โ Append Structured JSON to a Log File
Write structured JSON entries to a file or stdout. Supports variable interpolation in `target`.
**Example: Per-topic turn logging**
```yaml
hooks:
- point: turn:post
match:
topicId: "*" # Match any topic
action: log
target: "memory/topics/topic-{topicId}.jsonl"
onFailure:
action: continue
```
**When to use:**
- Auto-persist turns to per-topic memory files
- Audit log every exec call
- Track sub-agent spawns and completions
- Push structured data to external systems (parse JSONL with jq/Python)
**Key fields:**
- `action: log` โ Action type
- `target` โ File path (supports `{topicId}`, `{sessionKey}`, `{timestamp}`)
- If `target` is `"-"` or omitted, logs to stdout
**Output format:**
```json
{"point":"turn:post","sessionKey":"agent:main:telegram:group:-100EXAMPLE:topic:42","topicId":42,"timestamp":1735123456789,"prompt":"Fix the bug","response":"I'll investigate..."}
```
---
### ๐ฅ `inject_context` โ Load Context from File into Agent Prompt
Load a file and inject its content into the session context. Supports variable interpolation in `source`.
**Example: Inject topic context into every sub-agent**
```yaml
hooks:
- point: subagent:pre
match:
topicId: "*"
action: inject_context
source: "memory/topics/topic-{topicId}.jsonl"
onFailure:
action: continue
```
**When to use:**
- Share workspace conventions (AGENTS.md, TOOLS.md) with every sub-agent
- Load per-topic context before each turn
- Inject security policies or style guides
**Key fields:**
- `action: inject_context` โ Action type
- `source` โ File path to load (supports variable interpolation)
**Note:** Currently a stub โ will be wired to OpenClaw's context API in a future release.
---
### ๐ท๏ธ `inject_origin` โ Inject Message Origin Metadata
Inject message origin metadata (chat ID, topic ID, sender) into the agent context.
**Example: Add origin metadata to every turn**
```yaml
hooks:
- point: turn:pre
match:
topicId: "*"
action: inject_origin
onFailure:
action: continue
```
**When to use:**
- Preserve origin context across sub-agent spawns
- Track which topic/chat/sender originated a request
- Survive context compaction
**Key fields:**
- `action: inject_origin` โ Action type
**Injected metadata:**
```
Origin: chat={chatId} topic={topicId} from={sender}
```
---
### ๐ค `summarize_and_log` โ LLM-Summarize Then Log
Use an LLM to summarize the event context, then append to a log file. Supports variable interpolation in `target`.
**Example: Context catcher for topic memory**
```yaml
hooks:
- point: turn:post
match:
topicId: "*"
action: summarize_and_log
model: "anthropic/claude-haiku-4-5"
target: "memory/topics/topic-{topicId}.md"
onFailure:
action: continue
```
**When to use:**
- Human-readable turn summaries for topic memory
- Condense long threads before context compaction
- Generate executive summaries for heartbeat/cron reports
**Key fields:**
- `action: summarize_and_log` โ Action type
- `model` โ LLM model to use for summarization
- `target` โ File path (supports variable interpolation)
**Output format:** Appends markdown summary to the target file.
---
### ๐ง `exec_script` โ Run a Shell Script with Optional Stdout Injection
Run a shell script; exit 0 = pass, non-zero = fail. Supports variable interpolation in `script`. Optionally captures stdout into agent context.
**Example: Security check before tool calls**
```yaml
hooks:
- point: turn:tool:pre
match:
tool: exec
action: exec_script
script: "./scripts/security-check.sh {toolArgs.command}"
injectOutput: false
onFailure:
action: block
notifyUser: true
message: "โ Security check failed."
```
**Example: Inject script output into context**
```yaml
hooks:
- point: turn:pre
action: exec_script
script: "./scripts/load-env-vars.sh"
injectOutput: true
onFailure:
action: continue
```
**When to use:**
- Run external validators (security scanners, linters)
- Push webhook notifications (Slack, Discord, PagerDuty)
- Dynamically load environment-specific config
**Key fields:**
- `action: exec_script` โ Action type
- `script` โ Path to shell script (supports variable interpolation)
- `injectOutput` โ If `true`, capture stdout and inject into context (default: `false`)
---
### ๐ข `notify_user` โ Send Telegram Notification
Send a fire-and-forget Telegram notification to the user. Optionally generates an LLM summary before notifying.
**Example: Notify when sub-agent completes**
```yaml
hooks:
- point: subagent:post
action: notify_user
model: "anthropic/claude-haiku-4-5" # Optional: enables LLM summary
onFailure:
action: continue
```
**When to use:**
- Alert on critical events (sub-agent completion, dangerous command blocked)
- Push real-time status updates to Telegram
- Human-in-the-loop confirmations
**Key fields:**
- `action: notify_user` โ Action type
- `model` โ LLM model to use for summarization (optional)
**Note:** The notification target is automatically determined from the sessi
... (truncated)
tools
Comments
Sign in to leave a comment