OC

OpenClaw & Airlock Gateway

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

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 the Airlock mobile app (Google Play), 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).
  • Airlock account with an enforcer app configured at airlockapp.io.
  • Airlock mobile app on your phone.
  • Node.js 18+ for npm install or building from source.

For the developer programme, 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://igw.airlocks.io",
          "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://igw.airlocks.io)
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 in the mobile app (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 Airlock mobile app, 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 app:

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 App
                                                    │
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 app. Generate a new pre-generated code, update pairingCode in config, then run openclaw airlock pair again.
  • Access denied: pairing_revoked — The mobile app 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 approver mobile app is reachable.
  • Consent denied — Re-authorize in the mobile app, then run openclaw airlock consent again.
  • Gateway connectivity — Run openclaw airlock setup and test the gateway directly:
curl -s https://igw.airlocks.io/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 the Airlock dashboard (Pre-generated Codes) or the mobile app, 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