Caasi v0.2.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
scriptpathRequired. 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.
statusSimulation backend status.
checkCheck resources before launching.
logsShow logs of a simulation run.
extensionsList extensions in the Isaac Sim install tree.
stop / pause / resumeStop, pause or resume a running simulation.

Descriptions are the CLI's own — caasi sim --help prints this list. The launchers take the experiment YAML above and produce ordinary tracked runs; the rest operate on those runs or on the install itself.

caasi sim run

caasi sim run CONFIG_PATH [--name NAME] [--dry-run] [--json] [-- SCRIPT_ARGS…]
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 — 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}.

Status, checks and lifecycle

caasi sim status

caasi sim status [--json]

Two things at a glance: is an Isaac Sim install resolvable, and which sim-backend runs are currently active (running/paused)?

shellcaasi sim status
✓ Isaac Sim 6.0 → /opt/isaac-sim-6.0
ID                    Name  Status   PID
20260905-142301-wave  wave  running  48213
caasi sim status --json | jq '.backend'
{ "tool": "isaacsim", "version": "6.0", "path": "/opt/isaac-sim-6.0", "python": null }

Always exits 0 — an unregistered backend is reported (✗ Isaac Sim is not registered (caasi config set tools.isaacsim...)) but is not an error. JSON: {"backend": {…}, "active_runs": [run records]}.

caasi sim check

caasi sim check [--verbose]

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).

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 && caasi sim run experiments/wave.yaml

Exit 1 if any check fails (warnings don't fail), else 0 — made for && chains.

caasi sim logs

caasi sim logs QUERY [--lines|-n N] [--follow|-f] [--stream|-s stdout|stderr]

caasi run logs restricted to simulation runs — same options and defaults (-n 50, -s stdout), same follow behaviour. A run started by another backend is rejected instead of silently shown:

shellcaasi sim logs latest -n 2
[14:41:07] step 10000/10000 fps 244.1
[14:41:07] done.
caasi sim logs ant
Error: Run has backend 'lab', not 'sim'; use: caasi run logs <query>

Exit 1 for an unknown run, a non-sim backend, an unknown --stream value or a missing log file. To watch both streams at once, use caasi run attach.

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 status only reports it. A tree with no extension manifests prints No extensions found. and exits 0.

caasi sim stop / pause / resume

caasi sim stop   QUERY
caasi sim pause  QUERY
caasi sim resume QUERY

Simulation-flavored shortcuts for the identical run lifecycle commands (same QUERY semantics — latest, id prefix or name — same signals, same messages, same exit codes). Convenience, nothing more:

shellcaasi sim pause latest
Run 20260905-142301-wave paused.
caasi sim resume latest && caasi sim stop latest
Run 20260905-142301-wave resumed.
Run 20260905-142301-wave stopped.

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.
trainTrain a policy as a tracked background run.
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. The four launchers share their plumbing:

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.

caasi lab train

caasi lab train CONFIG_PATH [--steps N] [--envs N] [--resume PATH] [--seed N]
              [--device TEXT] [--name NAME] [--dry-run] [--json] [-- SCRIPT_ARGS…]

The Lab-side twin of caasi train, with the same argv translation: --steps, --envs, --resume, --seed, --device, then --headless when the YAML is headless, then your trailing args. It adds --name and --json, and records kind: train with extra: {experiment, steps, envs}:

shellcaasi lab 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 lab train experiments/ant.yaml --steps 500000 --envs 4096 --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.