Skip to content

Run & submit

Terminal window
simulo run app.py

simulo run is the one command that runs a Simulo app. If the file declares an @app.entrypoint, simulo run imports the file and calls it, and that entrypoint’s .spawn() call packages the app. Most apps declare no entrypoint — see App & Jobs — in which case simulo run maps its own flags onto the sole job’s signature (or the --job-selected one) and calls .spawn() itself. Either way, when you are signed in or have selected a cloud environment, the package is uploaded and a cloud job is created. simulo run then follows its logs to completion:

Submitted job 'train' -> job <job-id> (cloud)
Following job <job-id> (--detach to submit without waiting)...
[train] iteration 1/200 ...

Pass --detach to submit without waiting:

Terminal window
simulo run app.py --detach
Job <job-id> submitted (cloud). Attach with:
simulo logs <job-id> --follow
simulo result <job-id>

While importing the app, simulo run captures module-level Asset.from_registry(...) handles such as the starter’s simulo/robot/cartpole:v1. Before the job is created, the platform:

  1. resolves each ref to an immutable catalog version;
  2. checks its lifecycle and runtime-validation status;
  3. records the canonical ref and package digest with the job; and
  4. mounts the digest-verified package read-only when the job executes.

That is why the starter can name a global-catalog robot without bundling its USD files into the app. Your own organization-catalog refs follow the same path.

Flags your app defines vs. flags simulo run defines

Section titled “Flags your app defines vs. flags simulo run defines”

This is the one thing to get straight: every flag after app.py that looks like --num-envs or --max-iterations belongs to your app, not to simulo run. simulo run builds an argument parser from your @app.entrypoint’s own function signature if the file has one — a parameter named num_envs becomes --num-envs, max_iterations becomes --max-iterations, and so on. Most apps have no entrypoint, in which case the same mapping applies to the sole @app.job’s own signature instead — or, with more than one job, --job NAME picks which job’s signature the remaining flags map onto. See App & Jobs for the full behavior, including the error a multi-job file without --job prints (naming the valid jobs in declaration order).

simulo run itself only understands a handful of flags. They never collide with your app’s own flags because two different parsers handle them:

Flag Meaning
--entrypoint NAME Pick which @app.entrypoint to run, if the file declares more than one.
--job NAME Pick which @app.job to submit, if the file has no entrypoint and more than one job. Deliberately absent from the generated CLI Reference’s own Options table — unlike every other flag in this list, --job is never registered on simulo run’s own argument parser; it’s resolved from your app’s job parameters instead (see App & Jobs).
--detach Submit without waiting for the job’s logs to finish.
--viewstream Enable the live 3D viewport stream for this job — see Watch a run live.
--from JOB_REF[:best|:latest] Continue from a finished job’s checkpoint instead of starting fresh — see Continue training.
--frozen Refuse the cloud submit if any captured catalog asset omits an exact :vN pin.
--strict-assets Turn deprecated/runtime-unvalidated asset warnings into submit errors.
--skip-preflight Bypass the pre-submit platform check simulo run otherwise makes before every cloud submit (the same check simulo prepare runs standalone) — no request is made, not just “ignore the result.” Cloud submit only.
--describe Print each declared job’s pre-run-known outputs (from ResumableCheckpoint / DebugOnAnomaly callbacks) and exit — submits nothing.
Terminal window
# --num-envs / --max-iterations: YOUR app's flags (built from the entrypoint's,
# or (with none) the job's own, signature)
# --detach: simulo run's own flag
simulo run app.py --num-envs 512 --max-iterations 600 --detach

The two asset gates apply only to cloud submit, where refs are resolved. A reproducible CI invocation normally uses both:

Terminal window
simulo run app.py --frozen --strict-assets --detach

Read Choose & validate assets for the global-catalog and publish flow, or Asset Catalogs & Version Pinning for the resolution rules in depth.

Running the file directly with python is a fast way to check for a mistake: Simulo detects that it’s being run as __main__ and refuses — provided the file doesn’t call .spawn() itself. With an @app.entrypoint, the refusal fires at import time, before any trailing if __name__ == "__main__": block can run, so an entrypoint-bearing file is covered unconditionally. An entrypoint-less file is covered the same way as long as nothing in it calls .spawn() directly — an explicit .spawn() call is treated as an intentional submission, not a mistake, and is never silently blocked.

Terminal window
python app.py --num-envs 512
Simulo apps are submitted with the Simulo CLI, not `python`:
simulo run app.py --num-envs 512
Nothing was submitted.

It exits with status 2 rather than doing nothing silently — a script that accidentally wraps python app.py fails loudly instead of quietly never submitting anything. The printed simulo run line reproduces your flags verbatim, so it’s copy-pasteable as-is.

Observe the job you just submitted.