Skip the browser — call our REST API directly, connect Claude or GPT via our MCP server, use our Python or TypeScript SDK, or script workflows from the CLI. We are the server; you are the client.
Need proof of accuracy first? View the full benchmark report — side-by-side cost and latency results across all four providers.
Run real API calls right here — no account or API key required
/api/healthVerify the API is up. Returns status, version, and uptime.
/api/descriptionDiscover every capability, tool, and endpoint this platform exposes — no key needed.
/api/chaos/scenariosList all built-in failure scenarios you can inject: AZ outage, DB crash, network partition, and more.
/api/simulationsCreate a real AWS simulation with a t3.medium compute resource, then immediately run a step to see live metrics — cpu, latency, errorRate, and cost.
/api/demo/rl/startBootstrap a Gym-compatible RL environment, run the first episode step, and see the reward signal. Hit 'Step again' to advance the episode — watch obs, reward, done, and sim_time_human update with each action.
/api/demo/rl/db/startSame RL loop, but the scenario adds an Aurora Serverless v2 database. During the first few steps the DB is still warming up: its own cpu_util reads 0, ACU sits at the 0.5 floor, and it bills at the ~$0.06/hr floor — yet its small floor-sized pool saturates, so connection_pressure turns negative and the 'DB pool saturated' cue lights up. Hit 'Step again' and watch the per-DB metrics.serverless[] breakdown ramp its ACU and cost up while the pool pressure eases.
Call our REST API directly — no browser or UI required on your end
Every API endpoint is available at this URL. Authenticate with your API key and start making requests — no setup on your end beyond getting a key.
https://www.cloudworldmodel.ai
Pass your API key as a Bearer token in every request. Here's a minimal working example — create a simulation then advance it one step:
# All authenticated requests use a Bearer token in the Authorization headercurl -X POST https://www.cloudworldmodel.ai/api/simulations \-H "Authorization: Bearer your_api_key_here" \-H "Content-Type: application/json" \-d '{"name": "prod-replica","resources": [{ "id": "web", "type": "compute", "name": "Web Server", "provider": "aws" }]}'# Then step the simulation (replace <id> with the id from the response above)curl -X POST https://www.cloudworldmodel.ai/api/simulations/<id>/step \-H "Authorization: Bearer your_api_key_here" \-H "Content-Type: application/json" \-d '{ "trafficRPS": 1500 }'
# Health check — no auth requiredcurl https://www.cloudworldmodel.ai/api/health# → { "status": "ok", "version": "1.0.0", "uptime": 42.3 }# Full OpenAPI spec as JSONcurl https://www.cloudworldmodel.ai/api-docs/openapi.json# Interactive Swagger UIopen https://www.cloudworldmodel.ai/api-docs
Every /rl/environments/:id/step call accepts an optional tick_seconds field (1–3600) that overrides the episode-level clock for that single step. Use this to run a fast warm-up phase before your agent starts making real decisions:
The actual value used is reflected back in observation.tick_seconds so your agent always knows how much simulated time each step represents.
import requestsBASE_URL = "https://your-domain.com/api"API_KEY = "your_api_key_here"ENV_ID = "env-aws-001"session = requests.Session()session.headers.update({"Authorization": f"Bearer {API_KEY}"})def step(action: dict, tick_seconds: int) -> dict:r = session.post(f"{BASE_URL}/rl/environments/{ENV_ID}/step",json={"action": action, "tick_seconds": tick_seconds},)r.raise_for_status()return r.json()NO_OP = {"type": "no_op", "parameters": {}}# Phase 1 — Warm-up: large ticks fast-forward through startup noise.# 20 steps × 300 s = 6,000 s ≈ 1.7 h of simulated time.for i in range(20):data = step(NO_OP, tick_seconds=300)print(f"warmup {i+1:2d} sim={data['sim_time_human']} cpu={data['obs']['cpu_util']:.1%}")if data["done"]:break# Phase 2 — Training: 1-minute ticks for precise autoscaling control.# The agent now reacts on a per-minute basis, matching real cooldown windows.done = Falsewhile not done:cpu = data["obs"]["cpu_util"]if cpu > 0.75:action = {"type": "scale_out", "parameters": {"instanceCount": 1}}elif cpu < 0.30 and data["obs"]["instances"] > 1:action = {"type": "scale_in", "parameters": {"instanceCount": 1}}else:action = NO_OPdata = step(action, tick_seconds=60)done = data["done"]print(f"t={data['t']:4d} reward={data['reward']:+.3f} "f"cpu={data['obs']['cpu_util']:.1%} "f"p95={data['metrics']['latency_p95']} ms "f"cost=${data['metrics']['cost_usd_hr']:.2f}/hr")
See the full list of available observation fields, action types, and provider-specific environment options in the RL Environments reference.
Aurora Serverless v2 (aurora-serverless) scales ACUs continuously between minCapacity and maxCapacity, so cost tracks actual load rather than peak provisioned size. The simulation engine models a 2–4 step ACU ramp delay after add_resource — during those steps cpu_util reads 0 and cost_usd_hr reflects only the minCapacity floor (~$0.06/hr at 0.5 ACUs). Those top-level signals hold in this single-DB quickstart; in multi-resource sims the sim-wide aggregates mask one DB's warming window and ACU floor, so read the per-DB metrics.serverless[i] array instead. The full episode loop — including ramp-up handling, reward shaping, and idle scale-back — is covered in the Simulation Walkthrough.
Call metered endpoints without an account — pay per call in USDC, no API key required
Metered endpoints support the x402 pay-per-HTTP-request protocol. When no API key is present the server returns 402 Payment Required with the payment details in the response body. Your client pays the exact amount in USDC on Base mainnet, then retries with the signed receipt — the call goes through as normal. No account, no signup, no monthly commitment.
Payments are verified by the Coinbase x402 facilitator. You need a funded EVM wallet on Base with USDC to use this access method.
Browse and call endpoints directly at x402scan — the discovery index for x402-enabled APIs.
Discover configuration
Fetch GET /api/billing/x402/config to read the live wallet address, USDC amounts per call type, and facilitator URL.
Call the endpoint (no key needed)
Send your request without an API key. The server returns 402 Payment Required with payment details in the body.
Pay and retry
An x402-aware client signs a USDC transfer on Base, gets a receipt from the Coinbase facilitator, and retries with the X-Payment header attached.
Check your balance
Use GET /api/billing/x402/balance?address=0x… to see your remaining credits and GET /api/billing/x402/transactions?address=0x… for a full history.
# Step 1 — discover the live config (no auth required)curl https://www.cloudworldmodel.ai/api/billing/x402/config# → { "enabled": true, "network": "base", "asset": "0x833…913",# "payTo": "<wallet>", "facilitatorUrl": "https://x402.org/facilitator",# "creditsPerUsdc": 1000, "prices": { "simulation_step_hybrid": 1, ... } }# Step 3 — once you have a signed receipt from the facilitator,# attach it as the X-Payment header and retry the request.# (x402-aware clients handle this automatically — see snippets below.)curl -X POST https://www.cloudworldmodel.ai/api/simulations/<id>/step-hybrid \-H "Content-Type: application/json" \-H "X-Payment: <base64-encoded-receipt-from-facilitator>" \-d '{"trafficRPS":1000}'# → 200 OK with normal response body (payment verified, credits deducted)# Step 4 — check remaining credits for a wallet addresscurl "https://www.cloudworldmodel.ai/api/billing/x402/balance?address=0xYourWallet"# → { "address": "0xyourwallet", "credits": 847 }# Full transaction history (most recent first)curl "https://www.cloudworldmodel.ai/api/billing/x402/transactions?address=0xYourWallet&limit=10"# → { "address": "...", "transactions": [{ "delta": -1, "type": "rl_step", ... }, ...] }
| Endpoint | Call type | Price (USDC) |
|---|---|---|
POST /api/simulations/:id/step-hybrid | simulation_step_hybrid | $0.0010 |
POST /api/rl/environments/:id/step | rl_step | $0.0010 |
POST /api/simulations/:id/explain | ai_explain | $0.0010 |
POST /api/simulations/:id/optimize | ai_optimize | $0.0010 |
POST /api/simulations/:id/troubleshoot | ai_troubleshoot | $0.0010 |
POST /api/simulations/:id/analyze-bottlenecks | ai_bottleneck | $0.0010 |
POST /api/chaos/run | chaos_run | $0.0050 |
POST /api/chaos/batch | chaos_batch | $0.0050 |
POST /api/multi-cloud/explore | multicloud_explore | $0.0050 |
POST /api/analysis/optimize | optimization_run | $0.0050 |
POST /api/predictions/validate | prediction_validate | $0.0050 |
POST /api/predictions/optimize-thresholds | prediction_optimize_thresholds | $0.0050 |
Prices are in USDC on Base mainnet. Fetch the live price table at GET /api/billing/x402/config. Agent tooling (x402scan, OpenAI plugins) can also auto-discover all paid endpoints via the curated spec at GET /.well-known/x402/openapi.json.
# 1. Call any metered endpoint without an API key.curl -X POST https://www.cloudworldmodel.ai/api/chaos/run \-H "Content-Type: application/json" \-d '{"simulationId":"<id>","scenario":"az_outage"}'# → 402 Payment Required# Body: { "error": "Payment required", "accepts": [{ "scheme": "exact",# "network": "base", "maxAmountRequired": "5000",# "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",# "payTo": "<wallet>", ... }] }# 2. Use an x402-aware client to pay and retry automatically.# The client signs a USDC transfer on Base, submits it to the# Coinbase facilitator, and retries with X-Payment in the header.# The server verifies the receipt and processes the request normally.
from x402.client import wrap_httpx_clientimport httpx, os# Wrap any httpx client — payments are handled transparently.client = wrap_httpx_client(httpx.Client(),wallet_key=os.environ["AGENT_WALLET_PRIVATE_KEY"],)# Call the API exactly as you normally would — no API key header needed.# If the server returns 402, the wrapper pays and retries automatically.response = client.post("https://www.cloudworldmodel.ai/api/simulations/<id>/step-hybrid",json={"trafficRPS": 1000},)data = response.json()print(data["metrics"]["cpuUsage"]) # e.g. 0.71print(data["metrics"]["latencyP95"]) # e.g. 138.4print(data["metrics"]["costPerHour"]) # e.g. 0.096
import { wrapFetchWithPayment } from "x402/client";import { privateKeyToAccount } from "viem/accounts";const account = privateKeyToAccount(process.env.AGENT_WALLET_PRIVATE_KEY as `0x${string}`);// Wrap the global fetch — any 402 response triggers automatic payment + retry.const payingFetch = wrapFetchWithPayment(fetch, account);const res = await payingFetch("https://www.cloudworldmodel.ai/api/chaos/run",{method: "POST",headers: { "Content-Type": "application/json" },body: JSON.stringify({ simulationId: "<id>", scenario: "az_outage" }),});const data = await res.json();console.log(data); // same response shape as the authenticated API
Machine-readable x402 discovery signal also available in llms.txt and llms-full.txt. The x402 section in llms-full.txt includes the discovery endpoint, network, asset, and per-call price table in a format optimized for agent consumption. See the landing page overview for a human-readable introduction to x402 on this platform.
Model Context Protocol — lets Claude, GPT, and other AI assistants call our simulation directly via stdio
npm install -g "github:canvascloudai/cwm-mcp"
claude_desktop_config.json){"mcpServers": {"cloud-world-model": {"command": "npx","args": ["cwm-mcp"],"env": {"CWM_API_KEY": "your_api_key_here","CWM_BASE_URL": "https://www.cloudworldmodel.ai"}}}}
create_simulationCreate a new virtual cloud environment with resources and connections.simulate_stepAdvance the simulation by one tick and return metrics.get_simulation_metricsRead the latest CPU, latency, error rate, and cost metrics.list_simulationsList all simulations visible to the current API key.rl_create_environmentCreate a Gym-compatible RL training environment linked to a simulation.rl_stepExecute one RL action (scale_out, scale_in, etc.) and receive observation/reward.rl_resetReset an RL environment to start a new episode.list_chaos_scenariosList available chaos engineering scenarios (AZ outage, DB crash, etc.).chaos_runStart a chaos experiment and return a job ID.chaos_job_statusPoll a running chaos job for completion.chaos_job_resultsRetrieve the full resilience report once a chaos job is done.multicloud_exploreGenerate and score multi-cloud architecture strategies.multicloud_job_statusPoll a multi-cloud exploration job.multicloud_job_resultsRetrieve ranked strategy results.prediction_validateValidate infrastructure against a traffic forecast.prediction_job_statusPoll a running prediction/validation job.prediction_job_resultsRetrieve full validation results including bottlenecks and recommendations.optimization_runStart an autoscaling threshold optimization job.optimization_job_statusPoll a running optimization job.optimization_job_resultsRetrieve optimized threshold recommendations once the job is done.Monitor active RL environments — episodes, rewards, and status — in the RL Environment Status viewer.
Official Python client — zero dependencies, uses stdlib urllib
pip install "git+https://github.com/canvascloudai/cwm-sdk.git"
from cwm import CloudWorldModelclient = CloudWorldModel(base_url="https://www.cloudworldmodel.ai",api_key="your_api_key_here",)# 1. Create a simulationsim = client.create_simulation({"name": "prod-replica","resources": [{"id": "web","type": "compute","name": "Web Server","provider": "aws","characteristics": {"size": "t3.medium"},}],})# 2. Run a simulation stepresult = client.simulate_step(sim["id"], traffic=1500)m = result["metrics"]print(m["cpuUsage"]) # e.g. 0.72print(m["latencyP95"]) # e.g. 143.2print(m["costPerHour"]) # e.g. 0.0464
Full episode loop using the SDK's higher-level interface — mirrors the Aurora Serverless quickstart without raw HTTP calls.
from cwm import CloudWorldModelclient = CloudWorldModel(base_url="https://www.cloudworldmodel.ai/api",api_key="your_api_key_here",)# 1. Create an RL environment linked to a simulation that already contains# at least one AWS database resource (the engine clones it for the episode).env_result = client.create_rl_environment(simulation_id="<sim-id>",episode_config={"maxSteps": 40},)env_id = env_result["environment"]["id"]# 2. add_resource action — adds an Aurora Serverless v2 database to the sim.# The engine models a 2-4 step ACU scale-out delay for aurora-serverless targets.step1 = client.rl_step(env_id, action={"type": "add_resource","parameters": {"resourceType": "database", "provider": "aws"},})# Response keys: observation, reward {total, components, metrics}, done, infoobs = step1["observation"] # {cpu_util, rps, instances, traffic, currentTime}reward = step1["reward"] # {total, components: {performance, cost, stability, sla, connection_pressure?}, metrics}# 3. Ramp window (steps 1-4): ACU warming up — cpu_util == 0, cost at minCapacity floor.# Only count cost + stability reward components to avoid false latency penalties.result = step1for _ in range(4):result = client.rl_step(env_id, action={"type": "adjust_threshold","parameters": {"cpuThreshold": 70},})obs = result["observation"]rc = result["reward"]["components"]adj_reward = rc["cost"] + rc["stability"]print(f"Ramp cpu_util={obs['cpu_util']:.3f} adj_reward={adj_reward:.3f}")# 4. Steady-state training loop — all reward components now meaningful. With a database# resource present this is five (performance, cost, stability, sla, connection_pressure).done = result["done"]while not done:result = client.rl_step(env_id, action={"type": "adjust_threshold","parameters": {"cpuThreshold": 70},})done = result["done"]obs = result["observation"]rw = result["reward"]print(f"Train cpu_util={obs['cpu_util']:.3f} "f"cost_usd_hr={rw['metrics']['costPerHour']:.4f} "f"reward={rw['total']:.3f}")# 5. Reset for the next episode.client.rl_reset(env_id)
Provision a managed node pool and bound its autoscaling with nodeCount / minNodes / maxNodes. /step autoscales nodeCount between min and max.
from cwm import CloudWorldModelclient = CloudWorldModel(base_url="https://www.cloudworldmodel.ai/api",api_key="your_api_key_here",)# Create a simulation with a Kubernetes node pool and bound its autoscaling.sim = client.create_simulation({"name": "k8s-cluster","resources": [{"id": "api-pool","type": "kubernetes","name": "API Node Pool","provider": "aws", # EKS (also gcp=GKE, azure=AKS, oci=OKE, digitalocean=DOKS)"characteristics": {"nodeCount": 3, # worker nodes to start with"minNodes": 2, # autoscaler won't scale below this"maxNodes": 10, # autoscaler won't scale above this"maxThroughput": 6000, # serving capacity (RPS) at nodeCount},}],})# /step autoscales nodeCount between minNodes and maxNodes; maxThroughput# and hourly cost scale proportionally with the live node count.result = client.simulate_step(sim["id"], traffic=4000)print(result["metrics"]["cpuUsage"]) # e.g. 0.68print(result["metrics"]["costPerHour"]) # scales with current nodeCount
Typed Node.js client with full IDE autocomplete, uses native fetch
npm install "github:canvascloudai/cwm-ts-sdk"
import { CwmClient } from "@cwm/sdk";const client = new CwmClient({baseUrl: "https://www.cloudworldmodel.ai",apiKey: "your_api_key_here",});// 1. Create a simulationconst sim = await client.createSimulation({name: "prod-replica",resources: [{id: "web",type: "compute",name: "Web Server",provider: "aws",characteristics: { size: "t3.medium" },},],});// 2. Run a simulation step and read metricsconst result = await client.simulateStep(sim.id, { traffic: 1500 });console.log(result.metrics.cpuUsage); // e.g. 0.72console.log(result.metrics.latencyP95); // e.g. 143.2console.log(result.metrics.costPerHour); // e.g. 0.0464
Full episode loop using the SDK's higher-level interface — mirrors the Aurora Serverless quickstart without raw HTTP calls.
import { CwmClient } from "@cwm/sdk";const client = new CwmClient({baseUrl: "https://www.cloudworldmodel.ai/api",apiKey: "your_api_key_here",});// 1. Create an RL environment linked to a simulation that already contains// at least one AWS database resource (the engine clones it for the episode).const { environment } = await client.createRlEnvironment("<sim-id>", {episodeConfig: { maxSteps: 40 },});const envId = environment.id;// 2. add_resource action — adds an Aurora Serverless v2 database to the sim.// The engine models a 2-4 step ACU scale-out delay for aurora-serverless targets.let step1 = await client.rlStep(envId, {action: { type: "add_resource", parameters: { resourceType: "database", provider: "aws" } },tick_seconds: 60,});// Response keys: t, obs, metrics, reward, reward_components, donelet { t, obs, metrics } = step1; // t=1 after first action// obs: {cpu_util, rps, instances, traffic, currentTime}// metrics: {cost_usd_hr, latency_p95, error_rate, uptime, sla_violations}// 3. Ramp window (t = 1-4): obs.cpu_util === 0, metrics.cost_usd_hr at minCapacity floor (~$0.06/hr).// Only count cost + stability reward components — skip performance and sla during ACU ramp-up.const RAMP_STEPS = 4;let result = step1;for (let i = 0; i < RAMP_STEPS; i++) {result = await client.rlStep(envId, {action: { type: "adjust_threshold", parameters: { cpuThreshold: 70 } },tick_seconds: 60,});({ t, obs, metrics } = result);const rc = result.reward_components;const adjustedReward = rc.cost + rc.stability;console.log(`Ramp t=${String(t).padStart(2)} cpu_util=${obs.cpu_util.toFixed(3)} ` +`cost_usd_hr=${metrics.cost_usd_hr.toFixed(4)} adj_reward=${adjustedReward.toFixed(3)}`);}// 4. Steady-state training loop — all reward components are now meaningful. With a database// resource present this is five components — performance, cost, stability, sla, and the// connection_pressure DB-pool penalty (see the worked connection-pool example below).// metrics.cost_usd_hr climbs over 3-6 steps toward the ACU-proportional steady-state rate.let done = result.done;while (!done) {result = await client.rlStep(envId, {action: { type: "adjust_threshold", parameters: { cpuThreshold: 70 } },tick_seconds: 60,});({ t, obs, metrics } = result);const reward = result.reward;done = result.done;console.log(`Train t=${String(t).padStart(2)} cpu_util=${obs.cpu_util.toFixed(3)} ` +`latency_p95=${metrics.latency_p95.toFixed(0)}ms ` +`cost_usd_hr=${metrics.cost_usd_hr.toFixed(4)} reward=${reward.toFixed(3)}`);}// 5. Reset for the next episode.await client.rlReset(envId);
Provision a managed node pool and bound its autoscaling with nodeCount / minNodes / maxNodes. /step autoscales nodeCount between min and max.
import { CwmClient } from "@cwm/sdk";const client = new CwmClient({baseUrl: "https://www.cloudworldmodel.ai/api",apiKey: "your_api_key_here",});// Create a simulation with a Kubernetes node pool and bound its autoscaling.const sim = await client.createSimulation({name: "k8s-cluster",resources: [{id: "api-pool",type: "kubernetes",name: "API Node Pool",provider: "aws", // EKS (also gcp=GKE, azure=AKS, oci=OKE, digitalocean=DOKS)characteristics: {nodeCount: 3, // worker nodes to start withminNodes: 2, // autoscaler won't scale below thismaxNodes: 10, // autoscaler won't scale above thismaxThroughput: 6000, // serving capacity (RPS) at nodeCount},},],});// /step autoscales nodeCount between minNodes and maxNodes; maxThroughput// and hourly cost scale proportionally with the live node count.const result = await client.simulateStep(sim.id, { traffic: 4000 });console.log(result.metrics.cpuUsage); // e.g. 0.68console.log(result.metrics.costPerHour); // scales with current nodeCount
Zero-dependency Go client — stdlib only, context-aware, Go 1.21+
go get github.com/canvascloudai/cwm-go
package mainimport ("context""fmt""log""github.com/canvascloudai/cwm-go/cwm")func main() {client := cwm.New("https://www.cloudworldmodel.ai", "your_api_key_here")ctx := context.Background()// 1. Create a simulationsim, err := client.CreateSimulation(ctx, map[string]interface{}{"name": "prod-replica","resources": []map[string]interface{}{{"id": "web", "type": "compute","name": "Web Server", "provider": "aws","characteristics": map[string]interface{}{"size": "t3.medium"},},},})if err != nil {log.Fatal(err)}// 2. Simulate a step and read metrics (cwm.Float64(rps) sets traffic; nil keeps current)result, err := client.SimulateStep(ctx, sim.ID, cwm.Float64(1500), false)if err != nil {log.Fatal(err)}m := result.Metricsfmt.Printf("CPU: %.1f%% P95: %.1fms Cost: $%.4f/hr\n",m.CPUUsage*100, m.LatencyP95, m.CostPerHour)}
Multi-episode training loop using CreateRLEnvironment, RLStep, and RLReset — context-aware throughout.
package mainimport ("context""fmt""log""github.com/canvascloudai/cwm-go/cwm")func main() {client := cwm.New("https://www.cloudworldmodel.ai", "your_api_key_here")ctx := context.Background()sim, _ := client.CreateSimulation(ctx, map[string]interface{}{"name": "rl-training","resources": []map[string]interface{}{{"id": "web", "type": "compute", "name": "Web Server", "provider": "aws"},},})env, err := client.CreateRLEnvironment(ctx, sim.ID, &cwm.RlEpisodeConfig{MaxSteps: 100,InitialTraffic: 1000,})if err != nil {log.Fatal(err)}envID := env.Environment.IDfor episode := 1; episode <= 5; episode++ {if episode > 1 {client.RLReset(ctx, envID)}var totalReward float64for step := 0; step < 100; step++ {res, err := client.RLStep(ctx, envID, cwm.RlAction{Type: "scale_out"})if err != nil {log.Fatal(err)}totalReward += res.Reward.Totalif res.Done {break}}fmt.Printf("Episode %d total_reward=%.3f\n", episode, totalReward)}client.DeleteSimulation(ctx, sim.ID)}
Wrap net/http with the x402-go transport — any 402 response is settled in USDC on Base and retried automatically. No API key required.
package mainimport ("bytes""encoding/json""fmt""log""os"// Install: go get github.com/coinbase/x402-gox402 "github.com/coinbase/x402-go/pkg/httpclient")func main() {// Wrap the stdlib http.Client — any 402 response triggers automatic// USDC payment on Base mainnet and transparent retry. No API key needed.client, err := x402.New(os.Getenv("AGENT_WALLET_PRIVATE_KEY"),x402.WithFacilitator("https://x402.org/facilitator"),)if err != nil {log.Fatal(err)}body, _ := json.Marshal(map[string]any{"trafficRPS": 1000})resp, err := client.Post("https://www.cloudworldmodel.ai/api/simulations/<id>/step-hybrid","application/json",bytes.NewReader(body),)if err != nil {log.Fatal(err)}defer resp.Body.Close()var result map[string]anyif err := json.NewDecoder(resp.Body).Decode(&result); err != nil {log.Fatal(err)}m := result["metrics"].(map[string]any)fmt.Printf("CPU: %.1f%% P95: %.1fms Cost: $%.4f/hr\n",m["cpuUsage"].(float64)*100,m["latencyP95"].(float64),m["costPerHour"].(float64),)}
Script any workflow from the terminal — no code required
# Install globally from GitHubnpm install -g "github:canvascloudai/cwm-cli"# Verifycwm --help
cwm --help outputUsage: cwm <command> [options]Commands:config Manage CLI configuration (set, show)simulate Simulation management (create, get, list, step)rl RL environment interactions (create, step, reset)chaos Chaos engineering (scenarios, run, status, results)multicloud Strategy exploration (explore, status, results)keys API key management (create, list, revoke)Options:--base-url <url> CWM server URL (overrides config)--api-key <key> API key (overrides config)--output <format> Output format: text | json-h, --help Display help for a command
# Point the CLI at our server and set your key (saved to ~/.cwm/config.json)cwm config set --base-url https://www.cloudworldmodel.aicwm config set --api-key your_api_key_here# Create a simulation from a JSON spec filecwm simulate create --file sim-spec.json# Run a simulation step (optionally inject traffic)cwm simulate step <sim-id> --traffic 1500# List all simulationscwm simulate list# Run a chaos scenariocwm chaos run <sim-id> --scenario zone_failure --duration 300# Advance an RL environmentcwm rl step <env-id> scale_up# Explore multi-cloud strategies (pass a workload JSON file)cwm multicloud explore --file workload.json
After creating an RL environment with cwm rl, you can inspect live episode progress, cumulative rewards, and environment health in the RL Environment Status viewer.
Full episode loop using shell commands — mirrors the Aurora Serverless quickstart without writing any code.
# 0. Save your key once; the CLI reads it automatically from ~/.cwm/config.json.cwm config set --api-key your_api_key_here# 1. Create an RL environment linked to a simulation that already contains# at least one AWS database resource (the engine clones it for the episode).ENV_ID=$(cwm rl create <sim-id> --max-steps 40 --output json | jq -r '.environment.id')# 2. add_resource action — adds an Aurora Serverless v2 database to the sim.# cwm rl step passes no action parameters, so use curl for this parameterized step.# The engine models a 2-4 step ACU scale-out delay for aurora-serverless targets.curl -s -X POST https://www.cloudworldmodel.ai/api/rl/environments/$ENV_ID/step \-H "Authorization: Bearer your_api_key_here" \-H "Content-Type: application/json" \-d '{"action":{"type":"add_resource","parameters":{"resourceType":"database","provider":"aws"}}}' \| jq '{obs: .obs, reward: .reward, done: .done}'# Response keys: obs {cpu_util, rps, instances, traffic, currentTime},# reward (total scalar), reward_components {performance,cost,stability,sla,connection_pressure?},# metrics {cost_usd_hr, latency_p95, error_rate}, done# 3. Ramp window (steps 1-4): ACU warming up — obs.cpu_util == 0, cost at minCapacity floor.# Only cost + stability reward components are meaningful during ACU ramp-up.for i in 1 2 3 4; docwm rl step $ENV_ID adjust_threshold --output json \| jq '{cpu_util: .obs.cpu_util, adj_reward: (.reward_components.cost + .reward_components.stability)}'done# 4. Steady-state training loop — all reward components are now meaningful. With a database# resource present this is five (performance, cost, stability, sla, connection_pressure).# Loop until the episode is done (done == true in the JSON response).while true; doRESULT=$(cwm rl step $ENV_ID adjust_threshold --output json)echo "$RESULT" | jq '{cpu_util: .obs.cpu_util, cost_usd_hr: .metrics.cost_usd_hr, reward: .reward}'DONE=$(echo "$RESULT" | jq -r '.done')[ "$DONE" = "true" ] && breakdone# 5. Reset for the next episode.cwm rl reset $ENV_ID
Verify Simulation Accuracy
Before you build on the numbers, see how they hold up. The benchmark report runs the engine head-to-head across AWS, GCP, Azure, and OCI — comparing cost accuracy, latency profiles, and throughput. Every result is reproducible and re-validated in CI.
Open Benchmark ReportGet your API key in under two minutes — no waitlist, no credit card. If you have a Canvas Cloud AI account, you already have access.