Skip to content

feat(plugins): add Rocket.Chat platform adapter as bundled plugin - #30463

Closed
HearthCore wants to merge 3 commits into
NousResearch:mainfrom
HearthCore:fix/rocketchat-slash-command-position
Closed

feat(plugins): add Rocket.Chat platform adapter as bundled plugin#30463
HearthCore wants to merge 3 commits into
NousResearch:mainfrom
HearthCore:fix/rocketchat-slash-command-position

Conversation

@HearthCore

Copy link
Copy Markdown
Contributor

Summary

Adds a Rocket.Chat gateway adapter as a self-contained plugin (kind: platform) in plugins/platforms/rocketchat/. Built on aiohttp — zero new Python dependencies.

Background

This work is based on PR #14869 by @cyb0rgk1tty, refactored from the core gateway/platforms/ approach into the modern standalone plugin format introduced by PR #17664 / #17751. Many thanks to @cyb0rgk1tty for the original implementation and to @meron1122 (PR #4637) for the parallel plugin-structure work — both served as valuable references.

Architecture

Layer Direction Protocol
Inbound (receive) RC → Hermes DDP WebSocket (stream-room-messages:my_messages)
Outbound (send) Hermes → RC REST API v1 (chat.postMessage)
File upload Hermes → RC Two-step rooms.media + rooms.mediaConfirm
Cron sender Hermes → RC Standalone REST-only (no WS dependency)

Key Design Decisions

  1. Slash command position-0 only/ is matched at position 0 in both raw_msg and message_text (DMs may retain @mention prefix). Mid-sentence /status is correctly ignored. Hermes-known commands gate via is_gateway_known_command() before falling through to RC's commands.run.
  2. Bidirectional topic sync — Hermes session titles propagate back to RC room topics via dm.setTopic / groups.setTopic / channels.setTopic. Power-on self-topic on connect.
  3. TTS audio pipeline — WebM/OGG voice messages are converted to MP3 via ffmpeg for STT compatibility.
  4. Emoji reactions on channel messages (suppressed in DMs).
  5. Deferred attachments — file-only uploads are held per-room (5-min TTL) and merged with the next text message for natural workflows.
  6. DDP reconnect with exponential backoff (2s–60s). Full re-login + re-subscribe since RC doesn't resume DDP subs.

Files Changed

File Lines Purpose
plugins/platforms/rocketchat/adapter.py +1,464 Full adapter — transport, parsing, media, reactions, cron
plugins/platforms/rocketchat/plugin.yaml +48 Plugin manifest with env var metadata
plugins/platforms/rocketchat/init.py +3 Plugin discovery entry point
plugins/platforms/rocketchat/README.md +120 User-facing setup guide
plugins/platforms/rocketchat/AGENTS.md +153 AI-assistant development reference

Note: this is a pure plugin addition (kind: platform) — zero changes to Hermes core files.

Env Var Contract

Variable Required Description
ROCKETCHAT_URL Yes Server URL (e.g. https://rc.example.com)
ROCKETCHAT_TOKEN Yes Personal Access Token (generate with "Ignore Two Factor" checked)
ROCKETCHAT_USER_ID Yes Bot user _id
ROCKETCHAT_ALLOWED_USERS No Comma-separated allowed user IDs
ROCKETCHAT_ALLOW_ALL_USERS No Allow all users (dev only)
ROCKETCHAT_HOME_CHANNEL No Room ID for cron delivery
ROCKETCHAT_REQUIRE_MENTION No Require @mention in channels (default: true)
ROCKETCHAT_FREE_RESPONSE_CHANNELS No Rooms exempt from mention requirement
ROCKETCHAT_REPLY_MODE No thread for threaded replies, off for flat (default: off)

How to Test

# 1. Configure
export ROCKETCHAT_URL=https://your-rc-instance.com
export ROCKETCHAT_TOKEN=your_pat
export ROCKETCHAT_USER_ID=your_bot_id
export ROCKETCHAT_ALLOW_ALL_USERS=true

# 2. Start gateway with plugin
hermes gateway

# 3. DM the bot or @mention it in a channel
# 4. Verify slash commands (/new, /status, /dashboard, etc.)
# 5. Verify file uploads and voice messages

Desktop RC Note

The Rocket.Chat Desktop/Browser client intercepts unknown / commands client-side. To use Hermes commands on desktop, set Message_AllowUnrecognizedSlashCommand = true in RC Admin (Settings -> Message) or via env OVERWRITE_SETTING_Message_AllowUnrecognizedSlashCommand=true. Mobile clients work out of box.

Testing

Tested live against a self-hosted Rocket.Chat 8.x instance with:

  • Full LLM roundtrip (DM + channel)
  • Voice message to STT pipeline
  • Slash command routing (position-0 + mid-sentence rejection)
  • File upload/download
  • Bidirectional topic sync
  • DDP reconnect after server restart

Co-authored-by: HearthCore timo.goetzken@gmail.com

Adds a Rocket.Chat gateway adapter as a self-contained plugin
(kind: platform) in plugins/platforms/rocketchat/.

Based on PR NousResearch#14869 by @cyb0rgk1tty, refactored from
gateway/platforms/ into the modern plugin format — zero core
Hermes changes needed. Thanks also to @meron1122 (PR NousResearch#4637)
for the parallel plugin-structure approach.

Features:
- DDP WebSocket (__my_messages__) for inbound messages
- REST API v1 (chat.postMessage) for outbound writes
- Two-step file upload via rooms.media + rooms.mediaConfirm
- Attachment download with image/audio/document caching
- Voice message → MP3 conversion via ffmpeg for STT
- Thread support via tmid
- Bidirectional Hermes session title ↔ RC room topic sync
- Mention gating with free-response room exceptions
- Slash command routing (position-0 only, gate via
  is_gateway_known_command())
- typing indicator (Rocket.Chat 8.x compatible)
- Emoji reactions (👀✅❌) on channel messages
- DDP reconnect with exponential backoff (2s–60s)
- Standalone REST-only sender for cron delivery
- Interactive setup wizard (hermes gateway setup)
- Plugin.yaml manifest with full env var metadata
- AGENTS.md for AI assistant development reference
- README.md with setup guide and troubleshooting

Signed-off-by: HearthCore <timo.goetzken@gmail.com>
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/plugins Plugin system and bundled plugins comp/gateway Gateway runner, session dispatch, delivery labels May 22, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Supersedes #4637 and #14869 (both open Rocket.Chat PRs). Author acknowledges both as references and refactored into the modern standalone plugin format.

Hermes Agent (Timo) added 2 commits May 22, 2026 16:28
The README was originally written in German for local use. Since
this PR targets the upstream repo, the documentation needs to be
in English — the project's lingua franca.
@AdrianScott

Copy link
Copy Markdown
Contributor

i'm a rocket-chat user excited about this, thank you @HearthCore

some suggestions for consideration:

  • pls note check re contributor attribution check above

following feedback via codex-5.5 (not too worried about file size caps on first version of this myself):

    • DDP login/subscription does not appear to wait for login success before
      subscribing. [ i had my own plugin i vibe-coded and this was definitely an issue on first version, so something to check out. ]
  • No unit tests are included in feat(plugins): add Rocket.Chat platform adapter as bundled plugin #30463 itself, despite older PRs mentioning
    tests.
  • _send_url_as_file() downloads full response bodies without an explicit size
    cap.
  • _send_local_file() reads the entire file into memory before upload.
  • _download_attachments() downloads Rocket.Chat attachments without a size
    cap.
  • Topic sync builds SessionSource(..., chat_type="dm") unconditionally at
    adapter.py lines ~527-531, even for groups/channels. That looks like a
    likely behavior bug.
  • ROCKETCHAT_ALLOW_ALL_USERS=true is available and dangerous if enabled on a
    real workspace.

other auto-feedback:
Do a security hardening pass:

  • Add max download/upload size limits.
  • Validate ROCKETCHAT_URL scheme is https unless explicitly allowing
    local/dev.
  • Avoid exposing missing file paths in user-visible messages where
    possible.
  • Confirm allowlist behavior with tests.
  • Keep ROCKETCHAT_ALLOW_ALL_USERS=false by default.
  1. Fix obvious correctness issues:
  • Use actual chat_type in topic sync instead of hardcoded "dm".
  • Wait for DDP login/subscription confirmation or handle login errors
    explicitly.
  • Clean trailing whitespace.
  1. Add focused tests:
  • Plugin registration.
  • Env/config validation.
  • Authorization env var registration.
  • Mention gating.
  • Slash command routing.
  • URL safety block.
  • Attachment download size cap.
  • ffmpeg subprocess argv behavior.

@sevenjay sevenjay mentioned this pull request Jun 15, 2026
1 task
@chris2k20

Copy link
Copy Markdown

Any updates on that?

@florisvangeel

Copy link
Copy Markdown
 Quick progress update from testing the Rocket.Chat gateway adapter locally.                        
                                                                                                    
 Successes:                                                                                         
 - Rocket.Chat REST auth works with a personal access token.                                        
 - The bot account authenticates successfully via /api/v1/me.                                       
 - The bot is subscribed to the target rooms, including #general and #bots.                         
 - The Hermes plugin registry loads the Rocket.Chat platform correctly.                             
 - The gateway config reports Rocket.Chat as an enabled/connected platform.                         
 - The adapter factory creates RocketchatAdapter successfully.                                      
 - Manual async adapter connect() succeeds and sets is_connected=True.                              
 - Gateway now runs under the user hermes-gateway.service.                                          
                                                                                                    
 Important env variable findings:                                                                   
 - These Rocket.Chat env vars are already present in the source:              
   - ROCKETCHAT_ALLOWED_USERS                                                                       
   - ROCKETCHAT_ALLOW_ALL_USERS                                                                     
   - ROCKETCHAT_HOME_CHANNEL                                                                        
   - ROCKETCHAT_REQUIRE_MENTION                                                                     
   - ROCKETCHAT_FREE_RESPONSE_CHANNELS                                                              
   - ROCKETCHAT_REPLY_MODE                                                                          
   - ROCKETCHAT_REACTIONS                                                                           
 - plugin.yaml documents:                                                                           
   - ROCKETCHAT_ALLOWED_USERS                                                                       
   - ROCKETCHAT_ALLOW_ALL_USERS                                                                     
   - ROCKETCHAT_HOME_CHANNEL                                                                        
   - ROCKETCHAT_REQUIRE_MENTION                                                                     
   - ROCKETCHAT_FREE_RESPONSE_CHANNELS                                                              
   - ROCKETCHAT_REPLY_MODE                                                                          
 - ROCKETCHAT_MAX_UPLOAD_BYTES and ROCKETCHAT_MAX_DOWNLOAD_BYTES were not in HEAD; those appear     
 to be local safety additions for media transfer limits.                                            
                                                                                                    
 Finding around free-response channels:                                                             
 - ROCKETCHAT_FREE_RESPONSE_CHANNELS is implemented.                                                
 - The current logic compares entries against the Rocket.Chat room id (rid), not the display        
 name.                                                                                              
 - So ROCKETCHAT_FREE_RESPONSE_CHANNELS=#bots will likely not match.                                
 - It works when set to the actual room id for #bots.                                               
                                                                                                    
 Current remaining issue:                                                                           
 - Even though the adapter config and manual connection tests pass, the generic Hermes              
 send_message(action="list") path still reported no connected messaging platforms/channels.         
 That seems separate from basic Rocket.Chat API/auth/plugin loading.                                
                                                                                                    
 Possible improvements:                                                                             
 - Accept both room ids and channel names in ROCKETCHAT_FREE_RESPONSE_CHANNELS, e.g. #bots,         
 bots, and the raw room id. 
 - Log which Rocket.Chat rooms are subscribed after DDP login, to make free-response debugging      
 easier.                                                                      
 - Document clearly that ROCKETCHAT_FREE_RESPONSE_CHANNELS currently expects room ids.              
 - Add a small integration test for mention-gating vs free-response room behavior.                  
 - Investigate why send_message(action="list") does not discover Rocket.Chat despite successful     
 adapter-level validation.

Thanks for the great work, Floris + Hermes.

@iiicebearrr

Copy link
Copy Markdown

Any updates?

@engelgabriel

engelgabriel commented Jul 6, 2026

Copy link
Copy Markdown

Heads up on a related change landing upstream that could simplify the outbound half of this adapter down the line: RocketChat/Rocket.Chat#41082 adds a native MCP server to Rocket.Chat, exposing its REST API as MCP tools over JSON-RPC 2.0 at /api/v1/mcp.

Why it's relevant here

This adapter currently hand-rolls all of its outbound traffic against Rocket.Chat's REST API — sending messages, file upload/download, reactions, topic sync, slash-command routing. That same REST surface is exactly what #41082 wraps as MCP tools, with authentication, permission checks, rate limiting, and CORS handled server-side. Since Hermes is already MCP-capable, a good chunk of that bespoke REST plumbing could eventually be replaced by MCP tool calls instead — less integration code to maintain, and it tracks Rocket.Chat's API automatically rather than drifting.

Scope — outbound only

To be clear, this only touches the outbound path. The inbound side of this adapter relies on a DDP WebSocket subscription for real-time message delivery, and #41082 is request/response only (no streaming/subscription for receiving messages). So the WebSocket layer stays exactly as-is regardless — MCP doesn't replace it.

Not a dependency to adopt now

Flagging this as a future simplification path, not something to take on in this PR:

  • #41082 is still a draft and hasn't merged.
  • Only an allow-listed subset of tools is exposed, so it may not cover 100% of what this adapter does.

Suggest we keep the current REST implementation as-is for this PR and revisit routing outbound calls through MCP once #41082 lands and stabilizes — potentially as an optional backend that's used when the target instance has it enabled.

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the substantial standalone-platform implementation and for preserving the earlier Rocket.Chat contributors as references.

This automated hermes-sweeper review is closing this under the standing in-tree-provider-integration policy:

  • plugins/platforms/rocketchat/plugin.yaml:1-3 adds a bundled Rocket.Chat platform integration under plugins/.
  • AGENTS.md:797-813 requires integrations for third-party products to ship as standalone plugin repositories rather than in this core tree.
  • The existing plugin discovery path supports the intended alternative: publish this as a standalone plugin users install into ~/.hermes/plugins/ or via a pip entry point, and promote it in #plugins-skills-and-skins.

This is a coupling and maintenance policy, not a judgment on the quality or usefulness of the work.


Closed as not-planned per standing maintainer policy (in-tree-provider-integration). This is a design-direction decision, not a code-quality judgment — see the Contribution Rubric in AGENTS.md for what the project is looking for. If you believe this policy was misapplied to your change, comment here and a maintainer will take a look.

@teknium1 teknium1 closed this Jul 13, 2026
@teknium1 teknium1 added the sweeper:not-planned Sweeper: closed per standing maintainer policy (design direction) label Jul 13, 2026
@meron1122

Copy link
Copy Markdown

I published plugin powerup with amazing features from @HearthCore and a few more. Feel free to use and contribute
https://github.com/HalfbitStudio/hermes-plugin-rocketchat

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have sweeper:not-planned Sweeper: closed per standing maintainer policy (design direction) type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants