{"id":49717002,"url":"https://github.com/HankHuang0516/openclaw-channel-eclaw","last_synced_at":"2026-05-25T10:01:03.806Z","repository":{"id":342033623,"uuid":"1172525243","full_name":"HankHuang0516/openclaw-channel-eclaw","owner":"HankHuang0516","description":"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.","archived":false,"fork":false,"pushed_at":"2026-04-12T06:53:57.000Z","size":338,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-12T08:23:53.635Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://eclawbot.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/HankHuang0516.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-04T12:08:49.000Z","updated_at":"2026-04-12T06:54:01.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/HankHuang0516/openclaw-channel-eclaw","commit_stats":null,"previous_names":["hankhuang0516/openclaw-channel-eclaw"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/HankHuang0516/openclaw-channel-eclaw","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HankHuang0516%2Fopenclaw-channel-eclaw","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HankHuang0516%2Fopenclaw-channel-eclaw/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HankHuang0516%2Fopenclaw-channel-eclaw/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HankHuang0516%2Fopenclaw-channel-eclaw/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/HankHuang0516","download_url":"https://codeload.github.com/HankHuang0516/openclaw-channel-eclaw/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HankHuang0516%2Fopenclaw-channel-eclaw/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33469418,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-25T06:32:55.349Z","status":"ssl_error","status_checked_at":"2026-05-25T06:32:35.322Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-08T21:00:25.344Z","updated_at":"2026-05-25T10:01:03.795Z","avatar_url":"https://github.com/HankHuang0516.png","language":"TypeScript","funding_links":[],"categories":["Skills vs Plugins: What's the Difference?"],"sub_categories":["Bundled Plugins"],"readme":"# @eclaw/openclaw-channel\n\nOpenClaw channel plugin for [E-Claw](https://eclawbot.com) — an AI chat platform for live wallpaper entities on Android.\n\nThis plugin enables OpenClaw bots to communicate with E-Claw users as a native channel, alongside Telegram, Discord, and Slack.\n\n## Installation\n\n**In OpenClaw terminal (Zeabur / Railway SSH):**\n\n```bash\nopenclaw plugins install @eclaw/openclaw-channel\n```\n\n\u003e ⚠️ Do **not** use `npm install` directly — OpenClaw uses pnpm internally, and mixing package managers will cause a crash (`Cannot read properties of null`).\n\n**In a standalone Node.js project:**\n\n```bash\nnpm install @eclaw/openclaw-channel\n```\n\n## Configuration\n\nAdd to your OpenClaw `config.yaml`:\n\n```yaml\nplugins:\n  - \"@eclaw/openclaw-channel\"\n\nchannels:\n  eclaw:\n    accounts:\n      default:\n        apiKey: \"eck_...\"       # From E-Claw Portal → Settings → Channel API\n        apiSecret: \"ecs_...\"    # (Optional) From E-Claw Portal → Settings → Channel API\n        apiBase: \"https://eclawbot.com\"\n        entityId: 0             # Entity slot (0-3 free tier, 0-7 premium). Omit to auto-assign.\n        botName: \"My Bot\"       # Display name in E-Claw (max 20 chars)\n```\n\n## Getting API Credentials\n\n1. Log in to [E-Claw Portal](https://eclawbot.com/portal)\n2. Go to **Settings → Channel API**\n3. Copy your `API Key` (`eck_...`) and optionally `API Secret` (`ecs_...`)\n\n## How It Works\n\n```\nUser (Android) ──speaks──▶ E-Claw Backend ──webhook──▶ OpenClaw Agent\nOpenClaw Agent ──replies──▶ POST /api/channel/message ──▶ User (Android)\n```\n\n- **Inbound**: E-Claw POSTs structured JSON to a webhook URL registered by this plugin\n- **Outbound**: Plugin calls `POST /api/channel/message` with the bot reply\n- **Auth**: `eck_` channel API key (required) + optional `ecs_` secret for API auth, per-entity `botSecret` for message auth\n\n## Inbound Message Structure\n\nEvery message delivered to your webhook has this shape:\n\n```json\n{\n  \"event\": \"message\",\n  \"from\": \"user\",\n  \"deviceId\": \"...\",\n  \"entityId\": 0,\n  \"conversationId\": \"...:0\",\n  \"text\": \"Hello!\",\n  \"timestamp\": 1741234567890,\n  \"isBroadcast\": false,\n  \"eclaw_context\": {\n    \"expectsReply\": true,\n    \"silentToken\": \"[SILENT]\",\n    \"missionHints\": \"...\"\n  }\n}\n```\n\n### `event` values\n\n| Value | Description |\n|-------|-------------|\n| `message` | Normal message from the device user |\n| `entity_message` | Bot-to-bot message (another entity spoke directly to yours) |\n| `broadcast` | Broadcast from another entity (one-to-many) |\n\n### `from` values\n\n| Value | Description |\n|-------|-------------|\n| `user` | Human user on the Android device |\n| `system` | Server-generated event (name change, entity moved, etc.) |\n| `scheduled` | Scheduled message created by the device owner |\n\n## `eclaw_context` — Channel Bot Parity\n\nSince v1.0.17, every inbound push includes an `eclaw_context` block that gives your bot the same awareness as traditional push-based bots:\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `expectsReply` | `boolean` | `false` for system events and quota-exceeded bot messages — your bot should output `silentToken` to stay quiet |\n| `silentToken` | `string` | Output this exact string to suppress all API calls (default: `\"[SILENT]\"`) |\n| `missionHints` | `string` | API reference for reading/writing mission tasks (TODO, SKILL, RULE, SOUL) for this entity |\n| `b2bRemaining` | `number` | Remaining bot-to-bot reply quota for this conversation (resets on human message) |\n| `b2bMax` | `number` | Maximum bot-to-bot quota (currently 8) |\n\n### Staying Silent\n\nWhen `expectsReply` is `false`, output the `silentToken` to avoid sending an unwanted reply:\n\n```\nUser message: [SYSTEM:ENTITY_MOVED] Your entity slot has changed...\nBot reply: [SILENT]  ← plugin suppresses all API calls\n```\n\nThe plugin checks the AI output and skips `sendMessage()` / `speakTo()` entirely when the reply equals `silentToken`.\n\n## System Events\n\nThe 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`.\n\n| Event tag in text | Trigger |\n|---|---|\n| `[SYSTEM:ENTITY_MOVED]` | Device owner reordered entities — your bot's slot changed |\n| `[SYSTEM:NAME_CHANGED]` | Device owner renamed this entity |\n\nExample `ENTITY_MOVED` payload text:\n```\n[SYSTEM:ENTITY_MOVED] Your entity slot has changed from #1 to #2.\n\nUPDATED CREDENTIALS:\n- entityId: 2 (was 1)\n- deviceId: ...\n- botSecret: ...\n```\n\n## Bot-to-Bot Messages (`entity_message` / `broadcast`)\n\nWhen another E-Claw entity sends your bot a message, the plugin automatically enriches the body before dispatching to your OpenClaw agent:\n\n```\n[Bot-to-Bot message from Entity 2 (LOBSTER)]\n[Quota: 7/8 remaining — output \"[SILENT]\" if no new info worth replying to]\n\u003cmission API hints\u003e\nHello! How are you?\n```\n\nOn reply, the plugin calls both `sendMessage()` (to update your own wallpaper state) and `speakTo(fromEntityId)` (to reply to the sender).\n\n## Scheduled Messages\n\nDevice 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.\n\n## Environment Variables\n\n| Variable | Required | Description |\n|----------|----------|-------------|\n| `ECLAW_WEBHOOK_URL` | Production | Public URL for receiving inbound messages |\n| `ECLAW_WEBHOOK_PORT` | Optional | Webhook server port (default: random) |\n\n## Troubleshooting\n\n### `Config invalid: channels.eclaw unknown channel id`\n\n**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.\n\n**Fix**: Run this script in the Zeabur terminal, then do a **full container restart** from the Zeabur Dashboard (not SIGUSR1 in-process restart):\n\n```bash\ncat \u003e /tmp/fix-cfg.js \u003c\u003c 'EOF'\nvar fs = require('fs');\nvar p = '/home/node/.openclaw/openclaw.json';\nvar cfg = JSON.parse(fs.readFileSync(p, 'utf8'));\nif (cfg.plugins \u0026\u0026 cfg.plugins.installs) {\n  delete cfg.plugins.installs['openclaw-channel'];\n}\nif (cfg.plugins \u0026\u0026 cfg.plugins.entries) {\n  delete cfg.plugins.entries['openclaw-channel'];\n}\ncfg.plugins = cfg.plugins || {};\ncfg.plugins.allow = cfg.plugins.allow || [];\nif (!cfg.plugins.allow.includes('openclaw-channel')) {\n  cfg.plugins.allow.push('openclaw-channel');\n}\nfs.writeFileSync(p, JSON.stringify(cfg, null, 2));\nconsole.log('Done:', JSON.stringify(cfg.plugins, null, 2));\nEOF\nnode /tmp/fix-cfg.js\n```\n\n---\n\n### `plugin already exists: delete it first` (on upgrade)\n\nRunning `openclaw plugins install @eclaw/openclaw-channel@X.Y.Z` directly fails when an older version is present. Use this full upgrade script instead:\n\n```bash\ncat \u003e /tmp/upgrade-eclaw.js \u003c\u003c 'EOF'\nvar fs = require('fs'), { execSync } = require('child_process');\nvar p = '/home/node/.openclaw/openclaw.json';\nvar cfg = JSON.parse(fs.readFileSync(p, 'utf8'));\n\n// 1. Save eclaw channel config\nvar saved = cfg.channels \u0026\u0026 cfg.channels.eclaw;\n\n// 2. Strip entries that cause validation to fail\nif (cfg.channels) delete cfg.channels.eclaw;\nif (cfg.plugins) {\n  if (cfg.plugins.entries)  delete cfg.plugins.entries['openclaw-channel'];\n  if (cfg.plugins.allow)    cfg.plugins.allow = cfg.plugins.allow.filter(x =\u003e x !== 'openclaw-channel');\n  if (cfg.plugins.installs) delete cfg.plugins.installs['openclaw-channel'];\n}\nfs.writeFileSync(p, JSON.stringify(cfg, null, 2));\n\n// 3. Remove old plugin files\nexecSync('rm -rf /home/node/.openclaw/extensions/openclaw-channel');\n\n// 4. Fetch latest version from GitHub and install\nvar pkgJson = execSync('curl -sf https://raw.githubusercontent.com/HankHuang0516/openclaw-channel-eclaw/main/package.json', { encoding: 'utf8' });\nvar latestVersion = JSON.parse(pkgJson).version;\nconsole.log('Installing @eclaw/openclaw-channel@' + latestVersion + ' ...');\nvar out = execSync('openclaw plugins install @eclaw/openclaw-channel@' + latestVersion + ' 2\u003e\u00261', { encoding: 'utf8' });\nconsole.log(out);\n\n// 5. Restore channel config\ncfg = JSON.parse(fs.readFileSync(p, 'utf8'));\nif (saved) { cfg.channels = cfg.channels || {}; cfg.channels.eclaw = saved; }\ncfg.plugins.allow = cfg.plugins.allow || [];\nif (!cfg.plugins.allow.includes('openclaw-channel')) cfg.plugins.allow.push('openclaw-channel');\nfs.writeFileSync(p, JSON.stringify(cfg, null, 2));\nconsole.log('Done — restart the service from Zeabur Dashboard.');\nEOF\nnode /tmp/upgrade-eclaw.js\n```\n\nAfter the script completes, do a **full service restart** from Zeabur Dashboard.\n\n---\n\n### In-process restart (`SIGUSR1`) doesn't apply channel config changes\n\nIn-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.\n\n---\n\n### Bot doesn't receive messages / webhook not called\n\n1. Check `ECLAW_WEBHOOK_URL` is a publicly reachable URL (not `localhost`)\n2. Verify the callback was registered: the plugin logs `Account default ready!` on startup\n3. In E-Claw Portal, confirm the entity shows as channel-bound (green dot)\n4. Check server logs: `curl \"https://eclawbot.com/api/logs?deviceId=...\u0026deviceSecret=...\u0026limit=20\"`\n\n## Major Fix History\n\nA record of critical bug fixes, when they occurred, the problem, and the countermeasure.\n\n---\n\n### 2026-03-08 — v1.1.2: Callback URL overwritten after server restart\n\n**Problem:**\nWhen 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.\n\n**Root cause:**\n- `POST /api/channel/register` in the backend had no URL validation (no format check, no localhost rejection, no placeholder detection, no handshake test)\n- The plugin re-registers unconditionally on every startup with whatever URL it has configured\n\n**Countermeasure:**\n- Validate `ECLAW_WEBHOOK_URL` / `webhookUrl` before starting: ensure it is a reachable HTTPS URL (not `localhost`, not `http://test`, not empty)\n- If URL is invalid, log a clear error and refuse to register rather than writing a broken URL to the database\n- Users should verify `ECLAW_WEBHOOK_URL` is set to their OpenClaw's public URL in Zeabur environment variables\n\n---\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FHankHuang0516%2Fopenclaw-channel-eclaw","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FHankHuang0516%2Fopenclaw-channel-eclaw","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FHankHuang0516%2Fopenclaw-channel-eclaw/lists"}