11 KiB
Runtime native-MCP push parity — status
Goal: every workspace runtime delivers Molecule A2A inbox messages
with the same UX as claude-code's MCP notifications/claude/channel
push: session continuity + queued or interrupted handling of new
messages mid-thread, no fresh subprocess per message.
Tracked across four runtime streams. Updated 2026-05-02.
claude-code
Status: ✅ Done. Native MCP notifications/claude/channel push
shipped via workspace/a2a_mcp_server.py. Requires the host to launch
with --dangerously-load-development-channels server:molecule.
No further work.
OpenClaw
Status: Scaffolded; awaiting validation + companion adapter rewrite.
Path: Channel-plugin SDK (openclaw/plugin-sdk), auto-discovered
from ~/.openclaw/plugins/<name>/ or workspace .openclaw/. Plugin
registers an HTTP webhook on openclaw gateway; Molecule workspace
adapter POSTs A2A messages to it; gateway dispatches through the same
dispatchReplyWithBufferedBlockDispatcher kernel call native channels
(Telegram, Lark, Slack, Discord) use.
Artifacts landed:
molecule-ai-workspace-template-openclaw/packages/openclaw-channel-plugin/package.json,openclaw.plugin.json(manifest),index.ts(channel + webhook handler),README.md,tsconfig.json
- Pre-release
v0.1.0-pre. Mirrorsrabbit-lark-botreference plugin shape.
Remaining (task #84, #87):
- Validate against a running OpenClaw gateway. Open questions in the
plugin README:
resolveAgentRoutepeer-id shape,dispatchReplyWithBufferedBlockDispatcherasync semantics,outbound.sendTextno-op safety. - Rewrite Python adapter (
adapter.py) to stop shelling outopenclaw agent --message ...and instead POST to the plugin's webhook + run/agent-replycallback HTTP server. Post-demo work (touches a working integration).
hermes
Status: Workspace template patch PR #32 MERGED 2026-05-02; image
rebuild succeeded; plugin baked into the workspace runtime. Plugin
package published. Real-subprocess full-chain E2E (scripts/e2e_full_chain.py)
green — proves wire shape end-to-end against a real hermes gateway run
subprocess + stub OpenAI-compat LLM. Caught + fixed a real KeyError
in upstream hermes_cli/tools_config.py (PLATFORMS dict lookup
crashed on plugin platforms) — fix on the patched fork branch
(molecule-ai/hermes-agent feat/platform-adapter-plugins, commit
18e4849e, hosted on Gitea at
https://git.moleculesai.app/molecule-ai/hermes-agent — moved from the
suspended github.com/HongmingWang-Rabbit/hermes-agent, see
molecule-ai/internal#72). Upstream PR #18775 OPEN; CONFLICTING with main.
Not on critical path for our platform — patched fork is what the
workspace image installs.
Real A2A peer traffic on staging gated only on running the harness
(molecule-core/scripts/test-all-runtimes-a2a-e2e.sh) — script ready,
needs provider keys.
Path: Hermes's MODERN plugin system is hermes_cli/plugins.py
(not the older plugins/memory/). It already does full discovery
across user dir + project dir + pip entry_points (group:
hermes_agent.plugins) for tools / hooks / CLI commands / slash
commands / context engines / skills. Platform adapters are the only
plugin type still hardcoded (gateway/run.py:_create_adapter).
The PR adds three pieces upstream:
PluginContext.register_platform_adapter(name, adapter_class, requirements_check=None)GatewayConfig.plugin_platformspopulated byfrom_dictfor plugin-claimed namesGatewayRunner._create_plugin_adapter(name, config)boot-path fallback
Plus a PluginPlatformIdentifier helper class so plugin adapters can
satisfy BasePlatformAdapter.__init__(config, platform: Platform)
without extending the closed Platform enum.
Total: ~100 LOC upstream change. External plugin then ships as
hermes-platform-molecule-a2a via pip install + entry_points — no
fork needed in production.
Artifacts landed:
- Upstream PR: NousResearch/hermes-agent#18775
— 5 commits on
feat/platform-adapter-plugins: registration surface, config + boot wiring,PluginPlatformIdentifierhelper,resolve_platform_idfor plugin-platform-safe deserialization, andself.adapters[adapter.platform]keying fix (caught by real-subprocess test before merge — see below). - Plugin package: Molecule-AI/hermes-platform-molecule-a2a
v0.1.0 — public, MIT-licensed. 11 unit tests + 8 in-process E2E
- 4 real-subprocess E2E checkpoints all green.
- Workspace template patch: Molecule-AI/molecule-ai-workspace-template-hermes#32
— Dockerfile installs the patched fork + plugin into the hermes
installer's venv; start.sh seeds
platforms.molecule-a2aconfig stanza. Pre-demo deliberately install-only; adapter.py rewrite to USE the plugin path is a separate post-demo PR. - Real adapter package at
~/hermes-platform-molecule-a2a/:pyproject.tomlwithhermes_agent.pluginsentry pointhermes_platform_molecule_a2a/adapter.py—MoleculeA2APlatformAdapter(BasePlatformAdapter)with HTTP listener (aiohttp), inboundMessageEvent(internal=True)dispatch, outboundsend()POST to per-chat callback URL, optional shared secret enforcementtests/test_adapter.py— 11/11 unit tests pass covering plugin entry-point shape, lifecycle, inbound auth, outbound routingscripts/e2e_validate.py— production-path validation (entry points → registry → GatewayConfig → boot → HTTP roundtrip), all 7 checkpoints pass
docs/integrations/hermes-platform-plugins-upstream-pr.md— PR draft including problem, prior art, proposal, code shape, backward compat, test plan, and open questions..hermes-validation/test_register_platform_adapter.py— local 9-check validation of the patched fork via the user-dir discovery path (complementary to the entry-points path tested by the package).
Why no short-term polling shim: earlier framing was wrong. Molecule
runtime already polls the inbox via wait_for_message per turn; each
polled message fires a fresh execute() on the adapter, which
proxies to hermes's stateless /v1/chat/completions. Adding adapter-
side polling would be duplicate work. The genuine short-term gap is
session continuity (hermes daemon doesn't see a single
conversation across turns because chat/completions is stateless), not
push latency. That gap is solved by the upstream PR; no
intermediate shim earns its complexity.
Remaining:
- Upstream PR review/merge (NousResearch/hermes-agent#18775). On maintainers — typical OSS review lag.
- Workspace template merge + image republish (PR #32). Once
merged,
publish-runtime.ymlregenerates the hermes workspace image with the plugin baked in. Safe to merge as-is — install-only, no behavior change for current workspaces. - Runtime adapter rewrite (task #87 equivalent for hermes).
molecule-ai-workspace-template-hermes/adapter.pycurrently proxies A2A →/v1/chat/completions. Switching to POST/a2a/inboundis what unlocks single-session continuity. Post-demo timing (touches a working live integration). - Real A2A peer traffic E2E (task #86): boot a real workspace from the republished image, send peer A2A message from another workspace, observe single-session reply. Gated on items 2 + 3.
Codex (OpenAI Codex CLI)
Status: Template SHIPPED. Repo live at
Molecule-AI/molecule-ai-workspace-template-codex
(14 files, 1411 LOC, 12/12 tests). molecule-core registration in
PR #2512.
E2E with real A2A traffic remains.
Path: Persistent codex app-server stdio JSON-RPC client
(NDJSON-framed, v2 protocol). One app-server child per workspace
session; one thread/start per session; each A2A message becomes a
turn/start RPC; agent responses arrive as
agent_message_delta notifications. Per-thread serialization for
mid-turn arrivals (matches OpenClaw's per-chat sequentializer).
Optional turn/interrupt for "latest message wins" workspaces.
Artifacts landed:
docs/integrations/codex-app-server-adapter-design.md— full design including RPC sequence, executor skeleton, eight open questions.molecule-ai-workspace-template-codex/— full template repo scaffolded:app_server.py(286 LOC) — async JSON-RPC over NDJSON stdioexecutor.py(~270 LOC) — thread bootstrap, turn dispatch, notification accumulation, mid-turn serializationadapter.py— thinBaseAdaptershell + preflightDockerfile,start.sh,config.yaml,requirements.txt,README.mdtests/— 12/12 tests pass (7 vs NDJSON mock child, 5 vs fake AppServerProcess covering executor logic)
Validated against live codex-cli 0.72.0: NDJSON framing,
initialize handshake, AND thread/start all work end-to-end.
Schema-runtime drift caught: real binary returns thread.id,
not thread.threadId as the JSON schema claims. Executor now
accepts both shapes; without the smoke test this would have been
a production bug.
Remaining (task #85, #86):
- Register
codexin molecule-core'smanifest.json+workspace-server/internal/handlers/runtime_registry.go. Defer to post-demo — touches working live registry. - E2E verification with a real Molecule workspace + peer A2A
traffic, per
feedback_close_on_user_visible_not_merge.
Cross-cutting (task #86)
End-to-end verification per feedback_close_on_user_visible_not_merge.
For each runtime, the closure criterion is not "code merged" but
"observed: real workspace boots → A2A message from peer agent →
delivered to running session → reply returned through A2A response
queue → peer agent receives". No runtime stream closes until that
chain is observed.
What's blocking what
| Stream | Blocked on |
|---|---|
| claude-code | (done) |
| OpenClaw plugin | live gateway validation, then post-demo adapter rewrite |
| OpenClaw adapter rewrite | post-demo timing |
| hermes upstream PR | user confirmation to submit + Discord pre-validation |
| hermes consumer plugin | upstream PR merging |
| codex implementation | resolve 8 open questions, then post-demo eng time |
| E2E verification | each runtime stream completing |
Three of four runtime streams are at decision points needing user input. Pre-demo (T-4d to 2026-05-06), the safe move is to land the remaining design + scaffolding work and defer all behavioral changes to post-demo.