@@ -426,6 +426,134 @@ curl https://agent.yourdomain.com/.well-known/agent.json
426426
427427---
428428
429+ ## Managed Agent Deployment (deploy.xpragents.com)
430+
431+ The deploy service provides 1-click agent provisioning via a web wizard at [ deploy.xpragents.com] ( https://deploy.xpragents.com ) . It creates an XPR account, registers the agent on-chain, and deploys a Cloudflare Worker running OpenClaw with all XPR agent skills.
432+
433+ ### Two Deployment Modes
434+
435+ | Mode | How It Works | Deploy Time | When Used |
436+ | ------| -------------| -------------| -----------|
437+ | ** Single-tenant** | One CF Worker per agent (` xpr-{owner}-{agent}.workers.dev ` ) | ~ 5 min | Default when KV not configured |
438+ | ** Multi-tenant** | Shared CF Worker + per-agent KV config | ~ 2 sec | When ` CF_KV_NAMESPACE_ID ` + ` CF_GATEWAY_WORKER_NAME ` env vars set |
439+
440+ ### Multi-Tenant Architecture
441+
442+ In multi-tenant mode, all agents share a single Cloudflare Worker deployment (the "gateway"). Each agent gets its own:
443+ - ** KV config entry** with API keys, XPR account, tokens
444+ - ** Sandbox container** (Cloudflare Durable Object + container instance)
445+ - ** R2 storage prefix** for persistent data
446+
447+ ```
448+ Request: https://alice.xpragents.com/chat
449+ |
450+ v
451+ Gateway Worker: extract subdomain "alice"
452+ |
453+ v
454+ KV lookup: AGENT_KV.get("agent:alice") -> {xprAccount, anthropicApiKey, ...}
455+ |
456+ v
457+ Sandbox: getSandbox(env.Sandbox, "alice") -> separate container per agent
458+ |
459+ v
460+ Merge env: global Worker secrets + tenant KV config -> container env vars
461+ |
462+ v
463+ Proxy: HTTP/WebSocket to OpenClaw gateway on port 18789
464+ ```
465+
466+ ### Key Components
467+
468+ | Component | Location | Description |
469+ | -----------| ----------| -------------|
470+ | Deploy Frontend | ` deploy/frontend/ ` (Vercel) | React wizard for agent provisioning |
471+ | Deploy Backend | ` xpr-deploy-service ` (Railway) | Express API for account creation + CF deployment |
472+ | Gateway Worker | ` moltworker-xpr ` (CF Workers) | Shared Cloudflare Worker running OpenClaw containers |
473+ | Agent Registry | ` agentcore ` (on-chain) | Smart contract storing agent metadata + endpoints |
474+
475+ ### Gateway Startup Flow
476+
477+ When a request hits a multi-tenant agent:
478+
479+ 1 . ** Tenant resolution** — Extract subdomain from hostname, look up KV config
480+ 2 . ** Env merge** — Overlay tenant-specific config onto global Worker env
481+ 3 . ** Gateway prewarm** — ` waitUntil(ensureMoltbotGateway()) ` starts the container BEFORE auth (critical — otherwise auth middleware blocks container startup)
482+ 4 . ** Wallet auth** — User signs with XPR wallet, JWT cookie issued
483+ 5 . ** Proxy** — HTTP/WebSocket proxied to OpenClaw gateway inside container
484+
485+ ### Required Environment Variables
486+
487+ #### Deploy Service (Railway)
488+
489+ ``` bash
490+ # Core
491+ XPR_RPC_ENDPOINT=https://rpc.api.mainnet.metalx.com
492+ XPR_NETWORK=mainnet
493+ API_SECRET=< openssl rand -hex 32>
494+ WEBHOOK_SECRET=< openssl rand -hex 32>
495+ KEY_ENCRYPTION_SECRET=< openssl rand -hex 32> # AES-256, exactly 64 hex chars
496+ DEPLOY_ACCOUNT=agentcreate
497+ DEPLOY_PRIVATE_KEY=PVT_K1_...
498+ CF_ACCOUNT_ID=< cloudflare-account-id>
499+ CF_API_TOKEN=< cloudflare-api-token>
500+ JWT_SECRET=< openssl rand -hex 32>
501+
502+ # Multi-tenant mode (enables shared gateway)
503+ CF_KV_NAMESPACE_ID=900a672e08c1402ebb1b2e8e7889dbef
504+ CF_GATEWAY_WORKER_NAME=xpr-agent-sandbox
505+ ```
506+
507+ #### Gateway Worker (CF Secrets)
508+
509+ ``` bash
510+ # Always required
511+ ANTHROPIC_API_KEY=< key>
512+ MOLTBOT_GATEWAY_TOKEN=< openssl rand -hex 32>
513+
514+ # Single-tenant (set per worker)
515+ XPR_ACCOUNT=< agent-account>
516+ XPR_PRIVATE_KEY=PVT_K1_...
517+ XPR_OWNER_ACCOUNT=< owner-account>
518+
519+ # Multi-tenant agents get these from KV instead of Worker secrets
520+ ```
521+
522+ ### Container Configuration
523+
524+ The OpenClaw container requires ` OPENCLAW_GATEWAY_TOKEN ` to start (since v2026.1.29). The gateway Worker:
525+ 1 . Passes the token as a container env var
526+ 2 . Injects the token server-side into WebSocket URLs via ` wsConnect() `
527+ 3 . Users never see the token — it's handled transparently
528+
529+ Cold start takes ~ 90 seconds. The loading page polls ` /api/status ` every 5 seconds with a 5-minute max timeout.
530+
531+ ### R2 Storage Isolation
532+
533+ Multi-tenant agents use prefix-based isolation in a shared R2 bucket:
534+ - Single-tenant: ` r2:moltbot-data/openclaw/ `
535+ - Multi-tenant: ` r2:moltbot-data/{agentName}/openclaw/ `
536+
537+ ### Operational Commands
538+
539+ ``` bash
540+ # Check KV config for an agent
541+ npx wrangler kv key get --remote --namespace-id 900a672e08c1402ebb1b2e8e7889dbef " agent:myagent"
542+
543+ # List all tenant configs
544+ npx wrangler kv key list --remote --namespace-id 900a672e08c1402ebb1b2e8e7889dbef
545+
546+ # View live gateway logs
547+ cd /tmp/moltworker-xpr && npx wrangler tail
548+
549+ # Build and deploy gateway
550+ cd /tmp/moltworker-xpr && npm run build && npx wrangler deploy
551+ ```
552+
553+ > ** Important:** Always run ` npm run build ` before ` npx wrangler deploy ` — Wrangler uses pre-built ` dist/ ` and does NOT rebuild automatically.
554+
555+ ---
556+
429557## Architecture Details
430558
431559See [ CLAUDE.md] ( ../CLAUDE.md ) for:
0 commit comments