@cloudrise/openclaw-channel-rocketchat
v0.6.1
Published
Rocket.Chat channel plugin for OpenClaw (Cloudrise)
Downloads
107
Readme
OpenClaw Rocket.Chat Channel Plugin
Neutral, self-host friendly Rocket.Chat channel plugin for OpenClaw (Cloudrise-maintained).
- Inbound: Rocket.Chat Realtime (DDP/WebSocket) subscribe to
stream-room-messages - Outbound: Rocket.Chat REST
chat.postMessage
Upgrade notices
v0.6.0 — Per-room access control (beta)
New fine-grained per-room user access control:
rooms.<roomId>.canInteract— static list of users/roles who can interactrooms.<roomId>.roomApprovers— who can approve others for this roomrooms.<roomId>.responseMode— "always" or "mention-only"- Room-level commands:
--room-approve @user,--room-deny @user,--room-list
⚠️ Beta: Per-room ACL is functional but should be tested before production use.
v0.5.0 — Channel/room approval flow (beta)
New groupPolicy: "owner-approval" for controlling which channels the bot responds in:
- Bot sends "pending approval" message on first message in unapproved channels
- Approve with
--approve room:ROOMID, deny with--deny room:ROOMID
⚠️ Beta: Channel approval flow is functional but should be tested before production use.
v0.4.0 — Owner-approval DM policy
New dmPolicy: "owner-approval" for in-channel approval flow (no CLI needed):
- Configure
ownerApproval.notifyChannelsfor where to receive requests - Configure
ownerApproval.approverswith usernames or Rocket.Chat roles (role:admin,role:moderator) - Commands:
--approve @user,--deny @user,--pending
v0.3.0 — DM pairing support
Added support for OpenClaw's DM pairing flow. Default behavior unchanged (dmPolicy: "open"), but you can now enable dmPolicy: "pairing" for per-user approval.
v0.2.0+ — plugin id change
The plugin id changed from rocketchat to openclaw-channel-rocketchat to align with OpenClaw's package-derived id convention and eliminate the "plugin id mismatch" warning.
Update your config:
plugins:
entries:
openclaw-channel-rocketchat: # ← was "rocketchat"
enabled: true
channels:
rocketchat: # ← stays the same (channel id ≠ plugin id)
...Clawdbot → OpenClaw migration
If you were using the old Clawdbot-era package:
- Old:
@cloudrise/clawdbot-channel-rocketchat - New:
@cloudrise/openclaw-channel-rocketchat
Authors
- Chad (AI assistant running in OpenClaw) — primary implementer
- Marshal Morse — project owner, requirements, infrastructure, and testing
Quickstart (5–10 minutes)
Create a Rocket.Chat bot user (or a dedicated user account) and obtain:
userIdauthToken(treat like a password)
Add the bot user to the rooms you want it to monitor (channels/private groups). For DMs, ensure users can message the bot.
Install + enable the plugin in OpenClaw
plugins:
installs:
rocketchat:
source: npm
spec: "@cloudrise/openclaw-channel-rocketchat"
entries:
openclaw-channel-rocketchat:
enabled: true
channels:
rocketchat:
baseUrl: "https://chat.example.com"
userId: "<ROCKETCHAT_USER_ID>"
authToken: "<ROCKETCHAT_AUTH_TOKEN>"
# Optional: keep noise down
replyMode: auto
rooms:
GENERAL:
requireMention: trueRestart the gateway.
Test by @mentioning the bot in a room it’s a member of.
Example chat commands (reply to a room + model switching)
In Rocket.Chat you can send a normal message, or you can switch the session’s model first.
Switch model, then ask a question:
Rocket.Chat treats messages starting with / as Rocket.Chat slash-commands.
So for model switching, either:
- put the directive after an @mention (works on most servers/clients), or
- use the plugin’s alternate
--model/--<alias>syntax.
# Option A: use /model after an @mention
@Chad /model qwen3
@Chad write a 5-line summary of our incident in plain English
# Option B: alternate syntax (avoids Rocket.Chat /commands)
@Chad --model qwen3
@Chad write a 5-line summary of our incident in plain English
# Option C: shorthand alias form
@Chad --qwen3
@Chad write a 5-line summary of our incident in plain EnglishExample output (with messages.responsePrefix: "({model}) " enabled):
(mlx-qwen/mlx-community/Qwen3-14B-4bit) Here’s a 5-line summary...
...Send a one-off message to a specific Rocket.Chat room (from the gateway host):
openclaw message send --channel rocketchat --to room:GENERAL --message "Hello from OpenClaw"Send using a specific model for that one message:
openclaw message send --channel rocketchat --to room:GENERAL --message "/model qwen3 Hello from Qwen3"Install
Install from npm
npm install @cloudrise/openclaw-channel-rocketchatConfigure OpenClaw to load the plugin
You need to tell OpenClaw to load the installed plugin.
Option A (recommended): install via plugins.installs (npm source)
plugins:
installs:
rocketchat:
source: npm
spec: "@cloudrise/openclaw-channel-rocketchat"
entries:
openclaw-channel-rocketchat:
enabled: trueOption B: load from a local path
plugins:
load:
paths:
- /absolute/path/to/node_modules/@cloudrise/openclaw-channel-rocketchat
entries:
openclaw-channel-rocketchat:
enabled: trueThen restart the gateway.
Features
Inbound attachments: receives images, PDFs/documents, and audio; forwards them to OpenClaw for vision/document understanding and transcription.
Outbound attachments: can send local file paths as real Rocket.Chat uploads (inline previews when supported).
Reactions: can react to messages with emoji (via
chat.react).File attachments: receives images, PDFs, documents, audio uploaded to Rocket.Chat and passes them to the vision model.
Model prefix: honors
messages.responsePrefix(e.g.({model})) so replies can include the model name.
Model switching
There are two parts:
- Switching models in chat (temporary, per-session) via
/model ... - Defining short aliases like
qwen3so you don’t have to type the fullprovider/model
Switching models in chat (/model)
In any chat where OpenClaw slash-commands are enabled, you can switch the current session’s model:
/model
/model list
/model status
/model openai/gpt-5.2
/model qwen3Tip: on Rocket.Chat you’ll often be writing something like:
@Chad /model qwen3
@Chad what do you think about ...Model aliases (shortcuts like qwen3)
OpenClaw supports model aliases so you can type a short name (like qwen3) instead of a full provider/model ref.
Option A: define aliases in config
Aliases come from agents.defaults.models.<modelId>.alias.
agents:
defaults:
models:
"mlx-qwen/mlx-community/qwen3-14b-4bit":
alias: qwen3Option B: use the CLI
openclaw models aliases add qwen3 mlx-qwen/mlx-community/Qwen3-14B-4bit
openclaw models aliases listNotes:
- Model refs are normalized to lowercase.
- If you define the same alias in config and via CLI, your config value wins.
Configuration
Use the room rid (e.g.
GENERAL) for per-room settings.
Minimal (single account)
channels:
rocketchat:
baseUrl: "https://chat.example.com"
userId: "<ROCKETCHAT_USER_ID>"
authToken: "<ROCKETCHAT_AUTH_TOKEN>"Multiple accounts / multiple Rocket.Chat servers
You can configure multiple Rocket.Chat “accounts” under channels.rocketchat.accounts and choose which one to use via accountId when sending.
channels:
rocketchat:
accounts:
prod:
name: "Prod RC"
baseUrl: "https://chat.example.com"
userId: "<PROD_USER_ID>"
authToken: "<PROD_AUTH_TOKEN>"
staging:
name: "Staging RC"
baseUrl: "https://chat-staging.example.com"
userId: "<STAGING_USER_ID>"
authToken: "<STAGING_AUTH_TOKEN>"Notes:
- The legacy single-account format (top-level
baseUrl/userId/authToken) still works and is treated asaccountId: default. - Per-room settings live under each account (e.g.
channels.rocketchat.accounts.prod.rooms).
Reply routing (thread vs channel)
channels:
rocketchat:
# thread | channel | auto
replyMode: auto
rooms:
GENERAL:
requireMention: false
# Optional per-room override
# replyMode: channelAuto rules (deterministic):
- If the inbound message is already in a thread (
tmidexists) → reply in that thread - Else if the inbound message is “long” (≥280 chars or contains a newline) → reply in a thread
- Else → reply in channel
Per-message overrides
Prefix your message:
!thread ...→ force the reply to be posted as a thread reply!channel ...→ force the reply to be posted in the channel
(The prefix is stripped before the message is sent to the agent.)
Typing indicator
channels:
rocketchat:
# Delay (ms) before emitting typing indicator
typingDelayMs: 500(When using multiple accounts, this can also be set per account at channels.rocketchat.accounts.<accountId>.typingDelayMs.)
Typing indicators are emitted via DDP stream-notify-room using <RID>/user-activity.
- Channel replies emit typing without
tmid→ shows under channel composer - Thread replies include
{ tmid: ... }→ shows under thread composer
Development
git clone [email protected]:cloudrise-network/openclaw-channel-rocketchat.git
cd openclaw-channel-rocketchat
npm installLocal smoke tests (uses env vars; see .env.example):
# REST send
node test-chad.mjs
# Realtime receive
node test-realtime.mjsPackaging + publishing (no secrets)
Before publishing:
- Run a quick secret scan (at minimum):
grep -RIn --exclude-dir=node_modules --exclude=package-lock.json -E "npm_[A-Za-z0-9]+|ghp_[A-Za-z0-9]+|xox[baprs]-|authToken\s*[:=]\s*\"" .Bump version in
package.json.Verify the tarball:
npm pack- Publish:
npm publish(There is also a GitHub Actions workflow in .github/workflows/publish.yml.)
DM Access Control
The plugin supports multiple DM access control modes, including a unique Owner Channel Approval flow.
DM Policies
channels:
rocketchat:
dmPolicy: "owner-approval" # or "open" | "pairing" | "allowlist" | "disabled"| Policy | Behavior |
|--------|----------|
| open | (Default) All DMs allowed. Rocket.Chat server-level auth is the only gate. |
| owner-approval | 🆕 Unknown senders trigger approval request to owner channel. No CLI needed! |
| pairing | Unknown senders get a pairing code. Owner approves via CLI. |
| allowlist | Only users in allowFrom can DM. Others are silently blocked. |
| disabled | All DMs blocked. |
Owner Channel Approval (Recommended)
Approve or deny users directly in Rocket.Chat — no CLI needed!
channels:
rocketchat:
dmPolicy: "owner-approval"
ownerApproval:
enabled: true
# Where to send approval notifications
notifyChannels:
- "@admin" # DM to specific user
- "room:APPROVERS" # or a dedicated room
# Who can approve (supports Rocket.Chat roles!)
approvers:
- "@marshal" # specific username
- "role:admin" # anyone with RC admin role
- "role:moderator" # anyone with moderator role
# Notify requester when decision is made
notifyOnApprove: true
notifyOnDeny: true
# Optional timeout (seconds)
timeout: 3600
onTimeout: "pending" # or "deny" or "remind"Flow:
- Unknown user sends a DM
- Bot notifies owner channel:
"🔔 New DM request from @user123" - Owner replies:
--approve @user123or--deny @user123 - Requester gets notified:
"✅ You've been approved!" - Future messages are processed normally
Commands (in owner channel or DM to bot):
--approve @user123 # approve a user
--deny @user123 # deny a user
--approve room:GENERAL # approve a room
--pending # list pending requests💡 Note: Rocket.Chat has built-in
/slashcommands that may intercept messages starting with/. Use--prefix instead (e.g.,--approvenot/approve).
Channel/Room Approval (groupPolicy)
Control which channels the bot responds in:
channels:
rocketchat:
groupPolicy: "owner-approval" # or "open" | "allowlist" | "disabled"| Policy | Behavior |
|--------|----------|
| open | (Default) Bot responds in any channel it's added to. |
| owner-approval | Bot sends "pending approval" on first message in new channels. |
| allowlist | Only channels in groupAllowFrom receive responses. |
| disabled | Bot ignores all channel messages. |
With groupPolicy: "owner-approval":
- When invited to a new channel, first message triggers approval request
- Approvers receive:
"🔔 Bot invited to #channel-name by @user" - Approve with:
--approve room:ROOMID
🔑 Auto-Approval (Important!)
Approvers and notify channels are automatically allowed through access gates — no manual pre-approval needed!
| ownerApproval Entry | DM Gate | Channel/Group Gate |
|-----------------------|---------|-------------------|
| approvers: ["@user"] | ✅ Auto-allowed | ✅ Auto-allowed (in any room) |
| notifyChannels: ["room:ID"] | N/A | ✅ Auto-allowed |
Minimal recommended config (no lockout risk):
channels:
rocketchat:
dmPolicy: "owner-approval"
groupPolicy: "owner-approval"
ownerApproval:
enabled: true
approvers:
- "@yourusername" # You can DM the bot + approve in any room
notifyChannels:
- "room:YOUR_MAIN_ROOM_ID" # This room is auto-approved
notifyOnApprove: true
notifyOnDeny: trueThat's it! With this config:
- ✅ You can DM the bot (you're an approver)
- ✅ Your main room works (it's a notify channel)
- ✅ Approval commands work in your main room
- 🔒 Everyone else needs approval
Manual Pre-Approval (Optional)
If you need to pre-approve additional users or rooms that aren't approvers/notifyChannels:
In config:
channels:
rocketchat:
allowFrom: # Pre-approved DM users
- "@alice"
- "@bob"
groupAllowFrom: # Pre-approved rooms
- "room:GENERAL"
- "#support"Or via files:
# Pre-approve DM users
echo '{"version":1,"entries":["alice","bob"]}' > ~/.openclaw/credentials/rocketchat-allowFrom.json
# Pre-approve rooms
echo '{"version":1,"entries":["GENERAL"]}' > ~/.openclaw/credentials/rocketchat-rooms-allowFrom.jsonPer-Room User Access Control
Control which users can interact with the bot within each approved room:
channels:
rocketchat:
rooms:
GENERAL:
# Response mode for approved users
responseMode: "mention-only" # or "always" (default)
# Who can interact (static list)
canInteract:
- "@alice"
- "@bob"
- "role:admin"
- "role:moderator"
# Who can approve/deny users for THIS room
roomApprovers:
- "role:owner" # Room owners
- "role:moderator"
- "@marshal"
# When non-approved user @mentions bot
onMentionUnauthorized: "ignore" # or "reply" (sends "not authorized")
SUPPORT:
# No restrictions - everyone in the room can interact
responseMode: "always"Room-level commands (usable by roomApprovers):
--room-approve @alice # Approve alice for THIS room only
--room-deny @alice # Remove alice from this room's approved list
--room-list # Show who's approved in this roomHow it works:
- Room gets global approval (via
groupPolicy) - Per-room user check: is sender in
canInteract,roomApprovers, or dynamically approved? - If not approved:
- Silent ignore (unless
onMentionUnauthorized: "reply")
- Silent ignore (unless
- If approved:
- Check
responseMode— respond always or only when @mentioned
- Check
Storage: ~/.openclaw/credentials/rocketchat-room-users.json
Note: Global approvers (ownerApproval.approvers) can interact in ANY room, regardless of per-room settings.
CLI-Based Pairing
If you prefer CLI-based approval:
channels:
rocketchat:
dmPolicy: "pairing"
allowFrom:
- "@admin" # pre-approved usersFlow:
- Unknown user sends a DM
- Bot replies with a pairing code:
"Pairing required. Code: ABC12345" - Owner approves via CLI:
openclaw pairing list rocketchat openclaw pairing approve rocketchat ABC12345 - User is added to allowlist
Why is the default "open"?
Unlike public platforms (Telegram, WhatsApp, Signal), Rocket.Chat is typically:
- Self-hosted with authenticated users
- Behind organizational access controls
- Already requires user accounts to message
So server-level authentication acts as the primary gate. Use owner-approval or pairing if you need per-user approval on top of that.
Security
Treat Rocket.Chat authToken like a password.
This repository is intended to be publishable (no secrets committed).
License
MIT
