|
| 1 | +--- |
| 2 | +title: "OpenClaw" |
| 3 | +description: "Instrument OpenClaw with the observability plugin so Gateway sessions and tool calls reach Observe and risk policies are enforced on OpenClaw traffic." |
| 4 | +--- |
| 5 | + |
| 6 | +import { Callout } from "@/mdx/components"; |
| 7 | + |
| 8 | +OpenClaw loads plugins in-process when its Gateway starts, so the observability plugin ships as a native OpenClaw plugin package rather than a marketplace entry. The package is installed with `openclaw plugins install`, granted conversation access in the OpenClaw config, and picked up on the next Gateway restart. This page covers rendering that package, the two configuration steps it depends on, and verifying that events arrive. |
| 9 | + |
| 10 | +Once installed, the plugin captures OpenClaw sessions and tool calls for [Observe](/docs/ai-control-plane/observe) and enforces [risk policies](/docs/ai-control-plane/secure/guardrails) on prompts and tool calls. |
| 11 | + |
| 12 | +<Callout title="Hooks require OpenClaw's embedded runtime" type="warning"> |
| 13 | + When a model is configured with Claude CLI OAuth authentication, OpenClaw |
| 14 | + delegates the model and tool loop out of process to the Claude Code CLI, and |
| 15 | + none of the plugin's hooks fire β no prompts, tool calls, replies, or usage |
| 16 | + are recorded for that model. This is the login default whenever a |
| 17 | + `claude-cli` profile exists. Coverage requires a model whose agent runtime is |
| 18 | + OpenClaw's embedded runtime. Instrument Claude Code itself through the |
| 19 | + [Anthropic plugin](/docs/ai-control-plane/distribute/plugins/anthropic) to |
| 20 | + cover the delegated path. |
| 21 | +</Callout> |
| 22 | + |
| 23 | +<Callout title="OpenClaw has no OTEL exporter" type="info"> |
| 24 | + Claude Code and Codex export OpenTelemetry alongside their hooks. OpenClaw has |
| 25 | + no equivalent, so every OpenClaw signal arrives through the observability |
| 26 | + plugin. Sessions, tool calls, token counts, cost, and policy enforcement all |
| 27 | + work; the OTEL-derived detail described in [What the plugin |
| 28 | + captures](#what-the-plugin-captures) does not apply. No Claude-side OTEL |
| 29 | + configuration is needed for OpenClaw. |
| 30 | +</Callout> |
| 31 | + |
| 32 | +## Access requirements |
| 33 | + |
| 34 | +<Callout type="info"> |
| 35 | + Downloading the observability plugin requires the `org:admin` scope, and so |
| 36 | + does creating the API key the CLI path uses. Both are held by the default |
| 37 | + [Admin role](/docs/ai-control-plane/org-admin/roles-and-permissions). |
| 38 | +</Callout> |
| 39 | + |
| 40 | +## Download the plugin package |
| 41 | + |
| 42 | +On the dashboard's **Distribute > Plugins** page, open the **Platform Plugins** section, select **openclaw**, and click **Download Plugin**. The download is a ZIP with a hooks-scoped API key already embedded, so no key needs to be created or exported separately. |
| 43 | + |
| 44 | +Extract it into a directory of its own: |
| 45 | + |
| 46 | +```bash |
| 47 | +unzip observability-openclaw.zip -d speakeasy-observability |
| 48 | +``` |
| 49 | + |
| 50 | +The package contains `openclaw.plugin.json`, which declares the plugin id `speakeasy-observability` and activates it on startup, `index.js`, which proxies OpenClaw's typed hooks to the hooks runtime, `package.json`, which registers `index.js` as the extension entry point, `speakeasy.json`, which carries the deployment identity and the embedded key, and the bootstrap scripts that fetch the hooks runtime on first run. |
| 51 | + |
| 52 | +## Render the package with the CLI |
| 53 | + |
| 54 | +Use this path when the package needs to be rendered from a script or checked into a repository template. Install the `speakeasy-hooks` binary: |
| 55 | + |
| 56 | +```bash |
| 57 | +curl -fsSL https://raw.githubusercontent.com/speakeasy-api/gram/main/hooks/install.sh | sh |
| 58 | +``` |
| 59 | + |
| 60 | +Create an API key with the **Hooks** scope on the [API keys](/docs/ai-control-plane/org-admin/api-keys) page, then render the package: |
| 61 | + |
| 62 | +```bash |
| 63 | +GRAM_HOOKS_ORG_KEY="<hooks-scoped-api-key>" \ |
| 64 | +speakeasy-hooks install --provider=openclaw --dir=./speakeasy-observability --project=<project-slug> |
| 65 | +``` |
| 66 | + |
| 67 | +Useful flags: |
| 68 | + |
| 69 | +- `--provider` β the agent to render for, `openclaw` here |
| 70 | +- `--dir` β where the package is written |
| 71 | +- `--project` β the project slug events are attributed to, defaulting to `default` |
| 72 | +- `--browser-login` β let each developer sign in through the browser so events record under their own identity rather than the organization key |
| 73 | + |
| 74 | +## Install the package into OpenClaw |
| 75 | + |
| 76 | +Register the rendered directory with the Gateway: |
| 77 | + |
| 78 | +```bash |
| 79 | +openclaw plugins install ./speakeasy-observability |
| 80 | +``` |
| 81 | + |
| 82 | +Conversation-scope hooks β prompt submission, model replies, and turn end β are gated behind a per-plugin flag. Until it is set, those hooks never fire and no error is reported. Grant it: |
| 83 | + |
| 84 | +```bash |
| 85 | +openclaw config set plugins.entries.speakeasy-observability.hooks.allowConversationAccess true |
| 86 | +``` |
| 87 | + |
| 88 | +OpenClaw loads plugins at startup only, so restart the Gateway to activate the hooks: |
| 89 | + |
| 90 | +```bash |
| 91 | +openclaw gateway restart |
| 92 | +``` |
| 93 | + |
| 94 | +<Callout type="warning"> |
| 95 | + A live session that records tool calls but no prompts, replies, or token |
| 96 | + usage is the signature of a missing `allowConversationAccess`. Set the flag |
| 97 | + and restart the Gateway. |
| 98 | +</Callout> |
| 99 | + |
| 100 | +## Roll out across a fleet |
| 101 | + |
| 102 | +The [device agent](/docs/ai-control-plane/org-admin/device-agent) installs and maintains the OpenClaw package on every enrolled machine and reapplies it every minute, so organizations running it can skip the manual steps above. It installs each assigned package under `~/.openclaw/extensions/<plugin-id>/` and forces two leaves in `~/.openclaw/openclaw.json` β `plugins.entries.<plugin-id>.enabled` and `plugins.entries.<plugin-id>.hooks.allowConversationAccess` β leaving every other value in the file intact. A developer who switches the plugin off has it re-enabled on the next tick. |
| 103 | + |
| 104 | +Two behaviors are worth setting expectations on: |
| 105 | + |
| 106 | +- The agent never restarts the Gateway. A newly installed extension stays dormant until the developer's next Gateway restart. |
| 107 | +- An extension directory the agent does not own β one a developer installed manually before management began β is never overwritten, though its config entry is still enforced. Removing the manual copy hands it to the agent on the next tick. |
| 108 | + |
| 109 | +The agent skips OpenClaw silently on machines where `~/.openclaw` does not exist. OpenClaw is managed by default wherever it is installed. To exclude it on a given fleet, set the `platforms` key in the agent's managed configuration: |
| 110 | + |
| 111 | +```json |
| 112 | +{ |
| 113 | + "platforms": { |
| 114 | + "openclaw": false |
| 115 | + } |
| 116 | +} |
| 117 | +``` |
| 118 | + |
| 119 | +Unlike Claude Code, Codex, Cursor, and GitHub Copilot, OpenClaw has no admin-layer enforcement mode today, so `"managed"` behaves as user-layer management. See the [device agent reference](/docs/ai-control-plane/reference/device-agent) for the full managed configuration. |
| 120 | + |
| 121 | +## Verify the installation |
| 122 | + |
| 123 | +Restart the Gateway, then run any tool call β an MCP tool, or a prompt such as `echo hi there`. Confirm both surfaces: |
| 124 | + |
| 125 | +- The call appears in [Tool Logs](/docs/ai-control-plane/observe/tool-logs). For a local tool call, set the **Type** filter to include local tools. |
| 126 | +- The conversation appears in [Agent Sessions](/docs/ai-control-plane/observe/agent-sessions) with **Agent type** filtered to openclaw. Transcripts require **Agent Session Capture** on the [Logging & Telemetry](/docs/ai-control-plane/org-admin/logging-and-telemetry) page. |
| 127 | + |
| 128 | +If tool calls arrive but prompts do not, check `allowConversationAccess`. If nothing arrives at all, check whether the model in use runs on OpenClaw's embedded runtime rather than the delegated Claude CLI path. |
| 129 | + |
| 130 | +## What the plugin captures |
| 131 | + |
| 132 | +The plugin translates OpenClaw's typed plugin hooks into the platform's canonical hook events: |
| 133 | + |
| 134 | +| OpenClaw hook | Recorded as | |
| 135 | +| ----------------------------------- | ------------------------------------------------------- | |
| 136 | +| `session_start`, `session_end` | Session start and end | |
| 137 | +| `before_agent_run` | User prompt | |
| 138 | +| `before_tool_call`, `after_tool_call` | Tool call and result | |
| 139 | +| `agent_end` | Assistant response, with the turn's token and cost usage | |
| 140 | +| `subagent_spawned`, `subagent_ended` | Subagent start and end | |
| 141 | +| `llm_input`, `llm_output` | Model request and response | |
| 142 | +| `before_compaction`, `after_compaction` | Context compaction | |
| 143 | + |
| 144 | +Prompt submission and tool calls are blocking, so a risk policy set to block denies the action in OpenClaw rather than only recording it, and [spend rules](/docs/ai-control-plane/observe/costs/budgets) deny prompts and tool calls once an actor is over budget. Tool results, errors, subagent lifecycle, model traffic, and compaction are recorded without blocking. A blocked tool call is recorded as an error rather than a success, even though OpenClaw reports the block through the same hook it uses for completed calls. |
| 145 | + |
| 146 | +Because there is no OTEL stream, a few details available for Claude Code are not available for OpenClaw: |
| 147 | + |
| 148 | +- No permission-request surface, so permission prompts are neither recorded nor gated β OpenClaw exposes approval only as a response to a tool-call gate |
| 149 | +- No skill source resolution or prompt attachment capture |
| 150 | +- No MCP inventory, so configured MCP servers are not reported as part of the session |
| 151 | +- [OTEL forwarding](/docs/ai-control-plane/org-admin/logging-and-telemetry/otel-forwarding) copies OTEL payloads only, so OpenClaw events are not forwarded to an external collector |
| 152 | + |
| 153 | +Token and cost totals are unaffected: OpenClaw reports usage at the end of each turn and the plugin forwards it, so [Costs](/docs/ai-control-plane/observe/costs) attributes OpenClaw spend normally. |
0 commit comments