diff --git a/content/docs/external-agents.mdx b/content/docs/external-agents.mdx index 85e7b99..b43b948 100644 --- a/content/docs/external-agents.mdx +++ b/content/docs/external-agents.mdx @@ -21,6 +21,17 @@ register and heartbeat by hand. Use it when your agent can't run an MCP stdio server. +## Pick the right path + +| Your agent runs as | Best path | Why | +|---|---|---| +| **An MCP-aware runtime** (Claude Code, Hermes, OpenCode, Cursor, Cline) | [Bring Your Own Runtime (MCP)](/docs/runtime-mcp) | Universal `molecule-mcp` wheel — no HTTP server, no tunnel. | +| **A Claude Code session on your laptop** | [Claude Code Channel Plugin](/docs/guides/claude-code-channel-plugin) | Polling-based; no tunnel/public URL needed. Set up in <1 min. | +| Any HTTP server with a public URL | The flow on this page (or the [Python SDK guide](/docs/guides/external-agent-registration)) | Push-based; lower latency; works for any A2A-compatible HTTP endpoint. | +| A custom A2A server you wrote yourself | The flow on this page | Direct register + heartbeat + handler. | + +The rest of this doc covers the third + fourth rows. For Claude Code or other MCP runtimes, follow the linked guides. + ## Prerequisites - A running Molecule AI platform (default `http://localhost:8080`) diff --git a/content/docs/guides/claude-code-channel-plugin.md b/content/docs/guides/claude-code-channel-plugin.md new file mode 100644 index 0000000..1ea4df4 --- /dev/null +++ b/content/docs/guides/claude-code-channel-plugin.md @@ -0,0 +1,224 @@ +--- +title: "Claude Code Channel Plugin — Connect a Claude Code Session as an External Workspace" +description: "Bridge Molecule A2A traffic into a running Claude Code session via MCP. Polling-based, no tunnel required. The fastest path for laptop-launched Claude Code sessions to participate in your Molecule canvas." +--- + +# Claude Code Channel Plugin + +Run [Claude Code](https://claude.com/claude-code) on your laptop and have it appear on the Molecule AI canvas as a first-class external workspace. Inbound A2A messages from peer workspaces surface as conversation turns; replies route back through Molecule's A2A endpoints. + +> **What this is:** [`Molecule-AI/molecule-mcp-claude-channel`](https://github.com/Molecule-AI/molecule-mcp-claude-channel) — an MCP-based "channel plugin" that turns a Claude Code session into a Molecule workspace. + +> **What this is NOT:** the [Python SDK / curl register flow](/docs/guides/external-agent-registration) for arbitrary HTTP-speaking agents. That flow needs a public URL the platform can POST to. This one polls — runs on any laptop behind any NAT. + +--- + +## What you get + +``` +Molecule peer ──A2A──▶ [your workspace] ──poll──▶ [plugin] ──MCP notification──▶ Claude Code + ▲ │ + └────── POST /workspaces/:id/a2a ◄── reply_to_workspace ──┘ +``` + +| Property | Value | +|---|---| +| **Inbound latency** | up to `MOLECULE_POLL_INTERVAL_MS` (default 5s) | +| **Outbound latency** | direct POST — sub-second | +| **Tunnel / public URL** | not required | +| **Auth model** | per-workspace bearer token (same as Python SDK) | +| **Multi-workspace** | yes, comma-separated list | + +--- + +## Prerequisites + +| You need | Notes | +|---|---| +| A Molecule AI tenant | Self-hosted localhost or your `*.staging.moleculesai.app` SaaS tenant | +| One or more workspace IDs | Created via canvas or `POST /workspaces` (see [External Agent Registration](/docs/guides/external-agent-registration)) | +| The workspace bearer token | Shown once when the workspace is created — save it from the canvas modal | +| Claude Code | `claude` CLI ≥ the version that supports `--channels` | +| `bun` | The plugin runs under bun for fast startup; `bun install` is invoked automatically by `start` | + + +The platform must be running molecule-core ≥ PR #2300, which shipped the `?since_secs=` query parameter on `GET /workspaces/:id/activity`. Available on all staging-onward and self-hosted main builds after 2026-04-29. + + +--- + +## Step 1 — Create the workspace + +In your Molecule canvas: + +1. Click **+ New workspace** +2. Choose **External** runtime +3. Set tier as needed; click **Create** +4. The "Connect your external agent" modal opens — switch to the **Claude Code** tab +5. Copy the entire snippet (everything from the `mkdir -p` line through `claude --channels ...`) + +Or via API: + +```bash +curl -X POST "$MOLECULE_PLATFORM_URL/workspaces" \ + -H "Content-Type: application/json" \ + -d '{"name": "My Claude Code", "external": true, "tier": 2}' +``` + +The response includes `claude_code_channel_snippet` — same content as the canvas tab, ready to paste. + +## Step 2 — Set up the channel config + +Run the snippet from Step 1. It does two things: + +```bash +mkdir -p ~/.claude/channels/molecule +cat > ~/.claude/channels/molecule/.env <<'EOF' +MOLECULE_PLATFORM_URL=https://your-tenant.staging.moleculesai.app +MOLECULE_WORKSPACE_IDS=ws-uuid-1 +MOLECULE_WORKSPACE_TOKENS= +EOF +chmod 600 ~/.claude/channels/molecule/.env +``` + +Replace the token placeholder with the workspace bearer from Step 1. + +## Step 3 — Launch Claude Code + +```bash +claude --channels plugin:molecule@Molecule-AI/molecule-mcp-claude-channel +``` + +You should see on stderr (use `--debug` to surface): + +``` +molecule channel: connected — watching 1 workspace(s) at https://your-tenant.staging.moleculesai.app + workspaces: ws-uuid-1 + poll: every 5000ms with 30s window +``` + +That's it — the workspace is live on the canvas with a purple **REMOTE** badge, and any A2A traffic the workspace receives surfaces as conversation turns in your Claude Code session. + +--- + +## How replies work + +When a peer's message lands in your session, you'll see a turn with structured metadata: + +```json +{ + "method": "notifications/claude/channel", + "params": { + "content": "Hey, can you take a look at this? ", + "meta": { + "source": "molecule", + "workspace_id": "ws-uuid-1", + "peer_id": "ws-uuid-pm-coordinator", + "method": "user_message", + "activity_id": "act-...", + "ts": "2026-04-29T..." + } + } +} +``` + +Reply normally — Claude calls the `reply_to_workspace` MCP tool with `peer_id` from the meta block, and the response flows back through `POST /workspaces/:peer_id/a2a` so peers see it just like any other A2A message. + +--- + +## Multi-workspace setup + +Watch multiple workspaces from a single Claude Code session by comma-separating the lists. Both must have the same length and order: + +```bash +MOLECULE_WORKSPACE_IDS=ws-pm,ws-researcher,ws-engineer +MOLECULE_WORKSPACE_TOKENS=tok-pm,tok-researcher,tok-engineer +``` + +When Claude replies, the `reply_to_workspace` tool requires `workspace_id` (which of the watched workspaces to reply AS) explicitly. With a single workspace it's implicit. + +--- + +## Configuration reference + +| Variable | Default | Purpose | +|---|---|---| +| `MOLECULE_PLATFORM_URL` | (required) | Tenant base URL (no trailing slash) | +| `MOLECULE_WORKSPACE_IDS` | (required) | Comma-separated workspace UUIDs to watch | +| `MOLECULE_WORKSPACE_TOKENS` | (required) | Comma-separated bearer tokens, **same order as IDs** | +| `MOLECULE_POLL_INTERVAL_MS` | `5000` | How often each workspace is polled (ms) | +| `MOLECULE_POLL_WINDOW_SECS` | `30` | `since_secs` window per poll. Wider than interval to recover from missed ticks | +| `MOLECULE_STATE_DIR` | `~/.claude/channels/molecule` | Override state directory (testing) | + +--- + +## Architecture notes + +### Why polling instead of push? + +The [Python SDK external-agent flow](/docs/guides/external-agent-registration) uses **push**: register an inbound URL, platform POSTs A2A to that URL. Lower latency but requires a tunnel (ngrok / Cloudflare) or static IP — non-trivial for laptop sessions. + +This plugin uses **polling** as the default because it works through every NAT/firewall with zero infra. Cost: up to `MOLECULE_POLL_INTERVAL_MS` of inbound latency. For production setups where lower latency matters, push mode is on the v0.2 roadmap. + +### Why the 30s window over a 5s interval? + +A single missed tick (transient network blip, GC pause, laptop sleep) shouldn't lose messages. The plugin re-fetches the last 30 seconds on every poll and dedups by `activity_id`, so 25 seconds of overlap is the recovery margin. Increase `MOLECULE_POLL_WINDOW_SECS` for noisier networks. + +### Singleton lock + +Only one channel server runs per host — multiple instances would race the dedup state and double-deliver. The plugin maintains a PID file at `~/.claude/channels/molecule/bot.pid` and on startup kills any stale predecessor. This mirrors the [`@claude-plugins-official/telegram`](https://github.com/anthropics/claude-plugins-official/tree/main/plugins/telegram) pattern. + +--- + +## Troubleshooting + +### "molecule channel: required config missing" + +The plugin started before you filled in `.env`. Re-run the snippet from Step 2, then re-launch Claude Code. + +### "molecule channel: poll returned 401" + +Bearer token mismatch. Two common causes: + +- The token in `MOLECULE_WORKSPACE_TOKENS` doesn't match the workspace whose ID is in the corresponding position of `MOLECULE_WORKSPACE_IDS`. Verify same-order pairing. +- The workspace was rotated and the token was revoked. Generate a new token from the canvas Settings tab (or `POST /admin/workspaces/:id/tokens`). + +### "molecule channel: poll returned 404" + +Either the workspace doesn't exist or the `MOLECULE_PLATFORM_URL` is wrong. Confirm: + +```bash +curl -fsS "$MOLECULE_PLATFORM_URL/workspaces/$WS_ID" \ + -H "Authorization: Bearer $WS_TOKEN" | jq '.workspace.id' +``` + +### A2A messages aren't surfacing + +Check that the watched workspace is actually receiving them — the plugin only pulls `activity_logs` rows whose `activity_type = a2a_receive`. If peers aren't sending to this workspace, there's nothing to surface. Verify with: + +```bash +curl -fsS "$MOLECULE_PLATFORM_URL/workspaces/$WS_ID/activity?type=a2a_receive&limit=10" \ + -H "Authorization: Bearer $WS_TOKEN" | jq +``` + +If that returns events but Claude doesn't see them, file an issue at [`Molecule-AI/molecule-mcp-claude-channel`](https://github.com/Molecule-AI/molecule-mcp-claude-channel/issues) with the workspace_id + sample event. + +--- + +## Limitations (v0.1) + +- **Polling-only inbound.** No push mode yet; latency floor is `MOLECULE_POLL_INTERVAL_MS`. +- **No pairing flow.** Tokens are configured manually via `.env`; no canvas-side approval handshake. +- **No file-attachment download.** URLs surface in the meta block; the host fetches on-demand. +- **No outbound channel-init.** The plugin only sends replies (in response to inbound A2A); starting a fresh A2A conversation initiated FROM the Claude Code side requires a future `start_workspace_chat` tool. + +Track the v0.2 roadmap on the [plugin repo's README](https://github.com/Molecule-AI/molecule-mcp-claude-channel#limitations-v01). + +--- + +## See also + +- [External Agent Registration](/docs/guides/external-agent-registration) — full A2A wire-shape reference + Python SDK + curl flow +- [External Workspace Quickstart](/docs/guides/external-workspace-quickstart) — 5-min guide for any HTTP-speaking agent +- [Remote Workspaces FAQ](/docs/guides/remote-workspaces-faq) — production hardening notes +- [`Molecule-AI/molecule-mcp-claude-channel`](https://github.com/Molecule-AI/molecule-mcp-claude-channel) — plugin source code, issues, v0.2 roadmap diff --git a/content/docs/guides/external-workspace-quickstart.md b/content/docs/guides/external-workspace-quickstart.md index e3c500d..29f42e4 100644 --- a/content/docs/guides/external-workspace-quickstart.md +++ b/content/docs/guides/external-workspace-quickstart.md @@ -9,6 +9,8 @@ Run an agent on your laptop, a home server, a cloud VM, or any machine with inte > **Looking for the operator-focused reference?** See [External Agent Registration](/docs/guides/external-agent-registration) for full capability + auth details, or [Remote Workspaces FAQ](/docs/guides/remote-workspaces-faq) for hardening + production notes. This doc is the fast path. +> **Running Claude Code on your laptop?** Skip this guide — use the [Claude Code Channel Plugin](/docs/guides/claude-code-channel-plugin) instead. It's polling-based and needs no tunnel, so your laptop session shows up on the canvas in under a minute. + --- ## What is an "external workspace"?