From 4ea6f437e926c2fa0c8fc7827f2e9f0035bc6903 Mon Sep 17 00:00:00 2001 From: Hongming Wang Date: Mon, 4 May 2026 18:28:35 -0700 Subject: [PATCH 1/2] feat(external-templates): codex tab now includes the bridge-daemon inbound path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The codex tab in the External Connect modal had a "outbound-tools-only first cut" caveat — operators got the MCP wiring for codex calling platform tools, but there was no documented inbound path. Canvas messages couldn't wake an idle codex session. That gap is now filled by codex-channel-molecule (github.com/Molecule-AI/codex-channel-molecule), shipped today as the codex counterpart to hermes-channel-molecule. The daemon long-polls the platform inbox, runs `codex exec --resume ` per inbound message, captures the assistant reply, routes it back via send_message_to_user / delegate_task, and acks the inbox row. Per-thread session continuity persisted to disk so daemon restarts don't lose conversation context. This commit: - Updates externalCodexTemplate to include `pip install codex-channel-molecule` (step 1) and a foreground `nohup codex-channel-molecule` invocation (step 3) using the same env-var contract as the MCP server (WORKSPACE_ID + PLATFORM_URL + MOLECULE_WORKSPACE_TOKEN). - Adds a "Canvas messages don't wake codex" common-issues entry to the TAB_HELP codex section pointing at the bridge daemon log. - Updates the doc comment to record the upstream deprecation path: when openai/codex#17543 lands, the bridge becomes redundant and the wired MCP server delivers push natively. Verified: TestExternalTemplates_NoMoleculeOrgIDPlaceholder still passes (no MOLECULE_ORG_ID re-introduction); full handlers suite green. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/components/ExternalConnectModal.tsx | 5 ++ .../internal/handlers/external_connection.go | 76 ++++++++++++------- 2 files changed, 55 insertions(+), 26 deletions(-) diff --git a/canvas/src/components/ExternalConnectModal.tsx b/canvas/src/components/ExternalConnectModal.tsx index a9b1f360..58a23f0e 100644 --- a/canvas/src/components/ExternalConnectModal.tsx +++ b/canvas/src/components/ExternalConnectModal.tsx @@ -132,6 +132,11 @@ const TAB_HELP: Record< check: "TOML rejects duplicate `[mcp_servers.molecule]` tables. Open ~/.codex/config.toml and remove the old block before pasting the new one.", }, + { + symptom: "Canvas messages don't wake codex", + check: + "Step 3 (codex-channel-molecule bridge daemon) is required for inbound push. Check `pgrep -f codex-channel-molecule` and `tail ~/.codex-channel-molecule/daemon.log`.", + }, ], }, openclaw: { diff --git a/workspace-server/internal/handlers/external_connection.go b/workspace-server/internal/handlers/external_connection.go index b507e6b2..fd574ee0 100644 --- a/workspace-server/internal/handlers/external_connection.go +++ b/workspace-server/internal/handlers/external_connection.go @@ -289,35 +289,35 @@ hermes gateway --replace // externalCodexTemplate — for operators whose external agent is a // codex CLI (@openai/codex) session. Wires the molecule_runtime A2A // MCP server into codex's config.toml so the agent can call -// list_peers / delegate_task / send_message_to_user / commit_memory. +// list_peers / delegate_task / send_message_to_user / commit_memory, +// AND surfaces the codex-channel-molecule bridge daemon for inbound +// push parity. // -// Push parity caveat: codex's MCP client doesn't forward arbitrary -// notifications/* from configured MCP servers (verified by reading -// codex-rs/codex-mcp/src/connection_manager.rs in openai/codex). So -// this snippet gives outbound tools but NOT mid-turn push from -// inbound A2A. For full push parity on a codex external, the -// equivalent of hermes-channel-molecule would be needed — a bridge -// daemon that long-polls the platform inbox and calls codex's -// turn/steer RPC. Tracked separately; this snippet is the -// outbound-tool-only first cut. -const externalCodexTemplate = `# Codex MCP config — outbound tool path. For operators whose external -# agent is a codex CLI (@openai/codex) session. -# -# This wires the molecule platform's A2A MCP server into codex so -# the agent can call list_peers / delegate_task / send_message_to_user -# / commit_memory. Inbound A2A (canvas messages, peer-initiated tasks) -# does NOT push into the running codex turn yet — codex's MCP runtime -# doesn't route arbitrary notifications/* from configured MCP servers. -# For inbound delivery into a codex session, pair with the Python SDK -# tab for now. +// Push parity: +// - Outbound (codex calls platform tools) — works via the wired +// MCP server (step 2 below). +// - Inbound (canvas messages and peer-initiated tasks wake the +// codex agent) — works via codex-channel-molecule (step 3), +// which long-polls the platform inbox and runs `codex exec +// --resume ` per inbound message. Each turn is a fresh +// subprocess but per-thread session continuity is preserved on +// disk so conversation context survives. +// +// Long-term: when openai/codex#17543 lands (codex MCP runtime routes +// inbound notifications/* into the active session as Op::UserInput), +// the bridge daemon becomes redundant — the wired MCP server in +// step 2 will deliver push natively. Until then, run both. +const externalCodexTemplate = `# Codex external setup — outbound tools (MCP) + inbound push (bridge). +# For operators whose external agent is a codex CLI (@openai/codex) +# session. -# 1. Install codex CLI + the workspace runtime wheel: +# 1. Install codex CLI, the workspace runtime, and the bridge daemon: npm install -g @openai/codex@^0.57 -pip install molecule-ai-workspace-runtime +pip install molecule-ai-workspace-runtime codex-channel-molecule -# 2. Edit ~/.codex/config.toml and add the block below. {{PLATFORM_URL}} -# and {{WORKSPACE_ID}} are stamped server-side; paste your auth -# token for MOLECULE_WORKSPACE_TOKEN before saving. +# 2. Wire the molecule MCP server into codex's config.toml — this is +# the OUTBOUND path (codex calls list_peers / delegate_task / +# send_message_to_user / commit_memory). # # Don't append blindly — TOML rejects duplicate # [mcp_servers.molecule] tables, so re-running on an existing @@ -338,7 +338,31 @@ mkdir -p ~/.codex # PLATFORM_URL = "{{PLATFORM_URL}}" # MOLECULE_WORKSPACE_TOKEN = "" -# 3. Run codex — the molecule tools are now available to the agent: +# 3. Run the bridge daemon as a durable background process — this +# is the INBOUND path. Long-polls the platform inbox and runs +# "codex exec --resume " per inbound canvas/peer message, +# routes the assistant reply back via send_message_to_user / +# delegate_task. Per-thread session continuity persisted to +# ~/.codex-channel-molecule/sessions.json so conversation context +# survives daemon restarts. +# +# Same env-var contract as the MCP server above. +# +# Without this daemon, codex still works for outbound calls but +# canvas messages won't wake an idle session — codex's MCP runtime +# doesn't yet route notifications/* into the chat loop (tracked +# upstream at openai/codex#17543; when that lands, the bridge +# becomes redundant). + +WORKSPACE_ID="{{WORKSPACE_ID}}" \ +PLATFORM_URL="{{PLATFORM_URL}}" \ +MOLECULE_WORKSPACE_TOKEN="" \ +nohup codex-channel-molecule > ~/.codex-channel-molecule/daemon.log 2>&1 & +disown + +# 4. Run codex itself for interactive use — molecule tools are +# available to the agent, and the bridge wakes a non-interactive +# codex turn for any inbound canvas/peer message: codex ` From dfd0bc528cd07879246924d1aa2d2ca755e5c75b Mon Sep 17 00:00:00 2001 From: Hongming Wang Date: Mon, 4 May 2026 18:29:23 -0700 Subject: [PATCH 2/2] fix(external-templates): codex-channel-molecule via git+ URL (not on PyPI yet) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors the pattern hermes-channel-molecule uses (line 256). Drops the broken `pip install codex-channel-molecule` which would 404. PyPI publish workflow is a separate piece of work — until then, git+https install is the path operators get. Co-Authored-By: Claude Opus 4.7 (1M context) --- workspace-server/internal/handlers/external_connection.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workspace-server/internal/handlers/external_connection.go b/workspace-server/internal/handlers/external_connection.go index fd574ee0..249e74a7 100644 --- a/workspace-server/internal/handlers/external_connection.go +++ b/workspace-server/internal/handlers/external_connection.go @@ -313,7 +313,8 @@ const externalCodexTemplate = `# Codex external setup — outbound tools (MCP) + # 1. Install codex CLI, the workspace runtime, and the bridge daemon: npm install -g @openai/codex@^0.57 -pip install molecule-ai-workspace-runtime codex-channel-molecule +pip install molecule-ai-workspace-runtime +pip install 'git+https://github.com/Molecule-AI/codex-channel-molecule.git' # 2. Wire the molecule MCP server into codex's config.toml — this is # the OUTBOUND path (codex calls list_peers / delegate_task /