OC

OpenClaw & Airlock Gateway

Install and configure the Airlock plugin for human-in-the-loop approval of AI tool actions in OpenClaw

Enterprise deployment. Configure integrations against your organization's Gateway at https://<your-gateway-host> and identity at https://<your-auth-host>/realms/<your-realm>. See the Getting started and Developer Guide.

Overview

The @airlockapp/openclaw-airlock package adds Airlock Gateway integration to an OpenClaw-compatible agent runtime. It can intercept configured tools before they run, send encrypted approval requests to your organization's Mobile Approver, and verify signed decisions. Pairing uses pre-generated codes and X25519 ECDH; payloads use AES-256-GCM per the HARP model used across Airlock clients.

For an end-to-end scenario (Telegram bot, consent, pairing, and sample approvals), see the OpenClaw + Telegram demo.

Prerequisites

  • OpenClaw installed and running (for example via the DigitalOcean Marketplace).
  • Enterprise credentials — enforcer app Client ID/Secret from your administrator, Gateway URL https://<your-gateway-host>, and PAT.
  • Mobile Approver — distributed via your organization (MDM or internal catalog).
  • Node.js 18+ for npm install or building from source.

For enterprise deployment, enforcer apps, and tokens, see the Developer Guide and Airlock Apps.

1. Install the plugin

Option A: Install from npm (recommended)

On the OpenClaw host, create an extensions directory and install the package (replace <server-ip> with your server address):

ssh root@<server-ip> "mkdir -p ~/.openclaw/extensions/airlock && cd ~/.openclaw/extensions/airlock && npm init -y && npm install @airlockapp/openclaw-airlock"

Alternatively, install directly from your OpenClaw workspace:

openclaw plugins install @airlockapp/openclaw-airlock

Package: npmjs.com/package/@airlockapp/openclaw-airlock

Option B: Build from source

From the Airlock monorepo layout (this matches the openclaw-airlock package source tree):

cd gateway_sdk/src/openclaw-airlock
npm install
npm run build

From a clone of airlockapp/gateway-clients, use:

cd src/openclaw-airlock
npm install
npm run build

This produces the dist/ directory with compiled JavaScript.

2. Deploy to the server

If you used Option A, the files are already on the server — continue to configuration. If you built from source (Option B), copy the extension to the host:

# Create the extension directory
ssh root@<server-ip> "mkdir -p /root/.openclaw/extensions/airlock"

# Copy the required files
scp -r dist package.json openclaw.plugin.json node_modules \
  root@<server-ip>:~/.openclaw/extensions/airlock/

# Fix file ownership (required — OpenClaw blocks plugins with unexpected ownership)
ssh root@<server-ip> "chown -R root:root ~/.openclaw/extensions/airlock/"

Dual-user setup (DigitalOcean)

On some droplets the CLI runs as root while the service runs as the openclaw user. Both home trees need the extension files:

ssh root@<server-ip> "
  cp -r /root/.openclaw/extensions/airlock /home/openclaw/.openclaw/extensions/
  chown -R openclaw:openclaw /home/openclaw/.openclaw/extensions/airlock
"

3. Configure the plugin

Edit OpenClaw config at ~/.openclaw/openclaw.json and add the Airlock plugin under plugins.entries. See openclaw.plugin.json for the full schema.

{
  "plugins": {
    "entries": {
      "airlock": {
        "enabled": true,
        "config": {
          "gatewayUrl": "https://<your-gateway-host>",
          "enforcerId": "<your-enforcer-id>",
          "pat": "<your-personal-access-token>",
          "clientId": "<your-client-id>",
          "clientSecret": "<your-client-secret>",
          "pairingCode": "<your-pairing-code>",
          "protectedTools": [
            "exec",
            "shell.*",
            "computer.*",
            "*"
          ]
        }
      }
    }
  }
}

Configuration reference

Field Required Description
gatewayUrlYesAirlock Gateway URL (default https://<your-gateway-host>)
enforcerIdYesStable enforcer identifier (e.g. my-enforcer-001)
patYesPersonal Access Token from the Airlock dashboard (airpat_…)
clientIdYesEnforcer app Client ID
clientSecretYesEnforcer app Client Secret
pairingCodeYes*Pre-generated pairing code until openclaw airlock pair completes. *Only required before initial pairing.
protectedToolsNoTool name patterns to gate (wildcards such as shell.*). OpenClaw's built-in shell tool is named exec internally — add "exec" or use "*" for all tools. If empty, use the explicit airlock_request_approval tool.
failModeNoclosed (default, block on failure) or open (allow on failure)
workspaceNameNoLabel shown in the Mobile Approver (default OpenClaw Workspace)
timeoutMsNoApproval wait timeout (default 300000)
pollIntervalMsNoDecision poll interval, minimum 1000 (default 3000)
executionModeNopoll (supported); webhook reserved for future use

Important: If OpenClaw runs as different users, update config in both /root/.openclaw/openclaw.json and /home/openclaw/.openclaw/openclaw.json where applicable.

4. Restart the service

systemctl restart openclaw

# Verify the plugin loaded:
journalctl -u openclaw --no-pager | grep -i airlock
# Expected: [Airlock] Plugin loaded — enforcer=<id>, failMode=closed, protectedTools=...

5. Grant user consent

Before pairing, the gateway may require the user to consent to this enforcer app. Run:

openclaw airlock consent

This calls GET /v1/consent/status, triggers a push to the Mobile Approver, and polls about every 5 seconds for up to 5 minutes until approved.

6. Pair the enforcer

After consent is granted, pair with the Mobile Approver:

openclaw airlock pair

This verifies consent, claims the pairing code from config, completes X25519 ECDH, and persists the routing token and encryption material to ~/.openclaw/.airlock/pairing-state.json.

7. Verify setup

openclaw airlock setup

You should see gateway connectivity, consent status, pairing status, and the list of protected tools. In chat, /airlock-status summarizes connectivity, pairing, and protected tools.

CLI command reference

Command Description
openclaw airlock setupValidate config, test connectivity, show consent and pairing status
openclaw airlock consentTrigger user consent flow and poll until approved
openclaw airlock pairClaim pairing code and establish the encrypted channel

How it works

With protectedTools configured, matching tool calls are held until the approver decides or the request times out. Do Not Disturb policies on the gateway can auto-approve matching requests.

  1. The agent requests a tool (for example shell.exec).
  2. Airlock encrypts the payload (AES-256-GCM) and submits it to the gateway.
  3. The user receives a push notification in the Airlock app.
  4. The user approves or rejects.
  5. The plugin applies the decision and allows or blocks the tool call.
Agent ──► Airlock Plugin ──► Airlock Gateway ──► Mobile Approver
                                                    │
Agent ◄── Airlock Plugin ◄── Airlock Gateway ◄── approve/reject

Explicit tools

The agent can call airlock_request_approval for a dedicated approval round-trip and airlock_check_status for a prior request ID.

Persistence

Pairing state is stored at ~/.openclaw/.airlock/pairing-state.json and includes the routing token, derived encryption key, and enforcer identity. It survives service restarts; re-pair only if pairing is revoked.

Fail modes

With failMode: "closed" (default), timeouts and gateway errors block execution; "open" allows through in those cases. Revoked or stale pairing and quota errors are blocked regardless of fail mode.

Security notes

  • E2EE uses X25519 + HKDF and AES-256-GCM; the gateway routes ciphertext only.
  • Approver decisions can be verified with Ed25519 when signatures are present.
  • Implementation uses @airlockapp/gateway-sdk; see TypeScript SDK for the same APIs outside OpenClaw.

Troubleshooting

  • Plugin not loading — suspicious ownership — OpenClaw rejects plugin files not owned by root. Fix with: chown -R root:root ~/.openclaw/extensions/airlock/ then restart. This commonly happens when files are uploaded from a non-root system.
  • Plugin id mismatch warning — Message such as plugin airlock: plugin id mismatch is cosmetic; the plugin can still load.
  • Not paired after restart — Ensure extension files exist for both users where applicable: /root/.openclaw/extensions/airlock/ (CLI) and /home/openclaw/.openclaw/extensions/airlock/ (service).
  • No approver available (pairing stale) — The pairing was revoked from the Mobile Approver. Generate a new pre-generated code, update pairingCode in config, then run openclaw airlock pair again.
  • Access denied: pairing_revoked — The Mobile Approver user revoked the pairing. The plugin automatically clears stale state. Generate a new code and re-pair.
  • Approval timed out — The approver did not respond within the timeout. Increase timeoutMs if needed, or check the Mobile Approver is reachable.
  • Consent denied — Re-authorize in the Mobile Approver, then run openclaw airlock consent again.
  • Gateway connectivity — Run openclaw airlock setup and test the gateway directly:
curl -s https://<your-gateway-host>/echo
  • Rate limiting — After repeated auth failures, wait about 5 minutes before retrying.
  • New pairing code — Codes are single-use. Generate a new one in your enterprise admin console (Pre-generated Codes) or the Mobile Approver, update pairingCode in config, then run openclaw airlock pair.
  • Tools not intercepted — OpenClaw's built-in shell execution tool is named exec internally (not bash or shell.exec). Add "exec" to protectedTools, or use "*" to intercept all tools. Use the explicit airlock_request_approval tool for cases where pattern matching isn't sufficient.

Architecture, diagrams, and development commands: package README on GitHub.

Related documentation