npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@goplausible/ac2-plugin-openclaw

v0.0.111

Published

OpenClaw Channel Plugin — connects OpenClaw gateway to AC2 peers over WebRTC

Readme

@goplausible/ac2-plugin-openclaw

| Component | Version | | --- | --- | | @goplausible/ac2-plugin-openclaw (this) | 0.0.111 | | @goplausible/ac2-sdk (resolved from npm) | ^0.0.8 | | regent (matching controller wallet) | 1.1.21 |

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.

See version history for the full per-release changelog.


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.

Install & setup

Experimental — preview. This OpenClaw plugin and the AC2 SDK are experimental. Issues and frictions are expected — please send issues on GitHub.

# Step 1: Install or update the plugin (from npm registry)
openclaw plugins install @goplausible/ac2-plugin-openclaw
# OR
openclaw plugins update ac2-plugin-openclaw

# Step 2: Restart the gateway
openclaw gateway restart

# Step 3: Launch interactive setup wizard (enables/disables x402 toggle)
openclaw ac2 setup

# Step 4: Restart the gateway
openclaw gateway restart

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 help does NOT work — OpenClaw's CLI parser intercepts help as a special token before our handler runs. Use bare openclaw ac2 instead.

Plugin lifecycle

Install/update require a gateway restart so OpenClaw reloads the package, then openclaw ac2 setup, then one more restart so the generated config is active.

Install

openclaw plugins install @goplausible/ac2-plugin-openclaw
openclaw gateway restart
openclaw ac2 setup
openclaw gateway restart

Update

openclaw plugins update ac2-plugin-openclaw
openclaw gateway restart
openclaw ac2 setup
openclaw gateway restart

Uninstall

openclaw plugins uninstall ac2-plugin-openclaw
cd ~ && openclaw gateway restart

Uninstall 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 restart

Uninstall also leaves the openclaw.json config entries (plugins.allow, channels.ac2, bindings, tools.alsoAllow) — these are harmless and openclaw ac2 setup is 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 12 agent-callable tools via api.registerTool. One discovery tool (ac2_capabilities — handshake-based, no signing), one sign tool (HITL through the paired controller), one proactive send tool (ac2_send), and nine local-only verifiers covering the AC2 spec's full sig_hint matrix:

| Tool | sig_hint | Behavior | |---|---|---| | ac2_capabilities | (n/a) | Sends ac2/CapabilityRequest to the paired controller and returns its descriptor: version, features, signing identities (public keys / DIDs), and on-chain accounts grouped by blockchain. Pure discovery — no approval modal, no signing. Call before ac2_sign to pick a real address and a wallet-supported sig_hint. | | ac2_sign | (all) | Sends ac2/SigningRequest to the paired controller. Controller (e.g. Regent) shows an approval modal, gates on passkey/biometric, signs with the user-selected key, and returns signature + publicKey (+ optional address, keyType). HITL — never autonomous. | | ac2_send | (n/a) | Proactively sends a chat message to the paired wallet user without waiting for an inbound message — for scheduled/heartbeat/cron turns or unprompted notes mid-task. Replies to an inbound message do not need this (they auto-deliver). Fire-and-forget; reaches the user via FCM push when the WebRTC link is down. | | ac2_verify_raw_ed25519 | raw-ed25519 | Local Ed25519 verify via @noble/curves. Accepts raw-bytes pubkey or did:key:z…. | | ac2_verify_raw_secp256k1 | raw-secp256k1 | Local secp256k1 verify via @noble/curves. | | ac2_verify_message_algorand | message-algorand | ARC-60 message verify (Ed25519 with MX prefix). | | ac2_verify_message_evm | message-evm | EIP-191 personal-sign verify (secp256k1 ecrecover via viem). | | ac2_verify_message_solana | message-solana | Ed25519 message verify against a Solana address. | | ac2_verify_typed_data_evm | typed-data-evm | EIP-712 typed-data verify via viem. | | ac2_verify_transaction_algorand | transaction-algorand | Decodes SignedTxn msgpack via algosdk, Ed25519-verifies against the sender. | | ac2_verify_transaction_evm | transaction-evm | viem.recoverTransactionAddress — handles EIP-1559 / 2930 / legacy / 4844. | | ac2_verify_transaction_solana | transaction-solana | Legacy + versioned transactions; Ed25519 against static-account-key signer slots. |

All inputs/outputs are base64. Verifiers are pure-local (no network calls); the chain SDKs (algosdk, viem, @solana/web3.js) are used as math libraries only. See src/tools.ts for the typebox parameter schemas and specs/ac2.md §ac2/SigningRequest for the spec-level display_hint × sig_hint × key_type matrix.

Native approvals → wallet

When OpenClaw needs to approve a tool call — an exec approval (a shell/host command gated by OpenClaw's policy) or a plugin approval (a before_tool_call requireApproval from any plugin) — the AC2 channel is a native approval surface: the pending approval is delivered to the paired wallet as an approve/deny card (the same Reply "yes …" format Regent already renders), the user taps approve/deny, and the verdict resolves the approval over the gateway. The tool call blocks until then; timeout/blocking are OpenClaw's, not ours. Implemented in src/approvals.ts via the channel's approvalCapability.render.

Routing. By default OpenClaw forwards approvals to the session origin (approvals.exec.mode/approvals.plugin.mode default "session"), so an approval raised during a turn that came in over AC2 (i.e. the wallet user messaged the agent) routes straight back to that wallet with no config. To also route approvals from turns that did not originate over AC2 (e.g. a scheduled/cron turn), add an explicit target and set the mode to "both":

{
  "approvals": {
    "exec":   { "mode": "both", "targets": [{ "channel": "ac2", "to": "<paired-peer-did>" }] },
    "plugin": { "mode": "both", "targets": [{ "channel": "ac2", "to": "<paired-peer-did>" }] }
  }
}

The <paired-peer-did> is the wallet's peer DID (see /ac2 status). Only the paired wallet is authorized to approve. When the WebRTC link is down the card fails over via FCM; the verdict returns once the wallet reconnects.

Configuration

openclaw ac2 setup writes the canonical config (under channels.ac2). Manual overrides go into the same place. Example of the full shape after setup, in ~/.openclaw/openclaw.json:

{
  "plugins": {
    "allow": ["ac2-plugin-openclaw"],
    "entries": {
      "ac2-plugin-openclaw": { "enabled": true }
    }
  },
  "channels": {
    "ac2": {
      "enabled": true,
      "liquidAuthServer": "https://liquidauth.goplausible.xyz",
      "agentDid": "did:web:openclaw.local"
    }
  },
  "bindings": [
    { "agentId": "main", "match": { "channel": "ac2" } }
  ],
  "tools": {
    "profile": "coding",
    "alsoAllow": [
      "ac2_sign",
      "ac2_verify_raw_ed25519",
      "ac2_verify_raw_secp256k1",
      "ac2_verify_message_algorand",
      "ac2_verify_message_evm",
      "ac2_verify_message_solana",
      "ac2_verify_typed_data_evm",
      "ac2_verify_transaction_algorand",
      "ac2_verify_transaction_evm",
      "ac2_verify_transaction_solana",
      "ac2_capabilities"
    ]
  }
}

Two fields (liquidAuthServer, agentDid) are read by the plugin at runtime. Precedence:

  1. api.pluginConfig (OpenClaw's per-plugin injection)
  2. plugins.entries.ac2-plugin-openclaw.config.<field> (legacy override path, still supported)
  3. channels.ac2.<field> (canonical path written by setup)
  4. Fallback (see table below)

| 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.json instead.

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_capabilities tool / /ac2 capabilities / openclaw ac2 capabilities | ac2/CapabilityRequestac2/Capabilities (symmetric; also auto-exchanged on connect) | ✅ | | ac2_sign tool (HITL) | ac2/SigningRequestac2/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:

  1. packages/ac2-plugin-openclaw/package.json"version"
  2. openclaw.plugin.json"version" (THIS is the field OpenClaw caches by)
  3. Root package-lock.jsonpackages/ac2-plugin-openclaw nested 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>.tgz

The 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