← Back to Plugins
Voice

Blackwall Openclaw

bluetieroperations-create By bluetieroperations-create 👁 13 views ▲ 0 votes

BLACK_WALL pre-action guardrail for OpenClaw agents. Hooks before_tool_call to call forecast() before any tool runs; blocks STOP verdicts; surfaces CAUTION as approval prompts. Receipts are Ed25519-signed and verifiable offline.

GitHub

Configuration Example

import { createBlackwallPlugin } from 'blackwall-openclaw-plugin';

export default createBlackwallPlugin({
  mode: 'enforce',
  cautionAction: 'approve',  // 'approve' (default) | 'block' | 'allow'
});

README

# blackwall-openclaw-plugin

Pre-action risk check for [OpenClaw](https://github.com/openclaw/openclaw) agents. Hooks `before_tool_call` so STOP-rated actions can be **blocked before they run** β€” without modifying your character, tools, or other plugins.

Powered by [BLACK_WALL](https://blackwalltier.com). Get a free key at [blackwalltier.com/dashboard/keys](https://blackwalltier.com/dashboard/keys).

## Install

```bash
npm i blackwall-openclaw-plugin
```

Add to `~/.openclaw/openclaw.json`:

```json5
{
  plugins: {
    entries: {
      "blackwall-openclaw-plugin": { enabled: true }
    }
  }
}
```

Set the env var (in your shell, `~/.openclaw/.env`, or the launcher):

```bash
BLACKWALL_API_KEY=bw_live_xxx
BLACKWALL_MODE=observe     # or 'enforce' once you trust the verdicts
```

That's it. Every tool the agent tries to call goes through `before_tool_call` β†’ BLACK_WALL forecast β†’ verdict.

## What you get back per tool call

- `GO` / `CAUTION` / `STOP`
- risk score 0–100
- reversibility class (REVERSIBLE / RECOVERABLE / IRREVERSIBLE)
- named red flags β€” e.g. `SQL_NO_WHERE`, `PROMPT_INJECTION_LIKELY`, `IRREVERSIBLE_NO_BACKUP`
- an Ed25519-signed Decision Receipt β€” verifiable offline against the published public key

Round trip ~4–8s.

## Modes

| Mode | Behavior |
|---|---|
| `observe` (default) | Score every tool call and log to BLACK_WALL; never block. Zero behavior change β€” safe to drop in. |
| `enforce` | **STOP** β†’ hard block (returns `{ block: true }`). **CAUTION** β†’ surfaces an approval prompt natively via OpenClaw's `requireApproval`. **GO** β†’ proceeds. |

Start in `observe` for a few days to see what the verdicts look like on your real traffic. Switch to `enforce` once you trust the scoring.

## Configurable CAUTION behavior

```js
import { createBlackwallPlugin } from 'blackwall-openclaw-plugin';

export default createBlackwallPlugin({
  mode: 'enforce',
  cautionAction: 'approve',  // 'approve' (default) | 'block' | 'allow'
});
```

- `approve` β€” fires OpenClaw's built-in approval prompt with the named red flags. User decides per call.
- `block` β€” treats CAUTION as STOP. Hard block.
- `allow` β€” treats CAUTION as GO. Lets it run, just observed.

## Why hook into `before_tool_call`?

OpenClaw's plugin SDK exposes [`before_tool_call`](https://docs.openclaw.ai/plugins/hooks) as an official typed hook with `block` + `requireApproval` return semantics β€” exactly the shape a pre-action guardrail needs. The plugin does **not** monkey-patch the dispatcher; it uses the documented extension surface.

That means:

- Priority-ordered with other policy hooks (defaults to `priority: 80`)
- Per-hook timeout (`timeoutMs: 15_000` by default β€” a hung forecast can't stall the agent)
- Native `requireApproval` flow for CAUTION verdicts
- Hot-reloadable via the gateway

## Companion skills

This package also ships two OpenClaw skills under `./skills/` that you can install into `~/.openclaw/skills/`:

- **`/blackwall-policy`** β€” Explains what BLACK_WALL is gating in this session, the failure-mode codes, and why a tool was blocked. Read by the agent when a `failureResult` references BLACK_WALL.
- **`/blackwall-verify`** β€” Verifies a Decision Receipt cryptographically (offline against the published public key, or via the hosted stateless verify endpoint).

Copy them in:

```bash
cp -r node_modules/blackwall-openclaw-plugin/skills/* ~/.openclaw/skills/
```

(or symlink for development).

## Full config reference

```js
createBlackwallPlugin({
  apiKey: process.env.BLACKWALL_API_KEY,    // or set BLACKWALL_API_KEY
  baseUrl: 'https://blackwalltier.com',     // override for self-hosted/staging
  mode: 'enforce',                          // 'observe' (default) | 'enforce'
  cautionAction: 'approve',                 // 'approve' (default) | 'block' | 'allow'
  shouldGate: (toolName) => toolName !== 'no_op',  // per-tool opt-out
  maxInputBytes: 8 * 1024,                  // truncate forecast payload over this size
  forecastTimeoutMs: 15_000,                // per-hook timeout
  onEvent: (event) => myTelemetry(event),   // optional telemetry hook
});
```

### Telemetry events emitted via `onEvent`

`register`, `skipped`, `observed`, `stop`, `require_approval`, `forecast_error`, `observe_error`, `observed_outcome`.

## How it works

```
                     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                     β”‚ OpenClaw agent decides to    β”‚
                     β”‚ call tool X with params Y    β”‚
                     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                   β”‚
                          before_tool_call
                                   β”‚
                                   β–Ό
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚ blackwall plugin: forecast(X, Y)          β”‚
            β”‚ ↓                                          β”‚
            β”‚ STOP   β†’ return { block: true,             β”‚
            β”‚           blockReason: "..." }             β”‚
            β”‚ CAUTION β†’ return { requireApproval: {...}} β”‚
            β”‚ GO     β†’ return undefined                 β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                               β”‚ (if not blocked)
                               β–Ό
                       tool actually runs
                               β”‚
                          after_tool_call
                               β”‚
                               β–Ό
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚ blackwall plugin: observe(forecast_id,    β”‚
            β”‚   outcome_class)                          β”‚
            β”‚ matched / diverged / aborted              β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

Fail-open: if BLACK_WALL is unreachable, the hook logs a warning and lets the tool proceed. A BLACK_WALL outage will never take down your agent.

## Architecture

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ BLACK_WALL HTTP API (stable, versioned)      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              β–²
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ blackwall-mcp/lib  (shared client logic)     β”‚
β”‚   - forecast()                                β”‚
β”‚   - observe()                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              β–²
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ blackwall-openclaw-plugin (this package)     β”‚
β”‚   - before_tool_call hook                     β”‚
β”‚   - after_tool_call hook                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              β–²
            OpenClaw
```

When OpenClaw ships breaking changes to its plugin contract, only this package needs to update. The HTTP API, the `blackwall-mcp` library, the MCP server, and every other BLACK_WALL integration remain insulated.

## Links

- Site & docs: https://blackwalltier.com
- Free API key: https://blackwalltier.com/dashboard/keys
- Failure-mode taxonomy (28 named red-flag codes): https://blackwalltier.com/failure-modes
- npm: [`blackwall-openclaw-plugin`](https://www.npmjs.com/package/blackwall-openclaw-plugin) Β· [`blackwall-mcp`](https://www.npmjs.com/package/blackwall-mcp)
- Source: https://github.com/bluetieroperations-create/blackwall-openclaw-plugin
- Sibling plugin (ElizaOS): [`blackwall-eliza-guardrail`](https://www.npmjs.com/package/blackwall-eliza-guardrail)

## License

MIT
voice

Comments

Sign in to leave a comment

Loading comments...