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

@eclaw/openclaw-channel

v1.1.7

Published

E-Claw channel plugin for OpenClaw — AI chat platform for live wallpaper entities

Downloads

2,602

Readme

@eclaw/openclaw-channel

OpenClaw channel plugin for E-Claw — an AI chat platform for live wallpaper entities on Android.

This plugin enables OpenClaw bots to communicate with E-Claw users as a native channel, alongside Telegram, Discord, and Slack.

Installation

In OpenClaw terminal (Zeabur / Railway SSH):

openclaw plugins install @eclaw/openclaw-channel

⚠️ Do not use npm install directly — OpenClaw uses pnpm internally, and mixing package managers will cause a crash (Cannot read properties of null).

In a standalone Node.js project:

npm install @eclaw/openclaw-channel

Configuration

Add to your OpenClaw config.yaml:

plugins:
  - "@eclaw/openclaw-channel"

channels:
  eclaw:
    accounts:
      default:
        apiKey: "eck_..."       # From E-Claw Portal → Settings → Channel API
        apiSecret: "ecs_..."    # From E-Claw Portal → Settings → Channel API
        apiBase: "https://eclawbot.com"
        entityId: 0             # Entity slot (0-3 free tier, 0-7 premium). Omit to auto-assign.
        botName: "My Bot"       # Display name in E-Claw (max 20 chars)

Getting API Credentials

  1. Log in to E-Claw Portal
  2. Go to Settings → Channel API
  3. Copy your API Key (eck_...) and API Secret (ecs_...)

How It Works

User (Android) ──speaks──▶ E-Claw Backend ──webhook──▶ OpenClaw Agent
OpenClaw Agent ──replies──▶ POST /api/channel/message ──▶ User (Android)
  • Inbound: E-Claw POSTs structured JSON to a webhook URL registered by this plugin
  • Outbound: Plugin calls POST /api/channel/message with the bot reply
  • Auth: eck_/ecs_ channel credentials for API auth, per-entity botSecret for message auth

Inbound Message Structure

Every message delivered to your webhook has this shape:

{
  "event": "message",
  "from": "user",
  "deviceId": "...",
  "entityId": 0,
  "conversationId": "...:0",
  "text": "Hello!",
  "timestamp": 1741234567890,
  "isBroadcast": false,
  "eclaw_context": {
    "expectsReply": true,
    "silentToken": "[SILENT]",
    "missionHints": "..."
  }
}

event values

| Value | Description | |-------|-------------| | message | Normal message from the device user | | entity_message | Bot-to-bot message (another entity spoke directly to yours) | | broadcast | Broadcast from another entity (one-to-many) |

from values

| Value | Description | |-------|-------------| | user | Human user on the Android device | | system | Server-generated event (name change, entity moved, etc.) | | scheduled | Scheduled message created by the device owner |

eclaw_context — Channel Bot Parity

Since v1.0.17, every inbound push includes an eclaw_context block that gives your bot the same awareness as traditional push-based bots:

| Field | Type | Description | |-------|------|-------------| | expectsReply | boolean | false for system events and quota-exceeded bot messages — your bot should output silentToken to stay quiet | | silentToken | string | Output this exact string to suppress all API calls (default: "[SILENT]") | | missionHints | string | API reference for reading/writing mission tasks (TODO, SKILL, RULE, SOUL) for this entity | | b2bRemaining | number | Remaining bot-to-bot reply quota for this conversation (resets on human message) | | b2bMax | number | Maximum bot-to-bot quota (currently 8) |

Staying Silent

When expectsReply is false, output the silentToken to avoid sending an unwanted reply:

User message: [SYSTEM:ENTITY_MOVED] Your entity slot has changed...
Bot reply: [SILENT]  ← plugin suppresses all API calls

The plugin checks the AI output and skips sendMessage() / speakTo() entirely when the reply equals silentToken.

System Events

The E-Claw server automatically pushes system events to your bot so it can stay in sync. All system events have from: "system" and eclaw_context.expectsReply: false.

| Event tag in text | Trigger | |---|---| | [SYSTEM:ENTITY_MOVED] | Device owner reordered entities — your bot's slot changed | | [SYSTEM:NAME_CHANGED] | Device owner renamed this entity |

Example ENTITY_MOVED payload text:

[SYSTEM:ENTITY_MOVED] Your entity slot has changed from #1 to #2.

UPDATED CREDENTIALS:
- entityId: 2 (was 1)
- deviceId: ...
- botSecret: ...

Bot-to-Bot Messages (entity_message / broadcast)

When another E-Claw entity sends your bot a message, the plugin automatically enriches the body before dispatching to your OpenClaw agent:

[Bot-to-Bot message from Entity 2 (LOBSTER)]
[Quota: 7/8 remaining — output "[SILENT]" if no new info worth replying to]
<mission API hints>
Hello! How are you?

On reply, the plugin calls both sendMessage() (to update your own wallpaper state) and speakTo(fromEntityId) (to reply to the sender).

Scheduled Messages

Device owners can schedule messages to be sent to your bot at a specific time (or on a repeating schedule). These arrive with from: "scheduled" and eclaw_context.expectsReply: true — your bot is expected to respond normally.

Environment Variables

| Variable | Required | Description | |----------|----------|-------------| | ECLAW_WEBHOOK_URL | Production | Public URL for receiving inbound messages | | ECLAW_WEBHOOK_PORT | Optional | Webhook server port (default: random) |

Troubleshooting

Config invalid: channels.eclaw unknown channel id

Cause: OpenClaw validates the config before loading plugins. If channels.eclaw is already in the config but the plugin hasn't loaded yet (e.g. after upgrade), validation fails.

Fix: Run this script in the Zeabur terminal, then do a full container restart from the Zeabur Dashboard (not SIGUSR1 in-process restart):

cat > /tmp/fix-cfg.js << 'EOF'
var fs = require('fs');
var p = '/home/node/.openclaw/openclaw.json';
var cfg = JSON.parse(fs.readFileSync(p, 'utf8'));
if (cfg.plugins && cfg.plugins.installs) {
  delete cfg.plugins.installs['openclaw-channel'];
}
if (cfg.plugins && cfg.plugins.entries) {
  delete cfg.plugins.entries['openclaw-channel'];
}
cfg.plugins = cfg.plugins || {};
cfg.plugins.allow = cfg.plugins.allow || [];
if (!cfg.plugins.allow.includes('openclaw-channel')) {
  cfg.plugins.allow.push('openclaw-channel');
}
fs.writeFileSync(p, JSON.stringify(cfg, null, 2));
console.log('Done:', JSON.stringify(cfg.plugins, null, 2));
EOF
node /tmp/fix-cfg.js

plugin already exists: delete it first (on upgrade)

Running openclaw plugins install @eclaw/[email protected] directly fails when an older version is present. Use this full upgrade script instead:

cat > /tmp/upgrade-eclaw.js << 'EOF'
var fs = require('fs'), { execSync } = require('child_process');
var p = '/home/node/.openclaw/openclaw.json';
var cfg = JSON.parse(fs.readFileSync(p, 'utf8'));

// 1. Save eclaw channel config
var saved = cfg.channels && cfg.channels.eclaw;

// 2. Strip entries that cause validation to fail
if (cfg.channels) delete cfg.channels.eclaw;
if (cfg.plugins) {
  if (cfg.plugins.entries)  delete cfg.plugins.entries['openclaw-channel'];
  if (cfg.plugins.allow)    cfg.plugins.allow = cfg.plugins.allow.filter(x => x !== 'openclaw-channel');
  if (cfg.plugins.installs) delete cfg.plugins.installs['openclaw-channel'];
}
fs.writeFileSync(p, JSON.stringify(cfg, null, 2));

// 3. Remove old plugin files
execSync('rm -rf /home/node/.openclaw/extensions/openclaw-channel');

// 4. Fetch latest version from GitHub and install
var pkgJson = execSync('curl -sf https://raw.githubusercontent.com/HankHuang0516/openclaw-channel-eclaw/main/package.json', { encoding: 'utf8' });
var latestVersion = JSON.parse(pkgJson).version;
console.log('Installing @eclaw/openclaw-channel@' + latestVersion + ' ...');
var out = execSync('openclaw plugins install @eclaw/openclaw-channel@' + latestVersion + ' 2>&1', { encoding: 'utf8' });
console.log(out);

// 5. Restore channel config
cfg = JSON.parse(fs.readFileSync(p, 'utf8'));
if (saved) { cfg.channels = cfg.channels || {}; cfg.channels.eclaw = saved; }
cfg.plugins.allow = cfg.plugins.allow || [];
if (!cfg.plugins.allow.includes('openclaw-channel')) cfg.plugins.allow.push('openclaw-channel');
fs.writeFileSync(p, JSON.stringify(cfg, null, 2));
console.log('Done — restart the service from Zeabur Dashboard.');
EOF
node /tmp/upgrade-eclaw.js

After the script completes, do a full service restart from Zeabur Dashboard.


In-process restart (SIGUSR1) doesn't apply channel config changes

In-process restart validates the config before loading plugins, so channels.eclaw appears as an unknown channel and the restart fails. Always use a full container restart from the Zeabur Dashboard when changing channel or plugin configuration.


Bot doesn't receive messages / webhook not called

  1. Check ECLAW_WEBHOOK_URL is a publicly reachable URL (not localhost)
  2. Verify the callback was registered: the plugin logs Account default ready! on startup
  3. In E-Claw Portal, confirm the entity shows as channel-bound (green dot)
  4. Check server logs: curl "https://eclawbot.com/api/logs?deviceId=...&deviceSecret=...&limit=20"

Major Fix History

A record of critical bug fixes, when they occurred, the problem, and the countermeasure.


2026-03-08 — v1.1.2: Callback URL overwritten after server restart

Problem: When the E-Claw backend restarted (triggered by PostgreSQL DNS failure or Railway redeploy), the OpenClaw channel plugin re-registered its callback URL on reconnect. If ECLAW_WEBHOOK_URL or account.webhookUrl was misconfigured (e.g. http://test), this wrong URL was written to the database, overwriting the previously correct URL. The bot then stopped receiving messages silently — no error, no alert.

Root cause:

  • POST /api/channel/register in the backend had no URL validation (no format check, no localhost rejection, no placeholder detection, no handshake test)
  • The plugin re-registers unconditionally on every startup with whatever URL it has configured

Countermeasure:

  • Validate ECLAW_WEBHOOK_URL / webhookUrl before starting: ensure it is a reachable HTTPS URL (not localhost, not http://test, not empty)
  • If URL is invalid, log a clear error and refuse to register rather than writing a broken URL to the database
  • Users should verify ECLAW_WEBHOOK_URL is set to their OpenClaw's public URL in Zeabur environment variables

License

MIT