> ## Documentation Index
> Fetch the complete documentation index at: https://docs.visiqlabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenClaw Integration

> Gate every OpenClaw tool call with VisIQ action governance, retrieval redaction, and the audit trail — one plugin, six hooks.

<Note>
  **Prerequisites.** A VisIQ account ([sign in](https://app.visiqlabs.com)) with a
  harness key from **Settings → Harness Keys**, and **OpenClaw `2026.5.18`+**.
  This CLI harness governs OpenClaw's own agent, so no separate model key is
  needed here. Hitting an error? See [Troubleshooting](/troubleshooting).
</Note>

`@visiq/openclaw-plugin` is an [OpenClaw](https://openclaw.com) plugin that routes
every tool call through VisIQ's action and retrieval governance and feeds the
audit trail. It installs from npm and requires OpenClaw `2026.5.18` or newer.

## What it does

The plugin registers six OpenClaw hooks:

| Hook                   | Behavior                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `before_tool_call`     | Governs **every** tool call with one evaluation. **deny** blocks the call with a `[VisIQ decision=deny code=<rule-code>]` reason; **approval required** routes it to OpenClaw's native approval queue (allow-once / allow-always / deny); **mask** runs the tool with the named arguments redacted. Retrieval tools additionally get the retrieval facet: **deny** blocks, **redact** queues a redaction spec, **escalate** prompts a human approval. |
| `tool_result_persist`  | Applies any queued redaction spec to the tool's output before it lands in the session transcript.                                                                                                                                                                                                                                                                                                                                                     |
| `before_message_write` | Defense-in-depth gate. If a redaction was queued but never applied, the message is dropped (fail-closed by design).                                                                                                                                                                                                                                                                                                                                   |
| `llm_input`            | Best-effort telemetry about each model call — metadata only (model, prompt length, message and tool counts), never prompt text.                                                                                                                                                                                                                                                                                                                       |
| `llm_output`           | Best-effort telemetry about each model response — segment counts and token usage, never assistant text.                                                                                                                                                                                                                                                                                                                                               |
| `session_end`          | Clears the plugin's per-session redaction state.                                                                                                                                                                                                                                                                                                                                                                                                      |

The retrieval facet is pre-seeded for ten tool names: `web_search`, `x_search`,
`web_fetch`, `tool_search`, `tool_describe`, `get_account`, `get_transactions`,
`get_devices`, `check_watchlist`, and `search_knowledge`. Namespaced tools
(`mcp__brave__web_search`) match on the segment after the last `__`. The set is
a fast-path default, not a governance boundary — tools outside it still get
full action governance on every call.

Decisions evaluate in-process against the agent's rule bundle, which the plugin
pre-warms before the first call — registering a human approval is the only decision-path network call. New agents
auto-provision in **monitor** mode on first contact: every decision is
evaluated and recorded, but nothing is blocked until you switch the agent to
enforce (see [Verifying the install](#verifying-the-install)).

## Interactive setup

You need a harness API key (`vq_test_` or `vq_prod_`). The guided setup on the
**OpenClaw** card under **Integration → Connectors** mints a scoped key for you;
you can also create one under **Settings → Harness Keys**. Then install and
configure the plugin:

```bash theme={null}
openclaw plugins install @visiq/openclaw-plugin --dangerously-force-unsafe-install
export VISIQ_API_KEY=<your-api-key>
export VISIQ_AGENT_ID=<your-agent-id>
openclaw gateway run --auth none --bind loopback --port 18789
```

The plugin's `VISIQ_BASE_URL` / `VISIQ_ENDPOINT` defaults to
`https://api.visiqlabs.com` — set it only for cloud / onprem (sovereign)
deployments. On SaaS a bare API key is all you need.

<Note>
  The `--dangerously-force-unsafe-install` flag is required. OpenClaw's install
  scanner blocks any plugin that reads environment variables **and** makes network
  calls, flagging it as "possible credential harvesting". The VisIQ plugin does
  exactly that **by design** — it reads `VISIQ_API_KEY` and sends governance
  decisions to your VisIQ backend — so this is an expected false positive for a
  governance plugin. Without the flag the install is hard-blocked.
</Note>

`openclaw gateway run` runs the gateway in the foreground and serves the
Control UI at `http://localhost:18789`. To run it as a background service
(launchd / systemd / schtasks) instead:

```bash theme={null}
openclaw daemon install && openclaw daemon start
```

## Automated / CI setup

For pipelines, containers, and anywhere without an interactive TTY, supply
credentials via environment variables and run the gateway headless:

```bash theme={null}
VISIQ_API_KEY=vq_prod_... \
VISIQ_AGENT_ID=my-agent \
openclaw gateway run
```

Optional:

```bash theme={null}
VISIQ_CONFIG_PATH=/etc/visiq/config.json   # alternate JSON file
```

## Persisting credentials (the durable channel)

An exported variable only reaches a gateway **you** launch from that same shell.
For a gateway that is already running — a service, a supervised process, anything
you did not start yourself — the credentials must live in
`~/.openclaw/openclaw.json`. `openclaw setup` has already created that file, so
**add** the plugin entry rather than replacing it:

```bash theme={null}
CFG="$HOME/.openclaw/openclaw.json"
mkdir -p "$(dirname "$CFG")"
[ -s "$CFG" ] || echo '{}' > "$CFG"
jq '.plugins.entries["@visiq/openclaw-plugin"] = {
      "enabled": true,
      "config": { "apiKey": "vq_prod_...", "agentId": "my-agent",
                  "baseUrl": "https://visiq.internal.example" },
      "hooks": { "allowConversationAccess": true }
    }' "$CFG" > "$CFG.new" && mv "$CFG.new" "$CFG"
```

(`baseUrl` is only needed for cloud / onprem — on SaaS the plugin defaults to the
managed control plane.)

The package also ships a `configure` helper that does the same merge for you —
`VISIQ_CONFIGURE_NONINTERACTIVE=1 VISIQ_API_KEY=… VISIQ_AGENT_ID=… npx -y
@visiq/openclaw-plugin configure` — and additionally registers the plugin on
`plugins.load.paths`. <Warning>Versions **up to and including 0.1.15** exit 0
without writing anything when launched through a package manager (`npx`, `pnpm
exec`, a global bin): the entry check compared `import.meta.url` against
`process.argv[1]`, which is the `bin` shim, so `main()` never ran. Fixed in
**0.1.16**. On an older version, use the `jq` merge above, or invoke the module
directly: `node node_modules/@visiq/openclaw-plugin/dist/cli/configure.js`.</Warning>

Verify with the same predicate the gateway uses — not by eyeballing the file:

```bash theme={null}
jq -e '.plugins.entries["@visiq/openclaw-plugin"].config
       | .apiKey and .agentId and .baseUrl' "$HOME/.openclaw/openclaw.json"
```

<Warning>
  The plugin entry lives **three levels down** — `plugins` → `entries` →
  `"@visiq/openclaw-plugin"`. A config whose *top-level* key is
  `"@visiq/openclaw-plugin"` is the most common hand-edit mistake, and the gateway
  ignores it completely: the plugin starts credential-less and silently no-ops every
  hook. A `cat` of such a file still shows the API key, the agent id and the base URL,
  which is why the `jq -e` check above is the one to trust. After changing the file,
  **restart** the gateway — a hot config reload does not pick up new credentials.
</Warning>

The resulting file looks like this (the helper writes it for you):

```json theme={null}
{
  "plugins": {
    "entries": {
      "@visiq/openclaw-plugin": {
        "enabled": true,
        "config": {
          "apiKey": "vq_prod_...",
          "agentId": "my-agent",
          "baseUrl": "https://visiq.internal.example"
        },
        "hooks": { "allowConversationAccess": true }
      }
    }
  }
}
```

## Credential resolution precedence

The plugin resolves credentials in this order (highest priority first):

1. CLI flags: `--api-key` / `--agent-id` / `--base-url`
2. Environment variables: `VISIQ_API_KEY` / `VISIQ_AGENT_ID` / `VISIQ_BASE_URL`
   (`VISIQ_ENDPOINT` is accepted as a base-URL fallback; `VISIQ_BASE_URL` wins
   when both are set)
3. JSON file at the path in `VISIQ_CONFIG_PATH`
4. `~/.openclaw/openclaw.json` → `plugins.entries["@visiq/openclaw-plugin"].config`
5. Interactive prompt (only when both stdout and stdin are terminals)

## Fail-open vs fail-closed

The plugin defaults to **fail-open**: a VisIQ-side failure never disrupts
OpenClaw. Set `VISIQ_FAIL_MODE=closed` (in the environment or the plugin config)
to make those failures **block** instead.

* **Unconfigured (missing credentials)**: every hook no-ops. A single structured
  warning is emitted to stderr explaining how to configure the plugin — the
  plugin should never break OpenClaw on first install before credentials are
  provisioned.
* **Governance evaluation errors** (an unreachable backend, the governance core
  unavailable, a thrown evaluation): by **default** the tool call proceeds
  **ungoverned** with a loud `[VisIQ] FAIL-OPEN` stderr report, so a VisIQ outage
  never breaks the agent. Set `VISIQ_FAIL_MODE=closed` to **block** on those
  errors instead. Real policy outcomes always enforce regardless of failMode: an
  explicit rule **deny**, the operator kill-switch, and a queued redaction that
  cannot be applied (it downgrades to deny — see `before_message_write` above)
  all block.
* **Telemetry errors**: never affect agent behavior. Failures are logged to
  stderr and swallowed — telemetry is best-effort.

## Verifying the install

Start the gateway and trigger a `web_search`. In the dashboard at
[app.visiqlabs.com](https://app.visiqlabs.com), the agent appears under
**Harness → Agents** tagged as a CLI Harness, and the decision appears in the
**Harness → Runtime Enforcement** ledger. Governed decisions feed the audit
trail, including [signed decision receipts](/record/receipts).

When the recorded decisions look right, open the agent on the Agents page and
switch its mode from **Monitor — Log only** to **Enforce — Block**. The mode is
server-authoritative and per-agent; the plugin picks it up with its next rule
bundle refresh.
