# Run in the cloud

> Run the same simforge commands on SimForge's machines with --cloud, price them with --dry-run, cap them with --max-cost, and download the results.

Source: https://simforge.ai/docs/cloud

Add `--cloud` to a command and it runs on SimForge's hosted API instead of your runtime: the same command, the same scenario file, the same output. Use it for what your machine cannot do, such as photoreal renders without a large GPU, or many jobs at once.

> **Beta.** SimForge Cloud is open in beta: the Studio is free to explore and 2D renders are free; paid compute (3D renders, evaluations, transfers, Recast, asset generation, `--cloud`) runs on SimForge's machines. [Sign up](https://simforge.ai/?auth=sign-up) and start with $10 in free credits; credit purchases aren't open during the beta. Work the cloud does not run yet (3D renders, evaluations, transfers and Recast until their workers arrive) is refused with `cloud_not_open`: run the command without `--cloud`. `--dry-run` still shows the price.

## Prices

| What you run | Price |
|---|---|
| 3D render | $1.00 per render |
| Open-loop evaluation | $0.25 per evaluation |
| Closed-loop evaluation | $1.00 per evaluation |
| Closed-loop evaluation of a model | $2.00 per evaluation |
| Transfer to another map | $0.04 per scenario |
| Recast (log to scenario) | $1.00 per log |
| 3D asset generation | $1.00 per asset |
| 2D render | Free |

Each price is fixed before a run starts, and `--dry-run` shows it before anything runs. Prices are in cents on the command line (`--max-cost 100` is one dollar). Authoring, simulation, templates, OpenSCENARIO import and export, and validation are free.

- A new account starts with $10 in free credits. A paid run the workspace's credits do not cover is refused before anything starts (`insufficient_credits`), with a link to the workspace's credits page. Credits are checked first, so this is the answer even for work the cloud does not run yet.
- Free 2D renders run one at a time per account, up to 30 a day (UTC); past that the host answers `rate_limited`.
- A run that fails costs nothing. A partial or cancelled run is charged only for the jobs that finished, and Recast only when the log became a scenario.

## Price, cap, run, download

```sh
simforge render s.json --mode 3d --rig rig.json --out out-3d --cloud --dry-run
simforge render s.json --mode 3d --rig rig.json --out out-3d --cloud --max-cost 200 --wait --download
simforge simulate s.json --out sim --cloud --max-cost 50 --wait --download
```

- `--dry-run` returns the estimate (`costEstimateCents`) and starts nothing. On a scenario file it first saves the file to your workspace as an immutable revision (free), and the run that follows reuses exactly that revision. With `--max-cost` it still prices the run and adds `maxCost: {limitCents, exceeded}`: `exceeded: true` means the same command without `--dry-run` would be refused.
- `--max-cost` (in cents) is required with `--cloud`. A run whose estimate is above it or above the workspace's daily spending cap is refused before anything starts (`budget_exceeded`); one the workspace's credits do not cover, with `insufficient_credits`. `--max-cost 0` runs only free work.
- `--wait` follows the run to `succeeded`, `failed`, `partial` or `cancelled`; `--download` then writes every artifact into `--out`, sha256-checked. Giving `--out` also waits and downloads; without it the command returns as soon as the run is submitted. While it waits, stderr gets a `run.progress` line with the run id straight away, then the run's status and its jobs on each change and at least every 30 seconds; the result still comes on stdout at the end.
- `--idempotency-key` makes resending a lost submission safe: the host answers with the original run and charges once.

The cloud runs `render`, `simulate`, `preview frame` and `preview clip`, Recast (log ingestion), transfer (below), and downloads hosted datasets as files ([Getting data out](/docs/datasets)). Reinforcement learning stays local.

Hosted evaluation launches are disabled for everyone, including workspace owners and staff. `closed-loop`, `open-loop run` and cloud `evaluate` return `403 evaluation_launch_disabled`, including dry runs. Use the **Request evaluation** form on the Model Comparison page instead. Existing evaluation results and downloads stay available.

## Recast: bring your own logs

```sh
simforge import log drive.recording.json --map auto --name "left turn" --cloud --max-cost 100 --out ./drive
simforge import log drive.mcap --map auto --cloud --dry-run
```

Recast turns a recorded drive into an editable scenario: a recording (`simforge.recording/v1`) or a ROS 2 MCAP lidar log becomes a scenario on one of SimForge's maps. `--map auto` takes the recording's own map, or the map its GNSS path lies in. An MCAP log is perceived on a GPU worker first; its detector's weights are CC BY-NC-SA 4.0, so scenarios made from MCAP logs are for non-commercial use.

## The same event on another map

```sh
simforge transfer s.json --map yale-street --cloud --max-cost 20 --out ./yale
```

A transfer that lands creates a new scenario in the workspace; one no site on the map accepts creates nothing and exits 2 with its verdict.

> Run transfer with `--cloud` for now. A local transfer needs the target map's `odr` derivative, which `simforge maps pull` does not install yet, so it stops with `map_facts_missing`.

## Follow a run

```sh
simforge runs list --limit 20
simforge runs watch <run-id>
simforge runs cancel <run-id>
simforge results download <run-id> --out ./results
simforge usage
```

A partial or cancelled run keeps the artifacts it produced.

## Hosted scenarios

A scenario stored in your workspace runs at an immutable revision, which pins the exact map version, actors and recordings:

```sh
simforge scenarios list --limit 20
simforge render <scenario-id> --revision <revision-id> --mode 2d --out ./render --cloud --max-cost 50 --wait --download
```

To change a scenario and keep the original, copy it. The copy is a new scenario with the same map, actors, timeline and settings, named `<name> (copy)`; the original's renders and runs stay with the original. It lands in the original's dataset, or in your default dataset when you cannot change that one (`--dataset` picks another):

```sh
simforge scenarios copy <scenario-id> --name "Left turn, wet"
```

For a scenario shared from another workspace, the copy keeps its pinned recordings and provenance. If that original already has a copy in your target dataset, the existing copy opens instead of making another; the shared original stays read-only.

## Sign-in, scopes and API keys

`simforge login` asks for scopes that cover downloads and cloud runs. A CI job can use an API key instead: set `SIMFORGE_API_KEY` (`sfk_…`) and `SIMFORGE_API_URL`. The key acts in the workspace it was created in, and your workspace role still applies: a viewer only reads, runs need a member.

Managing keys needs the `keys:admin` scope, which a plain login does not ask for. `--scope` adds a scope to the default ones, so sign in again with it, then create the key:

```sh
simforge login --scope keys:admin          # the default scopes plus keys:admin
simforge keys create --name ci --expires-in-days 90
simforge keys list
simforge keys revoke <key-id>
```

A new key's secret (`sfk_…`) is printed once. You can also create and revoke keys in the browser, on your workspace's [API keys page](https://simforge.ai/dashboard/workspace/settings?view=api-keys). If `simforge auth status` then lists only `keys:admin` under `scopes`, the CLI is an older one that replaced the defaults: reinstall it (`curl -fsSL https://simforge.ai/install.sh | sh`), or name every scope (`simforge login --scope keys:admin --scope runs:write …`) as its `insufficient_scope` hint prints.

An AI agent that calls the API without the CLI signs in through [auth.md](/auth.md): you approve it on simforge.ai with a code it shows you, for one organization and the scopes it asks for.

## Errors

| Code (HTTP) | Meaning | Do |
|---|---|---|
| `cloud_not_open` (403) | SimForge Cloud is not open on this host yet (beta), or does not run this work yet: the reason names it ("3D renders aren't available yet on SimForge Cloud."), `detail.code` is `run_kind_unavailable` and `detail.kinds` its job kinds | Run the command without `--cloud` |
| `email_unverified` (403) | Runs, free 2D renders included, need a verified email; `detail.resendUrl` is the page that resends the link | Open the link in your email, or resend it, then retry |
| `insufficient_credits` (402) | The workspace's credits do not cover the run's price; `detail.creditsUrl` is its credits page. During the beta credit purchases are closed (`detail.checkout` is `closed`) | Run it locally, or choose free work such as a 2D render |
| `rate_limited` (429) | A free 2D render over the account's limit: one at a time (`detail.limit` `free_2d_concurrent`) or 30 a day (`free_2d_daily`) | Start it when the running one finishes, or after 00:00 UTC |
| `max_cost_required` (the CLI's) | `--cloud` without a cost cap; nothing was sent | Pass `--max-cost` deliberately |
| `budget_exceeded` (402) | Estimate above `--max-cost` or the workspace's daily spending cap (`detail.limit` is `max_cost` or `daily_cap`). A `--dry-run` is never refused for `--max-cost`: it answers the price with `maxCost.exceeded` | Raise the cap within your budget, or stop |
| `insufficient_scope` (403) | A scope (`detail.required`) or role (`detail.requiredRole`) is missing, or `--workspace` names another workspace than the login's (`detail.code` `workspace_mismatch`) | Run the login the hint names (`simforge login --scope keys:admin` for API keys), sign in for that workspace's organization, or ask an admin |
| `not_found` (404) | The object does not exist or is not visible to you | Check the id and the workspace |
| `conflict` (409) | A stale version or digest, or a duplicate | Read the object again, then decide |

The hosted API is described by its [OpenAPI document](/docs/openapi.json).
