# Run Sim-Auto in the cloud

> Make generated camera clips of your scenarios, or run your own Sim-Auto requests on SimForge's GPUs, with simforge factory; every generator option, its flag and its API field.

Source: https://simforge.ai/docs/run-sim-auto-in-the-cloud

SimForge Factory runs the Cosmos3-Nano-Sim-Auto video generator on SimForge's GPUs. It does two kinds of work:

- **Scenario clips.** You name scenarios and a look (or your own prompt). SimForge renders each scenario, draws the layout videos the generator follows, generates the clip, checks it against the render and labels it. You get checked, labeled camera clips; a clip that fails the check is made again on a new seed, free.
- **Raw generations.** You bring the generator's inputs yourself: a control (layout) video per camera, a prompt per camera, and in simulator mode a first frame per camera. SimForge runs exactly the request a local Sim-Auto server would get, and hands back what it made. No scenario, no labels, no check.

| | Scenario clips | Raw generations |
|---|---|---|
| You give | scenarios, looks or a prompt | control videos, prompts, first frames |
| Length | always 20 s: 600 frames at 30 fps | what you ask for (frames, fps, aspect) |
| Checked and labeled | yes | no |
| Charged | only for accepted clips; flagged and rejected clips are free | $1.00 per generation, whatever it shows |

Every scenario clip is 20 seconds, 600 frames at 30 fps, at 832x480: the generator makes 601 frames and the last is dropped. A scenario shorter than 20 s is simulated on to 20 s, and a longer one gives its first 20 s; the quote says so.

## Make scenario clips

```sh
simforge factory looks
simforge factory clip create --scenario SCENARIO_ID --look fog-dawn --look snow --dry-run
simforge factory clip create --scenario SCENARIO_ID --look fog-dawn --seed 7 --seed 8 --wait
simforge factory clip create --dataset DATASET_ID --prompt "Heavy rain at night, wet asphalt reflecting street lights." --yes
```

`simforge factory looks` lists the looks; an experimental one may not apply well. Name scenarios with `--scenario` (repeatable) or every scenario of a dataset with `--dataset`, and looks with `--look` (repeatable) or your own conditions with `--prompt`. `--camera-prompt CAMERA=TEXT` replaces one camera's whole prompt, and `--camera` (repeatable) makes fewer cameras of the 4-camera rig, priced on those cameras. `--seed` (repeatable) picks the seeds, or `--seeds-per-look N` makes N clips per scenario and look. `--mode simulator` also gives the generator each camera's first rendered frame, so the clip keeps the render's lighting (its look is then always Rendered).

The CLI prices the request first and shows the clips and the most it can cost, then asks before starting: type `y`. `--yes` starts without asking (needed when nothing can prompt, such as in a script), `--dry-run` only prices, and `--max-cost-cents` sets the cap yourself (by default the quote). A clip made with your prompt is labeled custom, and no check verifies its conditions.

## Run your own Sim-Auto request

```sh
simforge factory params
simforge factory clip create --raw \
  --camera camera_front_wide_120fov --control camera_front_wide_120fov=front.mp4 \
  --camera-prompt camera_front_wide_120fov="A wet city street at dusk, seen ahead from the windscreen." \
  --frames 601 --fps 30 --seed 1234 --wait
simforge factory clip create --raw --mode simulator \
  --control camera_front_wide_120fov=front.mp4 --vision camera_front_wide_120fov=front.png \
  --camera-prompt camera_front_wide_120fov="Golden hour, long shadows."
```

Give each camera its control video with `--control CAMERA=FILE.mp4` and its prompt with `--camera-prompt CAMERA=TEXT`; the cameras are generated in the order you name them (`--camera`, else the order of `--control`). In simulator mode give each camera its first frame with `--vision CAMERA=FILE.png` (or `.jpg`). `--prompt` is the request's overall prompt. Without `--frames` and `--aspect` the request names neither, exactly as a local call: the server makes its default 201 frames, at the aspect bucket closest to your first control video.

The CLI uploads each file and checks it against what the GPU worker accepts (format, size, frame rate and frame count) before anything starts; a file that would be refused stops the request, with the reason, and nothing is charged. It then shows the price and asks:

```
1 raw generation: $1.00 (charged per generation, whatever it shows; no check).
Start it? Type y and press Enter to start; anything else cancels.
```

A raw generation costs $1.00, charged when it delivers, whatever the video shows: there is no check and no free re-seed. One that never delivers (no GPU came up, the worker failed) is free. `simforge factory params` shows the price this deployment charges.

## Every generator option

`simforge factory params` lists every option the generator has, what a scenario clip and a raw generation may set, what is fixed and why, and whether this deployment offers it. The raw generation sends the Sim-Auto option itself (the first column); a scenario clip request (`POST /api/v1/factory/runs`) names it by its scenario clip field. A fixed option may be given with its fixed value only, so a request you used locally carries over unchanged; any other value is refused with the reason below.

| Sim-Auto option | CLI flag | Scenario clip field | Scenario clip | Raw generation |
|---|---|---|---|---|
| `seed` | `--seed` | `seeds`, `seedsPerLook` | settable; by default derived from the clip's id, so the same request makes the same clip | settable; by default derived from the request |
| `extra_params.multiview.views[].vision_reference_index` | `--mode` | `mode` | `positions` (default) or `simulator` | `positions` (default) or `simulator`; simulator needs one first frame per camera |
| none: SimForge's own | `--look` | `lookIds` | a look from `simforge factory looks`, or your own prompt | not used: a raw generation's prompts are yours, sent as given |
| `prompt` | `--prompt` | `prompt` | your conditions in place of a look, at most 2000 characters | sent as given; by default "A photorealistic driving scene." |
| `extra_params.multiview.views[].prompt` | `--camera-prompt` | `cameraPrompts` | replaces a camera's look sentence and description | one for every camera, at most 6000 characters |
| `extra_params.multiview.views[].camera_key` | `--camera` | `cameras` | any of the 4-camera rig, in rig order (default all four) | any of the model's 11 cameras, in your order |
| `input_references (extra_params.multiview.views[].control_reference_index)` | `--control` | none | fixed: drawn from the scenario's render | one MP4 per camera (H.264 or HEVC, the output size and fps, at least frames - 1 frames) |
| `input_references (extra_params.multiview.views[].vision_reference_index)` | `--vision` | none | fixed: the render's first frame | one PNG or JPEG per camera, in simulator mode only |
| `num_frames` | `--frames` | `numFrames` | fixed at 601 (600 kept): every scenario clip is 20 s | 5 to 2404, on the 4k+1 grid; at most 2404 over all cameras. By default the server's own (201), as a local call |
| `fps` | `--fps` | `fps` | fixed at 30: every scenario clip is 20 s | 1 to 60 (default 30; 10 to 30 recommended) |
| `extra_params.resolution` | `--resolution` | `resolution` | fixed at 480: the checkpoint is trained at 480 | fixed at 480: the checkpoint is trained at 480 |
| `extra_params.aspect_ratio (and size)` | `--aspect` | `aspectRatio` | fixed at 16,9 (832x480): the clip's labels are drawn at that size | 16,9 (832x480), 9,16, 4,3, 3,4 or 1,1. By default the bucket closest to the first control video's shape, as the server picks it |
| `num_inference_steps` | `--steps` | `numInferenceSteps` | fixed at 4: the checkpoint is distilled to 4 steps | fixed at 4: the checkpoint is distilled to 4 steps |
| `guidance_scale` | `--guidance` | `guidanceScale` | fixed at 1: the distilled model runs guidance 1 only | fixed at 1: the distilled model runs guidance 1 only |
| `extra_params.multiview.condition_video_as_image` | `--condition-video-as-image` | `conditionVideoAsImage` | fixed at true: the model conditions on each camera's first frame only | fixed at true, sent only with first frames |
| `negative_prompt` | `--negative-prompt` | `negativePrompt` | fixed at none: the model takes no negative prompt | fixed at none: the model takes no negative prompt |
| `model` | `--model` | `model` | fixed: one variant is deployed, nvidia/Cosmos3-Nano-Sim-Auto | fixed: one variant is deployed, nvidia/Cosmos3-Nano-Sim-Auto |

## Follow, retry, cancel

```sh
simforge factory clip list
simforge factory clip get RUN_ID
simforge factory clip wait RUN_ID
simforge factory clip retry RUN_ID --flagged
simforge factory clip cancel RUN_ID
```

`clip get` shows each clip's status, verdict, whether its prompt came from a look or from you, what it is waiting for and its cost. `clip wait` follows a run until every clip is done, printing what the clips wait for whenever it changes ("Waiting for a GPU, 3 clips ahead"); it exits 0 when every clip is done and non-zero when any failed. `clip retry` makes a run's failed and cancelled clips again (or `--failed`, `--cancelled`, `--flagged` for new seeds), or a failed raw generation, after the same quote and confirmation as `clip create`. Clips already accepted stay charged when you cancel.

## Many clips from one file

```sh
simforge factory batch clips.yaml --dry-run
simforge factory batch clips.yaml --yes --wait
```

```yaml
- scenario: SCENARIO_ID
  look: fog-dawn
  seed: 7
- scenario: SCENARIO_ID
  prompt: Dense fog at dawn, low sun behind the haze.
  cameras: [camera_front_wide_120fov]
  mode: positions
- raw: true
  fromRequest: run_0123/request.json
```

Each row is its own run: a scenario row takes `scenario`, `look` or `prompt`, and optionally `seed`, `cameraPrompts`, `cameras` and `mode`; a raw row takes `fromRequest` (a request.json, below) or `cameras`, `controls`, `visions`, `cameraPrompts`, `prompt`, `frames`, `fps`, `aspect`, `seed` and `mode`. Paths are relative to the file. Every row is priced first and the total is confirmed once. Each row is submitted under a key made from what it asks, so running the same file again submits nothing new: the CLI prints the runs it already made. JSON works too (a list of the same rows).

## Download

```sh
simforge factory clip download RUN_ID --out ./clips
simforge factory clip download RUN_ID --out ./clips --links-only
```

The CLI writes `./clips/RUN_ID/manifest.json`, every file with its signed link, sha256 and size, then fetches each file to its place and checks its sha256; running it again fetches only what is missing. `--links-only` writes just the manifest, for your own downloader. Nothing is zipped. A scenario clip's files are in `SCENARIO_ID/generated/LOOK-SEED/`: every file its `manifest.json` lists, among them `video/CAMERA.mp4`, `layout/CAMERA.mp4`, `inputs/CAMERA.mp4` and `inputs/CAMERA.png` (what the generator was given), `labels/boxes_2d.parquet`, `labels/actors_3d.parquet`, `labels/ego.parquet` and `quality.json`. A raw generation's are `request.json`, `response.mp4` (the server's own output), `video/CAMERA.mp4`, `timing.json` and `inputs/` (the files it was sent). Every output is a standard format: MP4 video, JSON, and Parquet labels.

## Your request, here or there

A raw generation is exactly a local Sim-Auto call, in both directions.

**From the cloud to your own server.** A delivered `request.json` holds the request as it was sent: the form fields under `request.fields`, and the files under `request.files` in order, each read from `inputs/` beside it. Start Sim-Auto with the model card's server:

```sh
vllm serve nvidia/Cosmos3-Nano-Sim-Auto --omni --model-class-name Cosmos3NanoSimAutoPipeline \
  --deploy-config <vllm-omni>/vllm_omni/deploy/cosmos3_nano_sim_auto.yaml --port 8000
```

and send it the delivered request unchanged, from the folder `clip download` wrote:

```sh
cd ./clips/RUN_ID
eval "curl -sS --fail -o local.mp4 http://127.0.0.1:8000/v1/videos/sync $(jq -r '
  [ (.request.fields | to_entries[] | "--form-string", "\(.key)=\(.value | if type == "string" then . else tojson end)"),
    (.request.files[] | "-F", "input_references=@\(.path);type=\(.mediaType)") ]
  | map(@sh) | join(" ")' request.json)"
```

Each field becomes a `--form-string` part (taken literally) and each file an `input_references` part, in the request's order.

**From your server to the cloud.** A request you used locally runs on SimForge's GPU as it is:

```sh
simforge factory clip create --raw --from-request request.json
```

It reads a delivered `request.json`, or your own `{"endpoint": "/v1/videos/sync", "fields": {...}, "files": [{"filename": "front.mp4", "path": "front.mp4"}]}` with `fields` exactly as you send them to the server (values as text, `extra_params` as its JSON text or the object) and `files` in `input_references` order, each `path` relative to the request.json's folder. The CLI uploads the files in order, checks them, and sends `fields` byte for byte.

## Over the API

Every command is an `/api/v1` call ([the command reference](/docs/cli/factory) lists every flag): `GET /api/v1/factory/params` and `/api/v1/factory/looks`; `POST /api/v1/factory/estimate`, then `POST /api/v1/factory/runs` with `maxCostCents` and an `Idempotency-Key`; for a raw generation, `POST /api/v1/uploads` for each file, `POST /api/v1/factory/inputs/check`, then `POST /api/v1/factory/generations` with the request's `fields`, its `files` and `maxCostCents`. Retrying a create with the same `Idempotency-Key` returns the run it already made.
