← Back to Plugins
Tools

Plugin Lifecycle Hooks

luke7524811 By luke7524811 👁 25 views ▲ 0 votes

OpenClaw plugin for lifecycle hooks and behavioral enforcement (@fractal-ai scope)

GitHub

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.

[![npm version](https://img.shields.io/npm/v/@fractal-ai/plugin-lifecycle-hooks.svg)](https://www.npmjs.com/package/@fractal-ai/plugin-lifecycle-hooks)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Node โ‰ฅ18](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](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

Loading comments...