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-airlockPackage: 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 buildFrom 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 |
|---|---|---|
gatewayUrl | Yes | Airlock Gateway URL (default https://igw.airlocks.io) |
enforcerId | Yes | Stable enforcer identifier (e.g. my-enforcer-001) |
pat | Yes | Personal Access Token from the Airlock dashboard (airpat_…) |
clientId | Yes | Enforcer app Client ID |
clientSecret | Yes | Enforcer app Client Secret |
pairingCode | Yes* | Pre-generated pairing code until openclaw airlock pair completes. *Only required before initial pairing. |
protectedTools | No | Tool 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. |
failMode | No | closed (default, block on failure) or open (allow on failure) |
workspaceName | No | Label in the mobile app (default OpenClaw Workspace) |
timeoutMs | No | Approval wait timeout (default 300000) |
pollIntervalMs | No | Decision poll interval, minimum 1000 (default 3000) |
executionMode | No | poll (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 setup | Validate config, test connectivity, show consent and pairing status |
openclaw airlock consent | Trigger user consent flow and poll until approved |
openclaw airlock pair | Claim 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.
- The agent requests a tool (for example
shell.exec). - Airlock encrypts the payload (AES-256-GCM) and submits it to the gateway.
- The user receives a push notification in the Airlock app.
- The user approves or rejects.
- 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 mismatchis 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
pairingCodein config, then runopenclaw airlock pairagain. - 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
timeoutMsif needed, or check the approver mobile app is reachable. - Consent denied — Re-authorize in the mobile app, then run
openclaw airlock consentagain. - Gateway connectivity — Run
openclaw airlock setupand 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
pairingCodein config, then runopenclaw airlock pair. - Tools not intercepted — OpenClaw's built-in shell execution tool is named
execinternally (notbashorshell.exec). Add"exec"toprotectedTools, or use"*"to intercept all tools. Use the explicitairlock_request_approvaltool for cases where pattern matching isn't sufficient.
Architecture, diagrams, and development commands: package README on GitHub.
Related documentation
- OpenClaw + Telegram demo — Telegram bot, consent, pairing, and sample approval flows.
- Developer Guide — platform, gateway, and lifecycle.
- Airlock Apps — client ID, secrets, and consent concepts.
- Gateway Client SDKs — including TypeScript.
- Claude Code Enforcer — related IDE-style enforcement pattern.
- HARP specification ↗