NousResearch/hermes-agent#17751 (merged 2026-04-30) shipped a
comprehensive pluggable-platform system with:
- ctx.register_platform(name, label, adapter_factory, check_fn, ...)
- Open Platform enum (Platform('molecule') creates a pseudo-member
via _missing_() when the platform_registry knows about it)
That supersedes my upstream PR #18775 (which used a narrower
register_platform_adapter shape with a closed enum + custom
PluginPlatformIdentifier). Closing #18775 as redundant.
This plugin previously coupled to my fork's API. Migration:
- __init__.py register() now prefers ctx.register_platform when
available; falls back to ctx.register_platform_adapter on legacy
forks (template-hermes' baked-in fork until it migrates).
- adapter.py constructs Platform(name) when the enum accepts
'molecule', else falls back to PluginPlatformIdentifier(name).
Same wheel installs cleanly on stock hermes-agent (post-#17751)
AND on the legacy template-hermes fork build. Removed the test
stub of PluginPlatformIdentifier; tests now stub the open-enum
Platform shape with the same _missing_() behavior the upstream
ships.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|---|---|---|
| .github/workflows | ||
| hermes_channel_molecule | ||
| tests | ||
| .gitignore | ||
| LICENSE | ||
| pyproject.toml | ||
| README.md | ||
hermes-channel-molecule
Hermes platform plugin that connects an external hermes-agent to the Molecule platform via the molecule-runtime A2A MCP server.
What this is for
You run hermes-agent on your own machine. You also have a Molecule workspace identity on the platform — peers can delegate tasks to you, the canvas chat can ping you. Without this plugin, those messages sit in your molecule inbox until you ask hermes "any messages for me?". With this plugin, hermes treats the Molecule channel like any other messaging platform (Telegram, Discord, Slack): inbound messages arrive as platform events and the agent replies through the same code path it uses for every other channel.
If your hermes runs inside a Molecule workspace container (rather than externally), use hermes-platform-molecule-a2a instead — that plugin uses the in-container HTTP callback path.
Architecture
hermes-agent (your machine)
│
│ stdio JSON-RPC
▼
python -m molecule_runtime.a2a_mcp_server (subprocess)
│
│ long-poll: wait_for_message
▼
Molecule platform inbox
│
├── canvas user typing in your workspace chat
└── peer agents sending A2A messages
MoleculeAdapter.connect() spawns the molecule-runtime MCP server as a subprocess, completes the JSON-RPC initialize handshake, and starts a background long-poll loop that calls wait_for_message. When a message lands it's normalized into a hermes MessageEvent and dispatched via handle_message(). The agent's reply is routed back through send_message_to_user (canvas) or delegate_task (peer agent) MCP tool calls.
Install
Pip (recommended)
pip install hermes-channel-molecule
The plugin loads via the hermes_agent.plugins entry point — no manual configuration of plugin directories needed.
Direct (no PyPI)
git clone https://github.com/Molecule-AI/hermes-channel-molecule.git
cp -r hermes-channel-molecule/hermes_channel_molecule ~/.hermes/plugins/molecule
Hermes discovers any directory under ~/.hermes/plugins/ containing a plugin.yaml and an __init__.py with a register(ctx) function.
Configure
Add this to ~/.hermes/config.yaml:
gateway:
platforms:
molecule:
enabled: true
Set the required env vars (your workspace identity on the Molecule platform):
export MOLECULE_WORKSPACE_ID=ws-... # from the platform
export MOLECULE_WORKSPACE_TOKEN=tok-... # from canvas → Tokens tab
export MOLECULE_PLATFORM_URL=https://your-tenant.moleculesai.app
export MOLECULE_ORG_ID=org-... # from the platform
MOLECULE_WORKSPACE_TOKEN is the per-workspace platform credential. Inside a molecule-managed container the runtime reads it from /configs/.auth_token (the platform writes it on provision). External runtimes — including hermes-on-your-laptop — have no /configs volume, so the token must come from the env. Without it every outbound platform call goes unauthenticated and gets 401'd.
Optional:
export MOLECULE_CONFIGS_DIR=/configs # default
export MOLECULE_MCP_PYTHON=/opt/molecule-venv/bin/python3 # python that has molecule_runtime
Restart hermes:
hermes gateway --replace
You should see in the gateway log:
[molecule] MCP initialize ok (server=a2a-delegation)
Verify
The agent can now receive messages on the Molecule channel. Send yourself a message from another workspace via the platform's canvas, or have a peer agent delegate a task to your workspace_id. Hermes will dispatch it through the normal message-handling path and reply back through the molecule platform.
How chat IDs are encoded
The plugin synthesizes hermes chat IDs with a routing prefix:
| chat_id format | Origin | Reply path |
|---|---|---|
canvas:<ws_id> |
Canvas user typing in your workspace chat | send_message_to_user |
peer:<peer_ws_id> |
Peer agent A2A message to your workspace | delegate_task |
The prefix is opaque to the gateway — it just sees a chat_id like any other platform — but the adapter parses it on the way out to pick the right MCP tool.
Development
git clone https://github.com/Molecule-AI/hermes-channel-molecule.git
cd hermes-channel-molecule
pip install -e ".[test]"
pytest -q
The integration tests stand up a small fake MCP server (a Python script that speaks JSON-RPC over stdio) so they exercise the real subprocess + handshake + framing code path. No mocking of asyncio.create_subprocess_exec.
License
Apache-2.0. See LICENSE.