diff --git a/canvas/src/components/ExternalConnectModal.tsx b/canvas/src/components/ExternalConnectModal.tsx index 58a23f0e..404b33e2 100644 --- a/canvas/src/components/ExternalConnectModal.tsx +++ b/canvas/src/components/ExternalConnectModal.tsx @@ -20,160 +20,6 @@ import * as Dialog from "@radix-ui/react-dialog"; type Tab = "python" | "curl" | "claude" | "mcp" | "hermes" | "codex" | "openclaw" | "fields"; -// Per-tab help metadata: docs link, where-to-install link, common errors. -// All URLs verified against repo content (docs/guides/* file paths map to -// docs.molecule.ai/docs/guides/*; canonical hostname confirmed by existing -// blog post canonical metadata) or against the snippet text the operator -// just copied. Never linking to a URL that wasn't already in product — -// dead links here defeat the purpose of "more comprehensive instructions." -const TAB_HELP: Record< - Tab, - { - docsUrl?: string; - docsLabel?: string; - downloadUrl?: string; - downloadLabel?: string; - commonIssues?: { symptom: string; check: string }[]; - } -> = { - mcp: { - docsUrl: "https://docs.molecule.ai/docs/guides/mcp-server-setup", - docsLabel: "MCP server setup guide", - downloadUrl: "https://pypi.org/project/molecule-ai-workspace-runtime/", - downloadLabel: "molecule-ai-workspace-runtime on PyPI", - commonIssues: [ - { - symptom: "Tools not appearing in your agent", - check: - "Run `claude mcp list` (or your runtime's equivalent) — the molecule entry should be listed. If missing, re-run the `claude mcp add` line.", - }, - { - symptom: "ConnectionRefused / DNS error on first call", - check: - "PLATFORM_URL must include the scheme (https://) and have no trailing slash. Verify with `curl $PLATFORM_URL/healthz`.", - }, - ], - }, - python: { - docsUrl: - "https://docs.molecule.ai/docs/guides/external-agent-registration", - docsLabel: "External agent registration guide", - downloadUrl: "https://pypi.org/project/molecule-ai-workspace-runtime/", - downloadLabel: "molecule-ai-workspace-runtime on PyPI", - commonIssues: [ - { - symptom: "401 from /heartbeat", - check: - "AUTH_TOKEN expired or wrong workspace_id. Tokens are shown only once at create time — re-create the workspace to get a fresh token.", - }, - { - symptom: "AGENT_URL not reachable from platform", - check: - "Public HTTPS URL required for inbound A2A. Use ngrok or Cloudflare Tunnel if your agent is behind NAT.", - }, - ], - }, - claude: { - docsUrl: - "https://docs.molecule.ai/docs/guides/external-agent-registration", - docsLabel: "External agent registration guide", - downloadUrl: "https://claude.com/claude-code", - downloadLabel: "Claude Code (claude.com)", - commonIssues: [ - { - symptom: "plugin not installed", - check: - "Run `/plugin marketplace add Molecule-AI/molecule-mcp-claude-channel` then `/plugin install molecule@molecule-mcp-claude-channel` inside Claude Code, then `/reload-plugins`.", - }, - { - symptom: "not on the approved channels allowlist", - check: - "Custom channels need `--dangerously-load-development-channels` on the launch command. Team/Enterprise orgs need admin to set `channelsEnabled` + `allowedChannelPlugins` in claude.ai admin settings.", - }, - { - symptom: "Inbound messages not arriving", - check: - "Check stderr for `molecule channel: connected — watching N workspace(s)`. Verify ~/.claude/channels/molecule/.env has the right PLATFORM_URL + token.", - }, - ], - }, - hermes: { - docsUrl: - "https://docs.molecule.ai/docs/guides/external-agent-registration", - docsLabel: "External agent registration guide", - downloadUrl: "https://github.com/NousResearch/hermes-agent", - downloadLabel: "hermes-agent (NousResearch)", - commonIssues: [ - { - symptom: "Gateway start failure", - check: - "Tail ~/.hermes/gateway.log. YAML duplicate-key in config.yaml is the most common cause — `gateway:` block must appear exactly once.", - }, - { - symptom: "Plugin not discovered after install", - check: - "Run `pip show hermes-channel-molecule` to confirm install. Some hermes builds need `hermes plugin reload` before the new platform_plugins entry takes effect.", - }, - ], - }, - codex: { - docsUrl: "https://docs.molecule.ai/docs/guides/mcp-server-setup", - docsLabel: "MCP server setup guide", - downloadUrl: "https://github.com/openai/codex", - downloadLabel: "openai/codex", - commonIssues: [ - { - symptom: "[mcp_servers.molecule] not loaded", - check: - "Codex must be ≥ 0.57. Check with `codex --version`; upgrade via `npm install -g @openai/codex@latest`.", - }, - { - symptom: "TOML parse error after re-running setup", - 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: { - docsUrl: "https://docs.molecule.ai/docs/guides/mcp-server-setup", - docsLabel: "MCP server setup guide", - commonIssues: [ - { - symptom: "Gateway not starting", - check: - "Tail ~/.openclaw/gateway.log. The loopback bind requires :18789 to be free — check with `lsof -iTCP:18789`.", - }, - { - symptom: "openclaw mcp set rejected", - check: - "The heredoc generates JSON; verify it parsed by running `jq < ~/.openclaw/mcp/molecule.json`. Re-run `openclaw mcp set` if the file is malformed.", - }, - ], - }, - curl: { - docsUrl: - "https://docs.molecule.ai/docs/guides/external-agent-registration", - docsLabel: "External agent registration guide", - commonIssues: [ - { - symptom: "401 / 403 on register", - check: - "WORKSPACE_AUTH_TOKEN must be the value shown at workspace create. Tokens are shown only once.", - }, - ], - }, - fields: { - docsUrl: - "https://docs.molecule.ai/docs/guides/external-agent-registration", - docsLabel: "External agent registration guide", - }, -}; - export interface ExternalConnectionInfo { workspace_id: string; platform_url: string; @@ -457,7 +303,6 @@ export function ExternalConnectModal({ info, onClose }: Props) { copy(info.heartbeat_endpoint, "hb")} copied={copiedKey === "hb"} /> )} -
@@ -506,70 +351,6 @@ function SnippetBlock({ ); } -// HelpBlock — collapsible "Need help?" section under each tab's snippet. -// Renders only the keys present in the per-tab help metadata (no empty -// sections). Closed by default so the snippet stays the visual focus; -// operators with a working setup never see this. Uses native
-// for keyboard accessibility (Tab + Enter) without extra ARIA wiring. -function HelpBlock({ - help, -}: { - help: (typeof TAB_HELP)[Tab] | undefined; -}) { - if (!help) return null; - const { docsUrl, docsLabel, downloadUrl, downloadLabel, commonIssues } = help; - if (!docsUrl && !downloadUrl && !commonIssues?.length) return null; - - return ( -
- - Need help? — install link, docs, common errors - -
- {downloadUrl && ( -
- Where to install: - - {downloadLabel || downloadUrl} - -
- )} - {docsUrl && ( -
- Documentation: - - {docsLabel || docsUrl} - -
- )} - {commonIssues && commonIssues.length > 0 && ( -
-
Common errors:
-
    - {commonIssues.map((issue, i) => ( -
  • - {issue.symptom} - — {issue.check} -
  • - ))} -
-
- )} -
-
- ); -} - function Field({ label, value, diff --git a/workspace-server/internal/handlers/external_connection.go b/workspace-server/internal/handlers/external_connection.go index c10bf059..4730d36b 100644 --- a/workspace-server/internal/handlers/external_connection.go +++ b/workspace-server/internal/handlers/external_connection.go @@ -109,6 +109,12 @@ curl -fsS -X POST "{{PLATFORM_URL}}/registry/register" \ "version": "0.1.0" } }' + +# Need help? +# Documentation: https://doc.moleculesai.app/docs/guides/external-agent-registration +# Common errors: +# • 401 / 403 on register — WORKSPACE_AUTH_TOKEN must be the value +# shown at workspace create. Tokens are shown only once. ` // externalChannelTemplate — Claude Code channel plugin install + .env. For @@ -172,6 +178,18 @@ claude --dangerously-load-development-channels \ # 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. + +# Need help? +# Documentation: https://doc.moleculesai.app/docs/guides/claude-code-channel-plugin +# Common errors: +# • "plugin not installed" — run /plugin marketplace add then +# /plugin install lines above; /reload-plugins or restart. +# • "not on the approved channels allowlist" — custom channels need +# --dangerously-load-development-channels; team/enterprise orgs +# need admin to set channelsEnabled + allowedChannelPlugins. +# • "Inbound messages not arriving" — stderr should show +# "molecule channel: connected — watching N workspace(s)"; +# verify ~/.claude/channels/molecule/.env has PLATFORM_URL + token. ` // externalUniversalMcpTemplate — runtime-agnostic standalone path. @@ -224,6 +242,17 @@ claude mcp add molecule -s user -- env \ # # Origin/WAF handling is built into the wheel — no manual headers # needed when calling tools through the MCP server. + +# Need help? +# Where to install: https://pypi.org/project/molecule-ai-workspace-runtime/ +# Documentation: https://doc.moleculesai.app/docs/guides/mcp-server-setup +# Common errors: +# • "Tools not appearing in your agent" — run ` + "`claude mcp list`" + ` (or +# your runtime's equivalent) and confirm the molecule entry. If +# missing, re-run the ` + "`claude mcp add`" + ` line above. +# • "ConnectionRefused / DNS error on first call" — PLATFORM_URL must +# include the scheme (https://) and have NO trailing slash. Verify +# with: curl ${PLATFORM_URL}/healthz ` // externalPythonTemplate uses molecule-sdk-python's RemoteAgentClient + @@ -262,6 +291,15 @@ async def main(): if __name__ == "__main__": asyncio.run(main()) + +# Need help? +# Where to install: https://pypi.org/project/molecule-ai-workspace-runtime/ +# Documentation: https://doc.moleculesai.app/docs/guides/external-agent-registration +# Common errors: +# • 401 from /heartbeat — AUTH_TOKEN expired or wrong workspace_id. +# Tokens shown only once at create time; re-create to get a fresh one. +# • AGENT_URL not reachable from platform — public HTTPS URL required +# for inbound A2A. Use ngrok or Cloudflare Tunnel if behind NAT. ` // externalHermesChannelTemplate — install snippet for operators whose @@ -329,6 +367,16 @@ hermes gateway --replace # # Source + issue tracker: # https://github.com/Molecule-AI/hermes-channel-molecule + +# Need help? +# Documentation: https://doc.moleculesai.app/docs/guides/external-agent-registration +# Common errors: +# • Gateway start failure — tail ~/.hermes/gateway.log. YAML +# duplicate-key in config.yaml is the most common cause; the +# gateway: block must appear exactly once. +# • Plugin not discovered after install — pip show hermes-channel-molecule +# to confirm install. Some hermes builds need ` + "`hermes plugin reload`" + ` +# before the new platform_plugins entry takes effect. ` // externalCodexTemplate — for operators whose external agent is a @@ -410,6 +458,18 @@ disown # available to the agent, and the bridge wakes a non-interactive # codex turn for any inbound canvas/peer message: codex + +# Need help? +# Documentation: https://doc.moleculesai.app/docs/guides/mcp-server-setup +# Common errors: +# • [mcp_servers.molecule] not loaded — codex must be ≥ 0.57. +# Check with ` + "`codex --version`" + `; upgrade via npm install -g @openai/codex@latest. +# • TOML parse error after re-running setup — TOML rejects duplicate +# [mcp_servers.molecule] tables. Open ~/.codex/config.toml and +# remove the old block before pasting the new one. +# • Canvas messages don't wake codex — 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. ` // externalOpenClawTemplate — for operators whose external agent is an @@ -471,4 +531,13 @@ disown # 5. Run an agent turn — molecule tools are now available: openclaw agent --message "list my peers" + +# Need help? +# Documentation: https://doc.moleculesai.app/docs/guides/mcp-server-setup +# Common errors: +# • Gateway not starting — tail ~/.openclaw/gateway.log. The loopback +# bind requires :18789 to be free; check with ` + "`lsof -iTCP:18789`" + `. +# • ` + "`openclaw mcp set`" + ` rejected — the heredoc generates JSON; +# verify with ` + "`jq < ~/.openclaw/mcp/molecule.json`" + ` and re-run +# ` + "`openclaw mcp set`" + ` if the file is malformed. `