@goplausible/ac2-plugin-openclaw
v0.0.68
Published
OpenClaw Channel Plugin — connects OpenClaw gateway to AC2 peers over WebRTC
Downloads
4,449
Readme
@goplausible/ac2-plugin-openclaw
| Component | Version |
| --- | --- |
| @goplausible/ac2-plugin-openclaw (this) | 0.0.67 |
| @goplausible/ac2-sdk (resolved from npm) | ^0.0.8 |
| regent (matching controller wallet) | 1.0.91 |
The plugin is published on npm. See Plugin lifecycle for install/update/uninstall and Post-install setup for the one-shot config command you run after every install or update.
v0.0.39 (current) — removed the shell-environment override knobs added in v0.0.35. Their reads tripped OpenClaw's plugin security audit again under the credential-harvesting heuristic. CLI-vs-gateway detection is now pure-argv: extend the gateway-subcommand set in
index.tsif a future OpenClaw command needs to count as gateway. All configuration goes throughopenclaw.jsonexclusively; no shell-environment reads anywhere in the plugin.
v0.0.38 — sig_hint ↔ verifier matrix is now complete. Three new transaction verifiers added:
ac2_verify_transaction_algorand(algosdk-based, decodes SignedTxn msgpack and Ed25519-verifies against the sender),ac2_verify_transaction_evm(viemrecoverTransactionAddress, handles EIP-1559/2930/legacy/4844 types),ac2_verify_transaction_solana(legacy + versioned, Ed25519 against static-account-key signer slots). Plugin grew by ~5 MB unpacked to bundlealgosdk,viem,@solana/web3.js; the chain SDKs are used purely as math libraries — no network calls.
v0.0.37 — two-field signing model per AC2 spec §
ac2/SigningRequest.display_hintis the spec-stable UX preview hint (text/json/hex), andsig_hintis the new explicit cryptographic-operation selector (raw-ed25519/raw-secp256k1/message-algorand/message-evm/message-solana/typed-data-evm/transaction-algorand/transaction-evm/transaction-solana). Verifier tools renamed 1:1 with sig_hint values:ac2_verify_raw_ed25519,ac2_verify_raw_secp256k1(NEW),ac2_verify_message_algorand(wasac2_verify_arc60),ac2_verify_message_evm(wasac2_verify_eip191),ac2_verify_message_solana(NEW),ac2_verify_typed_data_evm(NEW). See the AC2 spec (specs/ac2.md§ac2/SigningRequest) for the fullsig_hintmatrix.
v0.0.36 — sign tool overhauled to expose the full
display_hintenum (text/json/hex/message/typed-data/transaction) with accurate descriptions of the per-chain matrix and compatibility rules withkey_type. Three new verify tools shipped:ac2_verify_ed25519(now acceptsdid:key:z…DIDs as well as raw-bytes pubkeys),ac2_verify_arc60(Ed25519 with ARC-60MXprefix for AVM message sigs),ac2_verify_eip191(secp256k1 ecrecover for EVM personal-sign).v0.0.35 — the plugin detects whether it's being loaded for the long-running gateway or for a one-shot CLI command, and skips the auto-resume / auto-relisten loop in CLI mode. Without this, the open Liquid Auth WebSocket kept Node's event loop alive after the CLI command completed, hanging foreign CLI invocations (e.g.
openclaw plugins uninstall <other-plugin>) indefinitely. Detection is pure-argv; if the heuristic misfires on a new OpenClaw subcommand, extend the gateway subcommand set inindex.ts.
OpenClaw Channel Plugin that connects an OpenClaw gateway to an AC2 controller (peer) over Liquid Auth signaling + WebRTC. Built on top of @goplausible/ac2-sdk.
A controller (e.g. a wallet client) pairs with this OpenClaw agent once. After that the link is self-healing: the plugin auto-listens on startup and auto-relistens after any disconnect. Detection runs on five layers — dataChannel.onclose, iceConnectionState ∈ {failed, closed}, an 8 s iceConnectionState=disconnected stall, a 60 s inbound-activity watchdog (catches suspended-peer cases where ICE state never transitions), and a sub-second signaling.signalClient.disconnect/error event subscription on the agent's WebSocket. The retry loop runs with bounded backoff ([500 ms, 1 s, 2 s, 5 s], capped at 5 s) so the listener is in the DO room ≥99 % of the time.
The controller persists its requestId for 7 days and reconnects automatically. One controller per plugin instance — the controller may be paired with many other agents in parallel, but each agent sees one controller.
Commands
Slash (/ac2 …) — inside an OpenClaw session
| Command | What it does |
|---|---|
| /ac2 pair | Show a QR + deep link for the controller to scan. First-time pairing if unpaired; rotates to a fresh requestId if paired-but-offline (replaces the removed connect). Returns Already online (peer=…) if a session is currently active. |
| /ac2 pair cancel | Abort an in-flight pairing invitation. |
| /ac2 status | Show pairing record, online state, signaling server, agent DID. |
| /ac2 forget | Drop the pairing record from disk; channel returns to unpaired. |
Shell (openclaw ac2 …)
The shell CLI exits as soon as the action returns, which would tear down the pairing WebSocket — so pair is only available as a slash command. The shell surface is intentionally read/write-once:
openclaw ac2 # full command reference (bare invocation prints help)
openclaw ac2 setup # apply OpenClaw config required for the plugin (idempotent)
openclaw ac2 status # prints state + exits
openclaw ac2 forget # drops pairing + exits
openclaw ac2 version # plugin + bundled SDK versions
openclaw ac2 helpdoes NOT work — OpenClaw's CLI parser interceptshelpas a special token before our handler runs. Use bareopenclaw ac2instead.
Plugin lifecycle
Every command below requires a gateway restart afterwards (cd ~ && openclaw gateway restart) — OpenClaw caches plugin state and only re-reads it on gateway boot.
Install
openclaw plugins install @goplausible/ac2-plugin-openclaw
openclaw ac2 setup
cd ~ && openclaw gateway restartUpdate
openclaw plugins update ac2-plugin-openclaw
openclaw ac2 setup
cd ~ && openclaw gateway restartUninstall
openclaw plugins uninstall ac2-plugin-openclaw
cd ~ && openclaw gateway restartUninstall does NOT remove the plugin's on-disk state at
~/.openclaw/plugins/ac2-plugin-openclaw/(peer record, agent keypair, pending invitations, active-session marker). If you reinstall later, the peer record auto-resumes pairing. To wipe everything:openclaw plugins uninstall ac2-plugin-openclaw rm -rf ~/.openclaw/plugins/ac2-plugin-openclaw cd ~ && openclaw gateway restartUninstall also leaves the openclaw.json config entries (plugins.allow, channels.ac2, bindings, tools.alsoAllow) — these are harmless and
openclaw ac2 setupis idempotent if you reinstall.
Post-install setup
openclaw ac2 setup is idempotent — safe to re-run after every install/update. It applies the 5 OpenClaw config changes required for the plugin to function:
| Setting | What it does |
|---|---|
| plugins.allow += "ac2-plugin-openclaw" | Marks the plugin as explicitly trusted (suppresses untracked-code warnings). |
| plugins.entries.ac2-plugin-openclaw.enabled = true | Enables the plugin entry. |
| channels.ac2.liquidAuthServer = https://liquidauth.goplausible.xyz | Picks the default signaling server (override in openclaw.json if you self-host). |
| bindings += { agentId: "main", match: { channel: "ac2" } } | Routes the main agent to AC2 inbound. Adjust agentId if you use a non-default agent. |
| tools.alsoAllow += [10 × ac2_* tool names] | Exposes the agent-callable signing/verification tools regardless of the active tools.profile (coding/messaging/minimal/full). tools.alsoAllow bypasses profile filtering; tools.allow does not. |
Each setting prints ✓ applied, = already in place, or ✗ failed so you see exactly what changed.
For live plugin diagnostics (handshake events, ICE state changes, auto-relisten attempts, etc.), run the OpenClaw gateway in the foreground — its stdout carries the [ac2] … traces directly. The structured-logger subset (plugin registration, command results) also lands in /tmp/openclaw/openclaw.log if you prefer to tail a file.
connect and disconnect were removed in v0.0.19 — auto-listen-on-startup + auto-relisten cover the recovery story; pair covers the rotate-requestId case formerly served by connect.
Agent tools
The plugin registers two agent-callable tools via api.registerTool:
| Tool | Behavior |
|---|---|
| ac2_sign_ed25519 | Sends an ac2/SigningRequest to the paired controller. The controller (e.g. Regent) shows an approval modal, gates on a passkey/biometric, signs the raw bytes with its Ed25519 account key, and returns signature, publicKey, optional address, keyType. HITL — never autonomous. |
| ac2_verify_ed25519 | Local-only verification using @noble/ed25519. Inputs are base64 (message, signature, publicKey); returns { valid: boolean }. |
Inputs/outputs are base64 throughout for clean transmission. See src/tools.ts for the typebox schemas.
Configuration
In ~/.openclaw/openclaw.json:
{
"plugins": {
"allow": ["ac2-plugin-openclaw"],
"entries": {
"ac2-plugin-openclaw": {
"config": {
"liquidAuthServer": "https://liquidauth.goplausible.xyz",
"agentDid": "did:web:openclaw.local"
}
}
}
}
}Precedence for both fields: explicit config in openclaw.json → fallback.
| Field | Fallback |
| --- | --- |
| liquidAuthServer | https://liquidauth.goplausible.xyz |
| agentDid | Auto-generated did:key:z... (Ed25519); persisted at ~/.openclaw/plugins/ac2-plugin-openclaw/agent-key.json and reused on subsequent runs |
So the plugin works out of the box with zero config — the agent gets a fresh did:key on first install. Override only if you need a specific identity (e.g., did:web:... published at a known host).
Note — shell-environment reads were removed from this plugin in v0.0.20 (and further reduced in v0.0.34 to silence OpenClaw's substring-matched security audit). Configure via
openclaw.jsoninstead.
Persistence
The paired peer is stored at ~/.openclaw/plugins/ac2-plugin-openclaw/peer.json (mode 0o600):
{
"peerDid": "did:key:z6Mk...",
"walletAddress": "ALGORAND_BASE32_ADDRESS",
"pairedAt": 1714230000000,
"lastConnectedAt": 1714233600000,
"lastRequestId": "01HXX..."
}lastRequestId is what makes auto-listen-on-startup work: on plugin boot the manager re-enters the same Liquid Auth WalletRoom and Regent's persisted session reaches it without rescanning a QR. /ac2 forget deletes the file. The plugin's own Ed25519 keypair is at agent-key.json (0o600) in the same directory.
Wire format
v0 runs in lenient/text mode: chat traffic is plain text on the existing liquid data channel from liquid-auth-js, with a JSON discriminator overlay for typed AC2 messages. The plugin recognizes:
| OpenClaw flow | AC2 frame | v0 status |
|---|---|---|
| Inbound user text | plain string (or ac2/StreamRequest JSON, body.text extracted) | ✅ |
| Outbound agent reply | plain string via dispatchReplyWithBufferedBlockDispatcher | ✅ |
| ac2_sign_ed25519 tool | ac2/SigningRequest → ac2/SigningResponse / ac2/SigningRejected | ✅ |
| Streaming chunks | ac2/StreamResponse + ac2/StreamChunk | deferred |
| File transfer | ac2/AttachmentBegin + binary on ac2-data | deferred (single-channel POC) |
| Generic tool HITL | ac2/ApprovalRequest / Response / Rejected | deferred |
The conversationId in OpenClaw's session model = the controller's DID.
When the controller becomes AC2-native (Path A), this overlay is replaced by full envelope wrapping via AC2Session + PlainEnvelope.
Versioning + publishing
The plugin pulls @goplausible/ac2-sdk from npm as a regular transitive dependency — there is no more bundleDependencies / manual-SDK-materialization dance (retired in v0.0.33 once the SDK landed on npm publicly).
Three version sites must move in lockstep when bumping:
packages/ac2-plugin-openclaw/package.json—"version"openclaw.plugin.json—"version"(THIS is the field OpenClaw caches by)- Root
package-lock.json—packages/ac2-plugin-openclawnested entry's"version"
Plus this README's version banner at the top.
Build & publish:
# From repo root.
npm run build --workspaces --if-present # SDK build (and any other workspace builds)
( cd packages/ac2-plugin-openclaw && npm pack --pack-destination ../../dist-packs )
( cd packages/ac2-plugin-openclaw && npm publish )
# publishConfig.access=public is set in the plugin's package.json — no --access flag needed.Output: dist-packs/goplausible-ac2-plugin-openclaw-<version>.tgz (~10 KB, ~80 KB smaller than the bundled era).
Install on an OpenClaw host:
# Primary path: pull from npm.
openclaw plugins install @goplausible/ac2-plugin-openclaw
# Fallback for air-gapped hosts: tarball install.
openclaw plugins install /path/to/goplausible-ac2-plugin-openclaw-<version>.tgzThe npm-published tarball and the dist-packs/ tarball are bit-for-bit identical (the publish step takes whatever npm pack produced).
License
Apache-2.0
