OpenClaw end-to-end flow

How DefenseClaw integrates with OpenClaw end-to-end — fetch interceptor, before_tool_call hook, correlation headers, plugin-mediated HITL approvals, and the audit loop.

OpenClaw is the connector DefenseClaw was designed against. It is also the only connector that ships a first-party plugin in the same repository (extensions/defenseclaw/). That plugin owns the OpenClaw-side wiring; the gateway and CLI own everything else.

Plugin install + first guardrail. The DefenseClaw plugin loads inside OpenClaw, routes supported traffic through the sidecar, and returns policy decisions through OpenClaw's native surfaces.

Components

DefenseClaw plugin

TypeScript plugin under extensions/defenseclaw/. Hooks into OpenClaw's fetch interceptor and before_tool_call lifecycle.

defenseclaw-gateway

Go sidecar. Receives plugin requests, evaluates policy, returns verdicts, and writes the audit row.

DefenseClaw CLI

Python operator surface. Runs setup and exposes the TUI for audit, alerts, logs, and inventory.

Protocol compatibility

The DefenseClaw gateway client speaks the OpenClaw WebSocket handshake across the protocol v3-v4 range. During connect it sends minProtocol: 3 and maxProtocol: 4; OpenClaw returns the negotiated hello-ok protocol plus the supported method and event feature sets. That keeps current OpenClaw protocol v4 installs compatible while preserving the v3 challenge-response device flow for older OpenClaw endpoints.

End-to-end flow

The plugin hands two kinds of work to defenseclaw-gateway: model calls, which go through the guardrail proxy, and tool calls, which wait for a verdict from the inspect API.

A model call

OpenClaw
Plugin
Gateway
Model
calls the model
redirects to the proxy
forwards if allowed
model response
checked response, or a block
response
  1. 1OpenClaw to Plugin

    calls the model

  2. 2Plugin to Gateway

    redirects to the proxy

  3. 3Gateway to Model

    forwards if allowed

  4. 4Model to Gatewayreply

    model response

  5. 5Gateway to Pluginreply

    checked response, or a block

  6. 6Plugin to OpenClawreply

    response

The plugin's fetch interceptor sends each recognized LLM request to the guardrail proxy (port 4000 by default), keeping the original address in the X-DC-Target-URL header. The proxy checks the request before it forwards it and the response before it returns it.

A tool call

User
OpenClaw
Plugin
Gateway
about to run a tool
POST /api/v1/inspect/tool
allow · alert · confirm · block
run, block, or requireApproval
asks for approval (confirm only)
approve or deny
reports the answer (logged)
  1. 1OpenClaw to Plugin

    about to run a tool

  2. 2Plugin to Gateway

    POST /api/v1/inspect/tool

  3. 3Gateway to Pluginreply

    allow · alert · confirm · block

  4. 4Plugin to OpenClawreply

    run, block, or requireApproval

  5. 5OpenClaw to User

    asks for approval (confirm only)

  6. 6User to OpenClawreply

    approve or deny

  7. 7OpenClaw to Plugin

    reports the answer (logged)

Before each tool runs, the plugin posts it to the inspect API (port 18970 by default). In action mode a block verdict stops the tool and a confirm verdict becomes OpenClaw's requireApproval, which denies on timeout; allow and alert let the tool run. OpenClaw asks the user and applies the answer; the plugin only logs it.

Correlation headers

There is no X-DefenseClaw-Correlation-Id header. Depending on the available context, plugin requests use the shared header vocabulary X-DefenseClaw-Run-Id, X-DefenseClaw-Session-Id, X-DefenseClaw-Trace-Id, X-DefenseClaw-Agent-Id, X-DefenseClaw-Agent-Name, X-DefenseClaw-Policy-Id, X-DefenseClaw-Agent-Instance-Id, and X-DefenseClaw-Sidecar-Instance-Id; the HTTP client also identifies itself with X-DefenseClaw-Client.

Optional fields are omitted when OpenClaw has not supplied their context. The fetch interceptor mints a fresh trace ID for each intercepted LLM call and reuses the most recently observed tool context for run/session attribution. The sidecar can echo sticky agent/sidecar instance IDs so later requests converge on the same runtime identities.

HITL: the only connector with plugin-mediated approval

OpenClaw provides a native, plugin-mediated approval flow in its chat origin, so the operator approves or denies without leaving OpenClaw. For an action-mode confirm verdict, the plugin returns OpenClaw's requireApproval object with a deny-on-timeout policy. OpenClaw applies the decision. The plugin's onResolution callback logs the resolution; it does not send a separate "resolve approval" request to the DefenseClaw gateway. Other native-ask connectors use their own host hook UI instead of this plugin path.

Connectors and hook events without native ask apply their documented alert/allow/context fallback. Their events remain visible in audit and defenseclaw tui, but the TUI cannot resume the original call. See the HITL page for the per-connector matrix.

Files DefenseClaw owns inside the OpenClaw tree

openclaw.json (allow + load entries for the DefenseClaw plugin)

DefenseClaw limits its OpenClaw-tree changes to extensions/defenseclaw/ and its managed allow/load entries in openclaw.json. Backups are byte-for-byte; teardown either restores the file or surgically removes only DefenseClaw entries when the file has drifted. Hosts that still carry the removed legacy standalone sandbox should run the legacy cleanup first.

When this is the right connector

Pick OpenClaw when:

  • You want the strongest enforcement contract: proxy-mode interception, shell-shim subprocess inspection, native ask + plugin-mediated approval.
  • You're already running OpenClaw or are open to switching from Codex / Claude Code for security-critical workflows.
  • You need fail-closed behaviour on transport failures.

If you're not running OpenClaw, the Claude Code connector is the closest hook-only equivalent and supports native ask on PreToolUse.

OpenClaw version compatibility

OpenClaw 2026.6.8 and later can emit provider traffic through undici or embedded runtimes that skip a fetch-only patch. The DefenseClaw plugin intercepts globalThis.fetch, Node http/https.request, and the undici global dispatcher, then runs a sentinel self-test that never leaves the host. defenseclaw doctor reports OpenClaw interception from that self-test. A healthy :4000 liveliness probe is not enough; if agent turns succeed while doctor says traffic is not intercepted, restart OpenClaw so the plugin reloads and rerun doctor. Confirm a real INCOMING REQUEST delta in gateway.log only when that log can grow.