Update-safe Hermes user plugin that adds Rocket.Chat as a gateway platform.
This package is meant to be copied into a Hermes profile under:
~/.hermes/plugins/rocketchat
It registers the platform name:
rocketchat
- Rocket.Chat platform registration as a Hermes user plugin, no Hermes core patch required.
- REST authentication against
/api/v1/me. - Room discovery through
/api/v1/subscriptions.get. - Realtime inbound messages through Rocket.Chat DDP
/websocketandstream-room-messages. - Outbound text messages through
/api/v1/chat.postMessage. - Thread-aware replies using Rocket.Chat
tmid. - Mention/allowlist controls for safe bot access.
- Reply modes:
thread,auto, and channel/off behavior. - Ack reactions through
/api/v1/chat.react. - Mark-as-read through
/api/v1/subscriptions.read. - Typing indicator through
/api/v1/typing. - Basic message edits through
/api/v1/chat.update. - Message deletion through
/api/v1/chat.deletefor ephemeral cleanup flows. - Native outbound media uploads for images, documents, video, and voice/audio.
- Generated Hermes images delivered as real Rocket.Chat attachments.
- Remote image/GIF URL handling: download temporarily with streaming size enforcement, upload natively, then clean up.
- Thread-aware native media uploads.
- Rocket.Chat native upload flow:
rooms.media/{rid}plusrooms.mediaConfirm. - Cleanup of empty markdown artifacts such as
![title]()after native file extraction. - Multiple-image sending via sequential native uploads.
- Missed-message handling on reconnect using DDP last-seen timestamps plus recent room history backfill.
- Rocket.Chat-friendly text fallbacks for clarify/confirmation prompts where buttons are unavailable.
- Optional DM-only Rocket.Chat E2EE support: decrypt incoming encrypted DM text and encrypt outgoing DM replies using keys that already exist in Rocket.Chat. Hermes never creates, rotates, requests, shares, accepts/rejects, or replaces E2E keys; if a key is missing, the user must set/share it in Rocket.Chat first.
- Inbound image attachments in E2EE DMs are decrypted from Rocket.Chat's AES-CTR encrypted file payloads, then accepted only after byte-level PNG/JPEG/GIF/WebP verification before caching them for Hermes vision.
- Plugin-local
e2e1control command for one-shot encrypted DM exchanges when Hermes already has the room key. Legacy slash aliases are accepted but not recommended because Rocket.Chat may show parser warnings. - Persistent DM E2EE mode:
e2e_onkeeps the DM encrypted across turns until the user sendse2e_offas an encrypted message. Also supportse2e_statusfor read-only helper/key-state diagnostics. - Test coverage for transport, upload, backfill, prompt fallback, and deletion behavior.
rocketchat/
__init__.py
adapter.py
e2e.py
plugin.yaml
test_adapter.py
README.md
HANDOFF.md
AGENTS.md
- Copy the extracted
rocketchatdirectory to the target Hermes home:
mkdir -p ~/.hermes/plugins
cp -R rocketchat ~/.hermes/plugins/rocketchat- Enable the plugin:
hermes plugins enable rocketchat-platform- Add Rocket.Chat credentials to
~/.hermes/.envor Hermes config. Do not paste secrets into chat/logs.
Minimum environment variables:
ROCKETCHAT_URL=https://your-rocket-chat.example.com
ROCKETCHAT_USER_ID=your-bot-user-id
ROCKETCHAT_AUTH_TOKEN=your-bot-auth-token
ROCKETCHAT_ALLOWED_USERS=mark,jakeCommon optional environment variables:
ROCKETCHAT_ALLOW_ALL_USERS=false
ROCKETCHAT_HOME_CHANNEL=ROOM_ID
ROCKETCHAT_REPLY_MODE=thread
ROCKETCHAT_AUTO_THREAD_CHARS=280
ROCKETCHAT_REQUIRE_MENTION=false
ROCKETCHAT_ACK_REACTION=eyes
ROCKETCHAT_MARK_AS_READ=true
ROCKETCHAT_BACKFILL_ON_CONNECT=true
ROCKETCHAT_BACKFILL_WINDOW_SECONDS=300
# Optional DM-only E2EE. Configure the same recovery key used by the Rocket.Chat client.
# Hermes only reads existing E2E identities/room keys; it does not create or change keys.
ROCKETCHAT_E2E_ENABLED=true
ROCKETCHAT_E2E_DM_ONLY=true
ROCKETCHAT_E2E_PASSWORD_FILE=~/.hermes/secrets/rocketchat-e2e.env- Enable the platform in
~/.hermes/config.yamlif needed:
gateway:
platforms:
rocketchat:
enabled: true
extra:
url: "https://your-rocket-chat.example.com"
user_id: "<bot user id>"
reply_mode: "thread"
auto_thread_chars: 280
require_mention: false
ack_reaction: "eyes"
mark_as_read: true
backfill_on_connect: true
backfill_window_seconds: 300
e2e:
enabled: true
dm_only: true
password_file: "~/.hermes/secrets/rocketchat-e2e.env"- Restart Hermes gateway after installing or upgrading:
hermes gateway restartOr foreground smoke test:
hermes gateway runExpected startup log shape:
Rocket.Chat: authenticated as @<botname> (...) on https://...
Rocket.Chat: tracking N subscribed rooms
Rocket.Chat: connecting realtime websocket to wss://.../websocket
From a Hermes source/venv install, adjust paths as needed:
python -m py_compile ~/.hermes/plugins/rocketchat/adapter.py
python -m pytest ~/.hermes/plugins/rocketchat/test_adapter.py -q -o 'addopts='Expected current result:
56 passed
- Send Hermes a normal text message from an allowed Rocket.Chat user.
- Confirm Hermes replies in the expected room/thread.
- Ask Hermes to generate or send an image and confirm it appears as a native Rocket.Chat attachment.
- Send a remote image/GIF URL through a Hermes flow and confirm it uploads as an attachment, not just a bare URL.
- Confirm a long reply or thread reply preserves
tmidbehavior according to configured reply mode. - Restart the gateway, send a message during downtime, then confirm recent-message backfill catches it after reconnect if within the backfill window.
- Test
/approve,/always, and/cancelstyle confirmation text in Rocket.Chat if using command approval flows. - For one-shot E2EE DMs: enable plugin E2E, send
e2e1in the DM, wait for the plaintext “E2E ready” control reply, then send one encrypted message. Hermes should decrypt it, answer encrypted, and then disable room E2E again. - For persistent E2EE DMs: send
e2e_on, wait for “E2E persistent mode ready”, then continue chatting. To leave persistent mode, send encryptede2e_off. Usee2e_statusbefore encryption or encryptede2e_statusduring persistent mode to inspect helper/key state. Legacy/e2eslash aliases are accepted but may trigger Rocket.Chat “unknown command”/“not allowed” UI messages.
- This is a user plugin, not an upstream Hermes core platform.
- It uses REST for stable operations and DDP only for inbound realtime delivery.
- E2EE is deliberately conservative: DM/private-room text crypto is implemented, inbound encrypted image attachments are decrypted and accepted only after byte-level image verification, and the adapter defaults to DM-only. Encrypted media/file upload from Hermes is not implemented yet. Gateway-side E2EE is read-only for keys: Hermes only unwraps and uses an existing Rocket.Chat E2E identity and room key. If the identity or room key is missing/unreadable, Hermes reports that the key must be set/shared in Rocket.Chat first; it does not create, rotate, request, share, accept/reject, or replace keys. Use deliberate non-slash controls:
e2e1for one-shot,e2e_onfor persistent mode,e2e_offto disable, ande2e_statusfor diagnostics. Do not put sensitive content in control messages; send sensitive content only after the ready prompt. Slash aliases are accepted for compatibility but are not recommended because Rocket.Chat's slash-command parser may show parser warnings or block them while encrypted. - Rocket.Chat's DDP/realtime APIs are marked deprecated in current docs, but still remain useful for bot-style realtime inbound messages unless replacing with polling, webhooks, or a Rocket.Chat App.
- Keep secrets in
.envor config; never commit them into this plugin directory.
Reliability/protocol ideas were informed by Jake Miller's MIT rocketchat-openclaw plugin, then ported into Hermes-native Python/asyncio BasePlatformAdapter semantics.