Caasi v0.3.0 Simulation: sim · lab · experiment YAML

Simulation

Describe an experiment once in a small YAML file, then run it headless on Isaac Sim, Isaac Lab or plain Python — as a tracked run. Caasi resolves the right interpreter, wires the environment, detaches the process and hands you back a run id.

The experiment YAML

The single input format shared by sim run, train, benchmark start and dataset generate. By convention these live in the project's experiments/ directory.

# experiments/wave.yaml
name: wave                  # optional; default = file stem ("wave")
backend: sim                # sim | lab | python  (default: sim)
script: scripts/wave.py     # REQUIRED; relative paths resolve against this YAML's directory
headless: true              # default: true
args: ["--steps", "10000"]  # optional; passed to the script
env:                        # optional; extra environment variables
  MY_ASSET_ROOT: /data/assets
python: null                # optional; explicit interpreter, overrides backend defaults
cwd: null                   # optional; working directory (default: the YAML's directory)
KeyTypeDefaultNotes
scriptpath—Required. Missing → Error: 'script' is required in <path>.
backendsim | lab | pythonsimAnything else → error listing the valid backends.
namestrfile stemUsed for the run name / run id.
headlessbooltrueRecorded in the run manifest; train/benchmark append --headless to the script args when true.
argslist[]Must be a YAML list.
envmapping{}Merged into the process environment (yours wins over Caasi's defaults).
pythonstrautoExplicit interpreter; skips backend launcher resolution.
cwdpathYAML's directoryWorking directory of the process.

How the launch command is built

BackendCommandRequires
python<experiment.python or the CLI's python> script args…nothing
sim<registered python> or <ISAACSIM_PATH>/python.sh script args…registered tools.isaacsim (or env/`python:` fallback)
lab<registered python>, else <ISAACLAB_PATH>/isaaclab.sh -p script args…, else python3registered tools.isaaclab for the launcher path

Caasi also sets CAASI_EXPERIMENT=<abs config path> and, for sim/lab backends, ISAACSIM_PATH/ISAACLAB_PATH in the child environment — unless your env: block already defines them.

Without a registered install

If the backend needs a tool Caasi cannot resolve you get a clear error instead of a broken launch: Error: Backend 'sim' needs a registered isaacsim install. Register one with 'caasi config set tools.isaacsim...' or use backend 'python'. (exit 1)

caasi sim

SubcommandWhat it does
runRun an experiment configuration.
headlessRun an experiment with --headless --no-window forced.
checkCheck resources before launching.
extensionsList extensions in the Isaac Sim install tree.

Descriptions are the CLI's own — caasi sim --help prints this list, and since 0.3.0 it prints exactly these four. The two launchers take the experiment YAML above and produce ordinary tracked runs; check preflights the machine and extensions inventories the install.

The control verbs moved under run

sim status, sim stop, sim pause, sim resume and sim logs are gone in 0.3.0. Each was a thin wrapper around one semantic operation that the run group already owns, so drive simulation runs through it with --backend sim: caasi run status|stop|pause|resume|logs <query> --backend sim. The toolchain-availability half of the old sim status now lives in sim check; the machine-wide live view is caasi monitor. See caasi run and below.

caasi sim run

caasi sim run CONFIG_PATH [--name NAME] [--dry-run] [--json] [-- SCRIPT_ARGS…]

An entry point, not a separate operation: sim run delegates to caasi run start CONFIG_PATH --backend sim. Many entry points, one semantic op — everything below is that command with the sim backend implied, and caasi run status/logs/stop apply to the result exactly as they do to any other run.

ParameterKindTypeDefaultDescription
CONFIG_PATHargumentpathrequiredThe experiment YAML.
--nameoptionstrexperiment nameOverride the run name (and thus the run id).
--dry-runoptionflagoffPrint command, cwd and env without starting anything.
--jsonoptionflagoffPrint the run record instead of the two-line summary.
trailing argspass-throughAnything Caasi doesn't recognize is appended verbatim to the script's argv (after the YAML's args).

Example — dry run first

shellcaasi sim run experiments/wave.yaml --dry-run
Dry run — nothing was started:
  command: /opt/isaac-sim-6.0/python.sh /home/you/demo/scripts/wave.py --steps 10000
  cwd:     /home/you/demo/experiments
  env:     ISAACSIM_PATH=/opt/isaac-sim-6.0
  env:     MY_ASSET_ROOT=/data/assets

Example — launch and follow

shellcaasi sim run experiments/wave.yaml -- --seed 7
Run 20260905-142301-wave started in the background.
  Follow it with: caasi logs 20260905-142301-wave -f
caasi run status latest --json | jq '.status'
"running"

The run is created with backend: sim (or whatever the YAML says), kind: experiment, and extra: {experiment, headless} in the manifest.

JSON

--json (or the global flag — caasi --json sim run exp.yaml) prints the full run record instead of the summary; it has no effect together with --dry-run, which always prints the human-readable command. And remember: the command's exit code reflects the launch, not the simulation. Check the outcome later with caasi run status.

caasi sim headless

caasi sim headless CONFIG_PATH [--name NAME] [--dry-run] [--json] [-- SCRIPT_ARGS…]

sim run with --headless --no-window forced onto the script's argv — the same delegation to run start --backend sim, same argument, same options, same tracked run — whatever the YAML's headless: key says. For configurations written for a windowed session that you now launch on a machine with no display.

shellcaasi sim headless experiments/wave.yaml --dry-run
Dry run — nothing was started:
  command: /opt/isaac-sim-6.0/python.sh /home/you/demo/scripts/wave.py --steps 10000 --headless --no-window
  cwd:     /home/you/demo/experiments
  env:     ISAACSIM_PATH=/opt/isaac-sim-6.0
  env:     MY_ASSET_ROOT=/data/assets
caasi sim headless experiments/wave.yaml -- --seed 7
Run 20260905-142301-wave started in the background.
  Follow it with: caasi logs 20260905-142301-wave -f

The two flags land after the YAML's args and before your trailing pass-through args. The run is recorded with kind: experiment, the YAML's backend and extra: {experiment, headless: true}.

Checks and lifecycle

Two things live under sim: the pre-flight check and the install inventory. Everything else about a simulation run — is it alive, what did it print, pause it, stop it — belongs to the run group, targeted with --backend sim.

Up to 0.2.0Since 0.3.0
caasi sim statuscaasi run list --backend sim and caasi run status latest --backend sim for the runs; caasi sim check for the toolchain
caasi sim logs QUERYcaasi run logs QUERY --backend sim
caasi sim stop QUERYcaasi run stop QUERY --backend sim
caasi sim pause QUERYcaasi run pause QUERY --backend sim
caasi sim resume QUERYcaasi run resume QUERY --backend sim

caasi sim check

caasi sim check [--verbose] [--json]

Pre-flight check before a big launch: runs the doctor engine for the four sections that matter for simulation — isaac, nvidia, hardware, storage — and prints each check with hints for problems (or all, with --verbose). It also took over the toolchain-availability half of the old sim status: whether an Isaac Sim install resolves at all is the first item of the report.

sim check is one of the check entry points, so it emits the shared Check Contract — the same scope / items / result report the root caasi check produces, scoped to sim:

shellcaasi sim check
✓ Isaac Sim — 6.0 at /opt/isaac-sim-6.0
✓ nvidia-smi — 550.107.02
✓ GPU 0 — NVIDIA GeForce RTX 4090 (24564 MiB)
✓ RAM — 62.7 GiB
✓ Disk (runs) — 412.9 GiB free
caasi sim check --json | jq '{scope, result}'
{ "scope": "sim", "result": "ready" }
caasi sim check && caasi sim run experiments/wave.yaml

Exit 0 when the result is ready or warning (warnings don't gate), 3 when it is incompatible — the exit rule every check entry point shares, and what makes it usable in && chains and in CI.

caasi sim extensions

caasi sim extensions [--enabled] [--user] [--json]

An inventory of the Isaac Sim install tree — no simulator is started and nothing is imported. Caasi walks exts, extscache, extsInternal, extsUser, extsDeprecated and extsPhysics looking for <extension>/config/extension.toml, and reports the extension name (the [package] name key, else the directory name), the directory it came from, and whether [core] preload is true.

OptionTypeDefaultDescription
--enabledflagoffOnly list extensions preloaded (enabled) at startup.
--userflagoffOnly scan the extsUser directory.
--jsonflagoffArray of {name, source, enabled} objects.
shellcaasi sim extensions
Extension                 Source    Enabled
omni.anim.graph.core      exts      —
omni.kit.viewport.window  exts      ✓
caasi.custom.recorder     extsUser  —
caasi sim extensions --enabled --json
[ { "name": "omni.kit.viewport.window", "source": "exts", "enabled": true } ]

This one does need a registered install: without one it fails with Error: Isaac Sim is not registered (caasi config set tools.isaacsim...). (exit 1), where sim check reports the same absence as an item in its report. A tree with no extension manifests prints No extensions found. and exits 0.

Status, logs and lifecycle: caasi run … --backend sim

caasi run status QUERY [--backend sim|lab|python] [--json]
caasi run logs   QUERY [--backend sim|lab|python] [--lines|-n N] [--follow|-f] [--stream|-s stdout|stderr]
caasi run stop   QUERY [--backend sim|lab|python]
caasi run pause  QUERY [--backend sim|lab|python]
caasi run resume QUERY [--backend sim|lab|python]

One underlying operation per verb, reached through the run group: same QUERY semantics (latest, id prefix or name), same signals, same messages, same exit codes, and the same log options and defaults (-n 50, -s stdout). --backend filters or targets runs by backend — pass sim to keep the group to simulation runs, or drop it to act on any run:

shellcaasi run status latest --backend sim
wave (20260905-142301-wave)
  Status     running
  Backend    sim
caasi run logs latest --backend sim -n 2
[14:41:07] step 10000/10000 fps 244.1
[14:41:07] done.
caasi run pause latest --backend sim
Run 20260905-142301-wave paused.
caasi run resume latest --backend sim && caasi run stop latest --backend sim
Run 20260905-142301-wave resumed.
Run 20260905-142301-wave stopped.

To watch both streams at once, use caasi run attach; for the live resource panel — CPU, RAM, GPU, VRAM, throughput, runtime — use caasi monitor (--once for a single snapshot).

caasi lab

The same experiment YAML, launched through the Isaac Lab toolchain. Caasi delegates — it never imports Isaac Lab; it resolves the launcher, wires the environment and hands the process off as a detached run.

SubcommandWhat it does
statusIsaac Lab environment status.
runRun an experiment configuration with the lab backend.
playPlay a trained policy (isaaclab.sh -p <play script>).
evaluateEvaluate a trained policy checkpoint.

Descriptions are the CLI's own — caasi lab --help prints this list, and since 0.3.0 it prints exactly these four. The three launchers share their plumbing:

lab train moved to the root train

There is no caasi lab train in 0.3.0. Training is the generic root launcher caasi train CONFIG — one command for every backend, delegating to caasi run start and resolving the interpreter through the same backend table, so a backend: lab experiment still launches through isaaclab.sh -p. See below.

caasi lab status

caasi lab status [--json]

Isaac Lab detection plus the two integration points Caasi cares about: the isaaclab.sh launcher and whether a ros2 CLI is on PATH for the ROS bridge.

shellcaasi lab status
✓ Isaac Lab 2.0 at /opt/IsaacLab
  Launcher: /opt/IsaacLab/isaaclab.sh
  Python: /opt/IsaacLab/_isaac_sim/python.sh
caasi lab status --json
{
  "status": "ok",
  "detail": "Isaac Lab 2.0 at /opt/IsaacLab",
  "version": "2.0",
  "path": "/opt/IsaacLab",
  "python": "/opt/IsaacLab/_isaac_sim/python.sh",
  "launcher": "/opt/IsaacLab/isaaclab.sh",
  "ros2_bridge": true
}

Detection order: registry → ISAACLAB_PATH → ~/isaaclab, ~/IsaacLab, ~/workspace/* → pip metadata. When nothing is found the status is fail with an install hint — but the exit code is still 0 (this is a report, not a gate; use caasi setup or doctor for gating).

caasi lab run

caasi lab run CONFIG_PATH [--name NAME] [--dry-run] [--json] [-- SCRIPT_ARGS…]

Starts the config's script as a tracked run with kind: experiment and extra: {experiment, headless}:

experiments/ant.yamlname: ant-train
backend: lab
script: scripts/train_ant.py
headless: true
shellcaasi lab run experiments/ant.yaml --dry-run
Dry run — nothing was started:
  command: /opt/IsaacLab/isaaclab.sh -p /home/you/demo/scripts/train_ant.py
  cwd:     /home/you/demo/experiments
caasi lab run experiments/ant.yaml
Run 20260905-151207-ant-train started in the background.
  Follow it with: caasi logs 20260905-151207-ant-train -f

caasi sim run experiments/ant.yaml launches the very same file — it only adds a yellow Note: experiment backend is 'lab', not 'sim'. to point out the mismatch. Either way the run is tracked with backend: lab and appears in caasi run list like everything else.

Training: the root caasi train

caasi train CONFIG_PATH [--steps N] [--envs N] [--resume PATH] [--seed N]
            [--device cuda:0] [--dry-run] [-- SCRIPT_ARGS…]

lab train is gone in 0.3.0: training is the root caasi train, the generic training launcher. It delegates to caasi run start and resolves the interpreter through the same backend table, so a backend: lab experiment is still launched with isaaclab.sh -p — one command, every backend. The argv translation is the old one: --steps, --envs, --resume, --seed, --device, then --headless when the YAML is headless, then your trailing args; the run is recorded with kind: train and extra: {experiment, steps, envs}. train has no --name and no JSON mode of its own — use --dry-run to see the command, then caasi run status for everything after launch:

shellcaasi train experiments/ant.yaml --steps 500000 --envs 4096 --device cuda:0 --dry-run
Dry run — nothing was started:
  command: /opt/IsaacLab/isaaclab.sh -p /home/you/demo/scripts/train_ant.py --steps 500000 --envs 4096 --device cuda:0 --headless
  cwd:     /home/you/demo/experiments
caasi train experiments/ant.yaml --steps 500000 --envs 4096
Run 20260905-151207-ant-train started in the background.
  Follow it with: caasi logs 20260905-151207-ant-train -f
caasi run status latest --json | jq '.kind, .status'
"train"
"running"

caasi lab play / evaluate

caasi lab play     CONFIG_PATH [--checkpoint PATH] [--name NAME] [--dry-run] [--json] [-- SCRIPT_ARGS…]
caasi lab evaluate CONFIG_PATH [--checkpoint PATH] [--name NAME] [--dry-run] [--json] [-- SCRIPT_ARGS…]

Both run a policy instead of training one, and both take their script from optional extra keys in the same YAML: play uses play_script, evaluate uses evaluate_script and falls back to play_script; without them the plain script is used. --checkpoint PATH is handed to that script as --checkpoint PATH, ahead of any trailing args. Runs are recorded with kind: play / kind: evaluate and extra: {experiment, checkpoint}.

experiments/ant.yaml (additions)play_script: scripts/play_ant.py
evaluate_script: scripts/eval_ant.py
shellcaasi lab play experiments/ant.yaml --checkpoint logs/ant/model.pt --dry-run
Dry run — nothing was started:
  command: /opt/IsaacLab/isaaclab.sh -p /home/you/demo/scripts/play_ant.py --checkpoint logs/ant/model.pt
  cwd:     /home/you/demo/experiments
caasi lab evaluate experiments/ant.yaml --checkpoint logs/ant/model.pt
Run 20260905-172233-ant-train started in the background.
  Follow it with: caasi logs 20260905-172233-ant-train -f

Neither appends --headless on its own — pass it as a trailing arg (or in the YAML's args) when playing a policy back on a headless machine. Recorded artifacts can be opened afterwards with caasi view run.