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

helmpilot

v0.4.5

Published

Helmpilot desktop channel plugin for OpenClaw — interactive tools and gateway RPC bridge

Downloads

42

Readme

helmpilot-channel

The Helmpilot Desktop Channel plugin for OpenClaw — registers Helmpilot as a full-featured channel in the OpenClaw gateway, providing interactive tools, outbound messaging, and relay-based cross-network tunneling.

Channel ID: helmpilot Config Section: channels.helmpilot

Architecture

Helmpilot is a desktop client that communicates with OpenClaw via WebSocket RPC. This plugin makes Helmpilot a first-class channel in the OpenClaw ecosystem, following the same plugin pattern as Slack, Telegram, Discord, and other channels.

Relay Tunnel

When configured with a relay URL, the plugin establishes a transparent tunnel:

Helmpilot Desktop ──WS(deviceKey)──→ Helmpilot Relay ←──WS(channelKey)── helmpilot-channel plugin
                                 (transparent)                         │
                                                                  bridge WS
                                                                       ↕
                                                              ws://127.0.0.1:<port>
                                                               (local gateway)

The relay forwards raw WebSocket messages without parsing. The plugin acts as a bridge: it connects to the relay as the "gateway side", then opens a local WebSocket to the OpenClaw gateway. Messages are transparently forwarded between these two connections.

Interactive Tool Flow

Agent calls hp_ask_user({ questions: [...] })
  ↓
OpenClaw emits tool.start event → Helmpilot client renders QuestionCard UI
  ↓
Plugin execute() blocks on a Promise (keyed by toolCallId)
  ↓
User fills answers → Helmpilot client calls helmpilot.respond via WS RPC
  ↓
Gateway method resolves the Promise → returns answers as tool result
  ↓
Agent sees actual user answers, continues reasoning

Plugin Structure

plugins/helmpilot-channel/
  index.ts               ← Plugin entry (definePluginEntry) — tools, RPC, channel registration
  channel-plugin.ts      ← ChannelPlugin definition (meta/config/gateway/startAccount)
  tools.ts               ← Tool schemas, PendingMap (Symbol.for key)
  bridge.ts              ← LocalBridge — WS tunnel to local gateway with ping/pong heartbeat
  outbound.ts            ← Outbound adapter (sendText/sendMedia via relay)
  relay-client.ts        ← RelayClient with Ed25519 auth + auto-reconnect + keepalive
  relay-registry.ts      ← Module-level Map<accountId, RelayClient> singleton
  adapters.ts            ← Messaging/Setup/Status/Pairing/Security adapters
  types.ts               ← Question/Answer TypeBox schemas
  preload.cjs            ← CJS→ESM bridge + SDK symlink
  openclaw.plugin.json   ← Manifest (declares channel: "helmpilot")
  package.json           ← Package metadata and OpenClaw compatibility
  __tests__/             ← Outbound adapter + config adapter tests

Channel Adapters

The plugin implements the full ChannelPlugin interface:

| Adapter | Source | Purpose | |---------|--------|---------| | outbound | outbound.ts | Send text/media to Helmpilot client via relay (deliveryMode: 'direct', textChunkLimit: 4000) | | messaging | adapters.ts | Target normalization and resolution | | setup | adapters.ts | Account config validation and application | | status | adapters.ts | Channel summary, account snapshot, probe | | pairing | adapters.ts | Device key pairing (idLabel: 'Device Key') | | security | adapters.ts | Security policy adapter | | config | Inline in plugin | Account CRUD, enable/disable, account resolution |

Outbound Adapter

Sends messages as OpenClaw event frames through the relay:

// Format sent to relay
{
  type: 'event',
  event: 'helmpilot.outbound',
  payload: {
    kind: 'text' | 'media',
    text?: string,
    mediaUrl?: string,
    messageId: string,       // Format: msg_<uuid>
    replyToId?: string,
    identity?: { name?, avatar?, emoji? }
  }
}

Tools

hp_ask_user

Present structured questions to the user in the Helmpilot desktop client. Blocks until the user submits answers. No fixed timeout — waits indefinitely until the user responds. Cleanup relies on connection/session lifecycle boundaries.

{
  questions: [
    {
      header: "Language",           // Short unique ID (max 50 chars)
      question: "Which language?",  // Display text (max 500 chars)
      options: [                    // Optional predefined choices
        { label: "Python", recommended: true },
        { label: "TypeScript" },
        { label: "Rust", description: "Systems programming" }
      ],
      multiSelect: false,           // Allow multiple selections
      allowFreeformInput: true      // Allow typing a custom answer
    }
  ]
}

hp_send_msg

Send a notification or structured message to the Helmpilot client. Non-blocking — delivers the message for display as a distinct notification card, separate from inline chat stream. Supports Markdown in the message body.

{
  message: "Deployment **completed** successfully!",  // Markdown content
  type: "success",        // "info" (default) | "success" | "warning" | "error"
  title: "Deploy Status"  // Optional notification title
}

hp_send_file

Send a file to the Helmpilot client for local display/writing. Non-blocking — the tool returns immediately after relaying the content.

Gateway RPC Methods

helmpilot.respond

Called by the Helmpilot client to deliver user answers to a pending hp_ask_user call.

{ "toolCallId": "...", "answers": "User's formatted answer string" }

Configuration

CLI Quick Setup

The fastest way to configure helmpilot-channel is via the OpenClaw CLI:

# Full non-interactive setup (all three fields at once)
openclaw channels add --channel helmpilot \
  --url wss://relay.example.com \
  --code helmpilot-abc123 \
  --token ck_xyz789

# Interactive wizard mode (guided step-by-step)
openclaw channels add --channel helmpilot

# Partial update (e.g. rotate channel key only)
openclaw channels add --channel helmpilot --token ck_new_key

| CLI Flag | Config Field | Validation | Example | |----------|-------------|------------|---------| | --url | channels.helmpilot.relayUrl | Must be ws://, wss://, http://, or https:// | wss://relay.example.com | | --code | channels.helmpilot.channelId | Must start with helmpilot- | helmpilot-abc123 | | --token | channels.helmpilot.channelKey | Must start with ck_ | ck_xyz789 |

Tip: The channelId and channelKey are generated by the Relay server during provisioning (triggered from the Helmpilot desktop client). Copy them from the Helmpilot setup screen into the CLI command above.

Manual Configuration

Add to your OpenClaw config (openclaw.json):

Single account (simple)

{
  "channels": {
    "helmpilot": {
      "enabled": true,
      "relayUrl": "wss://relay.example.com",
      "channelKey": "ck_xxxxx..."
    }
  }
}

Multi-account

{
  "channels": {
    "helmpilot": {
      "accounts": {
        "work": { "relayUrl": "wss://relay.example.com", "channelKey": "ck_aaa..." },
        "home": { "relayUrl": "wss://relay.example.com", "channelKey": "ck_bbb..." }
      }
    }
  }
}

Secret storage for channelKey

To avoid storing channelKey in plaintext, use any of these formats:

// Env template — resolved from process.env at startup
"channelKey": "${HELMPILOT_CHANNEL_KEY}"

// SecretRef (env source)
"channelKey": { "source": "env", "id": "HELMPILOT_CHANNEL_KEY" }

// SecretRef (file source)
"channelKey": { "source": "file", "id": "/run/secrets/helmpilot-channel-key" }

| Field | Type | Required | Purpose | |-------|------|----------|---------| | enabled | boolean | No (default: true) | Enable/disable the channel | | relayUrl | string | Yes (for relay mode) | Relay service WebSocket URL | | channelId | string | Auto-populated | Channel ID from relay registration | | channelKey | string | SecretRef | Yes (for relay mode) | Channel key — supports env templates and SecretRef |

Installation

openclaw plugins install helmpilot-channel

Or add to your workspace's plugin load paths:

# Local development (symlink)
ln -s /path/to/Helmpilot/plugins/helmpilot-channel ~/.openclaw/extensions/helmpilot-channel

Relay Client

RelayClient (relay-client.ts) manages the gateway-side WebSocket connection to the relay:

  • Ed25519 auth: Auto-generates key pair, handles challenge-response with relay
  • Legacy fallback: Falls back to ?key=<channelKey> URL param if Ed25519 keys not registered
  • Auto-reconnect: Exponential backoff from 1s to 30s
  • Keepalive: Sends {"__relay":true,"type":"ping"} every 25 seconds
  • Flush handling: Recognizes flush_start/flush_end relay markers for buffered message batches
  • States: 'disconnected' | 'connecting' | 'authenticating' | 'connected' | 'error'

Local Bridge

LocalBridge (bridge.ts) manages the WS connection to the local OpenClaw gateway:

  • Transparent tunnel: Forwards raw WS frames between relay and local gateway
  • Ping/pong heartbeat: 20s interval + 10s timeout for dead connection detection
  • Lifecycle: Opened per startAccount(), closed on disconnect

Process Architecture

The gateway loads plugin registration twice:

  • Connection-level: registerGatewayMethod() handlers (client-specific)
  • Per-agent: registerTool() handlers (agent-scoped)

These scopes don't share closure variables. We use globalThis[Symbol.for('helmpilot.pendingMap')] as a process-level shared mailbox between helmpilot.respond (connection) and hp_ask_user execute (agent).

Multi-Account Isolation

Each account gets its own RelayClient + LocalBridge pair, registered in relay-registry.ts. Outbound messages are routed to the correct relay via getRelay(accountId) — the null-fallback has been removed to prevent cross-account message leakage.

The helmpilot.respond RPC handler requires an explicit toolCallId to prevent resolving a pending request from a different account's agent.

Testing

# All plugin tests
npx vitest run plugins/helmpilot-channel/__tests__/

# Individual test files
npx vitest run plugins/helmpilot-channel/__tests__/outbound.test.ts       # Outbound adapter (10 cases)
npx vitest run plugins/helmpilot-channel/__tests__/config-adapter.test.ts  # Config/multi-account (varies)
npx vitest run plugins/helmpilot-channel/__tests__/setup-adapter.test.ts   # CLI setup adapter (16 cases)

License

MIT