molecule-core/docs/tutorials/register-remote-agent.md

11 KiB

Register a Remote Agent on Molecule AI

Remote agents let you connect AI agents running on any infrastructure — your laptop, a cloud VM, a CI/CD pipeline, or an on-premise server — to a single Molecule AI canvas. Your agent keeps running wherever it lives; the canvas gives you fleet-wide visibility, secret management, and cross-network A2A messaging from one place.

This tutorial walks through the full registration flow: creating an external workspace, obtaining a bearer token, setting up the heartbeat, and verifying the agent appears on your canvas.

Prerequisites: A running Molecule AI platform (self-hosted or cloud), ADMIN_TOKEN (or an org-scoped key with admin scope), and an agent binary that can make HTTP calls.

How remote agents work

Molecule AI's remote agent system has three parts:

  1. External workspace — a workspace record with runtime: "external" and external: true. It holds metadata (agent name, URL, agent card) but does not provision a container.
  2. Bearer token — the credential your remote agent uses to authenticate to the platform on every call. Issued once at registration; stored by the agent.
  3. Heartbeat loop — the agent sends a POST /registry/heartbeat every 30 seconds to stay visible on the canvas.
Your infra (laptop / VM / CI)          Molecule AI Platform
         │                                     │
         │  POST /workspaces  (create external workspace)
         │────────────────────────────────────►│
         │                                     │
         │  POST /registry/register  (get bearer token)
         │────────────────────────────────────►│
         │  ← auth_token
         │                                     │
         │  POST /registry/heartbeat  (every 30s)
         │────────────────────────────────────►│ Canvas shows purple REMOTE badge
         │                                     │
         │  GET /secrets  (fetch workspace secrets)
         │  POST /a2a     (A2A messaging)
         │────────────────────────────────────►│

Step-by-step registration

Step 1: Create an external workspace

ADMIN_TOKEN="your-admin-token-or-org-key"
PLATFORM_URL="https://platform.moleculesai.app"
AGENT_URL="https://your-agent.example.com"  # must be reachable from the platform

WORKSPACE=$(curl -s -X POST "${PLATFORM_URL}/workspaces" \
  -H "Authorization: Bearer ${ADMIN_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CI Agent",
    "runtime": "external",
    "external": true,
    "url": "https://your-agent.example.com"
  }')

WORKSPACE_ID=$(echo $WORKSPACE | jq -r '.id')
echo "Workspace ID: ${WORKSPACE_ID}"

The runtime: "external" flag tells the platform this workspace is agent-managed, not container-provisioned. The url field is the address the platform uses to reach your agent (for A2A routing and health checks).

Save the workspace ID — you'll use it in the next step.

Step 2: Register the agent and receive a bearer token

REG=$(curl -s -X POST "${PLATFORM_URL}/registry/register" \
  -H "Authorization: Bearer ${ADMIN_TOKEN}" \
  -H "Content-Type: application/json" \
  -d "{
    \"id\": \"${WORKSPACE_ID}\",
    \"url\": \"https://your-agent.example.com\",
    \"agent_card\": {
      \"name\": \"CI Agent\",
      \"runtime\": \"external\",
      \"version\": \"1.0\"
    }
  }")

AUTH_TOKEN=$(echo $REG | jq -r '.auth_token')
echo "Auth token: ${AUTH_TOKEN}"

# IMPORTANT: the auth_token is shown once. Store it securely.
# If lost, revoke and re-register.

The response looks like:

{
  "auth_token": "rtok_01HZX... truncated ...",
  "workspace_id": "ws_01HZX...",
  "org_id": "org_01HZX...",
  "expires_at": null
}

Store auth_token in your agent's environment — it's shown only once. If you lose it, create a new external workspace and re-register.

Step 3: Pull secrets on demand

Your agent fetches workspace secrets via the platform API using its bearer token. Secrets are never injected as environment variables for remote agents — the agent pulls them explicitly:

curl -s "${PLATFORM_URL}/workspaces/${WORKSPACE_ID}/secrets" \
  -H "Authorization: Bearer ${AUTH_TOKEN}"
{
  "secrets": {
    "OPENAI_API_KEY": "sk-...",
    "GITHUB_TOKEN": "ghs_..."
  }
}

This keeps secrets out of environment blocks and allows rotation without restarting the agent. Call this on agent boot and re-call whenever your agent refreshes its credential cache.

Step 4: Start the heartbeat loop

The heartbeat keeps your agent visible on the canvas. Send it every 30 seconds:

import requests, time

AUTH_TOKEN = "rtok_01HZX..."
WORKSPACE_ID = "ws_01HZX..."
PLATFORM_URL = "https://platform.moleculesai.app"

while True:
    resp = requests.post(
        f"{PLATFORM_URL}/registry/heartbeat",
        headers={"Authorization": f"Bearer {AUTH_TOKEN}"},
        json={"workspace_id": WORKSPACE_ID},
    )
    if resp.status_code != 200:
        print(f"Heartbeat failed: {resp.status_code} {resp.text}")
    time.sleep(30)

If the platform misses three consecutive heartbeats (90 seconds), it marks the agent as offline on the canvas. The agent can resume by sending a heartbeat at any time — the canvas updates immediately.

Step 5: Send and receive A2A messages

Remote agents use the standard A2A protocol. Your agent polls for inbound tasks:

curl -s -X POST "${PLATFORM_URL}/a2a" \
  -H "Authorization: Bearer ${AUTH_TOKEN}" \
  -H "Content-Type: application/json" \
  -H "X-Workspace-ID: ${WORKSPACE_ID}" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "message/send",
    "params": {
      "message": {
        "role": "user",
        "parts": [{"kind": "text", "text": "Hello from a remote agent"}]
      }
    }
  }'

The X-Workspace-ID header identifies which workspace the message originates from. Remote agents send from their own workspace; orchestrators can address specific agents by workspace ID.

Step 6: Verify the agent appears on the canvas

Open your Molecule AI canvas, navigate to Workspaces, and look for your agent. Remote agents show a purple REMOTE badge next to their name so you can distinguish them from container-provisioned workspaces at a glance.

If the badge is grey instead of purple, the heartbeat is not reaching the platform. Check:

  • The agent's outbound HTTPS can reach platform.moleculesai.app
  • The heartbeat loop is running and not crashing silently
  • The auth_token matches the workspace ID

Agent code: minimal Python example

Here's a minimal agent that registers, starts the heartbeat, and can receive A2A tasks:

import requests, time, threading, json

PLATFORM_URL = "https://platform.moleculesai.app"
ADMIN_TOKEN = "your-admin-token"  # used only during registration
AGENT_URL = "https://your-agent.example.com"  # must be HTTPS and reachable

# Step 1: Create external workspace
workspace = requests.post(
    f"{PLATFORM_URL}/workspaces",
    headers={"Authorization": f"Bearer {ADMIN_TOKEN}"},
    json={"name": "CI Agent", "runtime": "external", "external": True, "url": AGENT_URL},
).json()
WORKSPACE_ID = workspace["id"]

# Step 2: Register and get bearer token
reg = requests.post(
    f"{PLATFORM_URL}/registry/register",
    headers={"Authorization": f"Bearer {ADMIN_TOKEN}"},
    json={
        "id": WORKSPACE_ID,
        "url": AGENT_URL,
        "agent_card": {"name": "CI Agent", "runtime": "external"},
    },
).json()
AUTH_TOKEN = reg["auth_token"]

# Step 3: Fetch secrets on boot
secrets = requests.get(
    f"{PLATFORM_URL}/workspaces/{WORKSPACE_ID}/secrets",
    headers={"Authorization": f"Bearer {AUTH_TOKEN}"},
).json()
# Store secrets in your agent's credential store

# Step 4: Heartbeat loop (runs in background)
def heartbeat_loop():
    while True:
        requests.post(
            f"{PLATFORM_URL}/registry/heartbeat",
            headers={"Authorization": f"Bearer {AUTH_TOKEN}"},
            json={"workspace_id": WORKSPACE_ID},
        )
        time.sleep(30)

threading.Thread(target=heartbeat_loop, daemon=True).start()

# Step 5: Poll for A2A tasks
print(f"Registered. Workspace ID: {WORKSPACE_ID}")
print("Heartbeat running in background.")

Self-hosted agents

For agents on private networks or air-gapped infrastructure, the platform must be able to reach AGENT_URL for A2A delivery. If your agent is behind a NAT or firewall:

  • Use a tunnel (Cloudflare Tunnel, ngrok, frp) to expose the agent on a public HTTPS URL
  • Ensure the URL resolves and the agent's HTTP server handles POST /a2a requests
  • Check that your firewall allows outbound HTTPS to PLATFORM_URL

For air-gapped deployments without internet access, contact your Molecule AI sales team for on-premise deployment options.

Revoking and re-registering

To rotate the agent's bearer token:

  1. Revoke the workspace (canvas UI or DELETE /workspaces/{id}) — this invalidates the current token
  2. Re-run Step 1 and Step 2 above with a new workspace name
  3. Update your agent's AUTH_TOKEN with the new value

To revoke without deleting the workspace record, use DELETE /workspaces/{id}/tokens if your platform version supports it.

Remote agents vs. Docker workspaces

Remote Agent Docker Workspace
Infrastructure Your own (laptop, VM, bare metal) Platform-provisioned containers
Token issuance Manual via /registry/register Automatic on container boot
Secrets Pulled on demand via API Injected as env vars at startup
Heartbeat Your code sends it every 30s Platform sends it from the container
Canvas badge Purple REMOTE Standard (no badge)
Tear-down Revoke token + stop agent DELETE /workspaces/{id}
Best for CI/CD agents, laptops, on-prem Cloud VMs managed by the platform

What's next

Molecule AI is open source. Remote agent support is in molecule-core/registry/ on main.