diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a7474110..601533f4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -175,6 +175,17 @@ and run CI manually. - Type hints on public functions - pytest for all tests +## External integrations + +Code in this repo lands in molecule-core. Some related runtime artifacts +live in their own repos: + +- [`Molecule-AI/molecule-ai-workspace-runtime`](https://github.com/Molecule-AI/molecule-ai-workspace-runtime) — Python adapter SDK (`molecule_runtime`) that runs inside containerized Molecule workspaces. Bridges Claude Code SDK / hermes / langgraph / etc. → A2A queue. +- [`Molecule-AI/molecule-sdk-python`](https://github.com/Molecule-AI/molecule-sdk-python) — `A2AServer` + `RemoteAgentClient` for external agents that register over the public `/registry/register` flow. +- [`Molecule-AI/molecule-mcp-claude-channel`](https://github.com/Molecule-AI/molecule-mcp-claude-channel) — Claude Code channel plugin. Bridges A2A traffic into a running Claude Code session via MCP `notifications/claude/channel`. Polling-based (no tunnel required); install with `claude --channels plugin:molecule@Molecule-AI/molecule-mcp-claude-channel`. + +When extending the **A2A surface** in molecule-core (`workspace-server/internal/handlers/a2a_proxy.go` etc.), consider whether the change has a downstream impact on the runtime SDK or the channel plugin — they're versioned independently but share the wire shape. + ## Architecture Overview See `CLAUDE.md` for detailed architecture documentation, including: diff --git a/workspace-server/internal/handlers/external_connection.go b/workspace-server/internal/handlers/external_connection.go index 7a73a37b..12a3abfb 100644 --- a/workspace-server/internal/handlers/external_connection.go +++ b/workspace-server/internal/handlers/external_connection.go @@ -67,6 +67,37 @@ curl -fsS -X POST "{{PLATFORM_URL}}/registry/register" \ }' ` +// externalChannelTemplate — Claude Code channel plugin install + .env. For +// operators whose external agent IS a Claude Code session (laptop or +// remote dev VM); routes the workspace's A2A traffic into the running +// Claude Code session as conversation turns via MCP. The plugin source +// lives at github.com/Molecule-AI/molecule-mcp-claude-channel — polling +// based, no tunnel required (uses /workspaces/:id/activity?since_secs=, +// platform-side support shipped in #2300). +const externalChannelTemplate = `# Claude Code channel — bridges this workspace's A2A traffic into your +# Claude Code session. No tunnel/public URL needed (polling-based). +# +# 1. Save this token + workspace_id, then create ~/.claude/channels/molecule/.env: +mkdir -p ~/.claude/channels/molecule +cat > ~/.claude/channels/molecule/.env <<'EOF' +MOLECULE_PLATFORM_URL={{PLATFORM_URL}} +MOLECULE_WORKSPACE_IDS={{WORKSPACE_ID}} +MOLECULE_WORKSPACE_TOKENS= +EOF +chmod 600 ~/.claude/channels/molecule/.env + +# 2. Launch Claude Code with the channel enabled: +claude --channels plugin:molecule@Molecule-AI/molecule-mcp-claude-channel + +# Inbound A2A messages now surface as conversation turns. Claude's +# replies route back via the reply_to_workspace MCP tool — no extra +# wiring on your side. +# +# Multi-workspace: comma-separate IDs and tokens (same order). See +# https://github.com/Molecule-AI/molecule-mcp-claude-channel for +# pairing flow, push-mode upgrade, and v0.2 roadmap. +` + // externalPythonTemplate uses molecule-sdk-python's RemoteAgentClient + // A2AServer (PR #13 in that repo). Until the SDK cuts a v0.y release // to PyPI the snippet pins git+main. diff --git a/workspace-server/internal/handlers/workspace.go b/workspace-server/internal/handlers/workspace.go index 723b85b6..00d86b7e 100644 --- a/workspace-server/internal/handlers/workspace.go +++ b/workspace-server/internal/handlers/workspace.go @@ -370,6 +370,17 @@ func (h *WorkspaceHandler) Create(c *gin.Context) { "{{PLATFORM_URL}}", platformURL), "{{WORKSPACE_ID}}", id, ), + // Claude Code channel plugin snippet. For operators + // whose external agent IS a Claude Code session — + // the snippet sets up ~/.claude/channels/molecule/.env + // and points at the canonical first-party plugin at + // github.com/Molecule-AI/molecule-mcp-claude-channel. + // Polling-based; no tunnel needed. + "claude_code_channel_snippet": strings.ReplaceAll( + strings.ReplaceAll(externalChannelTemplate, + "{{PLATFORM_URL}}", platformURL), + "{{WORKSPACE_ID}}", id, + ), } } c.JSON(http.StatusCreated, resp)