Native & Shell
The escape hatches. caasi native hands your arguments straight to the real tool
(python.sh, isaaclab.sh, ros2) and mirrors its exit code, so
Caasi never becomes the thing that blocks you. caasi shell drops you into a shell that
already has the Isaac environment wired up. Both are foreground commands — they are
not tracked runs.
sim run / train / ros launch → background, tracked,
logged. native / shell → foreground, exit code mirrored, nothing
recorded. Use the escape hatch for one-off probing, odd flags Caasi does not model, and for
wiring Caasi into CI where the exit code is the whole contract.
caasi native
caasi native sim [ARGS…] # → <isaacsim>/python.sh ARGS…
caasi native lab [ARGS…] # → <isaaclab>/isaaclab.sh ARGS…
caasi native ros [ARGS…] # → <distro>/bin/ros2 ARGS…
caasi native run SCRIPT [--tool sim|lab|python] [ARGS…]
| Target | Resolved from | Executed as |
|---|---|---|
sim | tools.isaacsim registry, else ISAACSIM_PATH | <path>/python.sh … |
lab | tools.isaaclab registry, else ISAACLAB_PATH | <path>/isaaclab.sh … |
ros | ROS_DISTRO, else scan /opt/ros | <distro>/bin/ros2 … (or ros2 on PATH) |
run | --tool (see below) | an interpreter + your script |
Resolution is the same one every other command uses — see Tool registry. The env var is only consulted as a fallback and only accepted if it points at an existing directory.
Execution semantics
- Everything is forwarded verbatim. The
sim/lab/rostargets declare no options of their own, so every token after them is passed through untouched — including--help,--jsonand--verbose. Caasi's own global flags must come beforenative. - Output is captured, then re-printed (stdout first, then stderr). There is no timeout: Caasi waits as long as the tool runs.
- The exit code is mirrored. Whatever the tool exits with, Caasi exits with.
A negative code (process killed by a signal) becomes
1. - No run record, no logs on disk. If you want those, use
caasi sim run/caasi train/caasi ros launch.
Because stdout/stderr are captured and printed at the end, animated progress bars and interactive prompts do not render while the tool runs, and the tool sees pipes rather than a TTY. For interactive sessions use caasi shell — or call the tool directly.
caasi native sim
caasi native sim [ARGS…]
Raw Isaac Sim launcher. Useful for one-liners, for flags Caasi does not model, and for confirming that a registered install actually works.
shellcaasi native sim --version
5.1.0
caasi native sim -c "import omni.isaac.core; print('core ok')"
core ok
caasi native sim ~/work/standalone.py --headless --max_frames 200
[0.000s] Simulation App Starting...
...
[12.418s] app shutdown
exit code: 0 (mirrored from python.sh)
Nothing registered → error on stderr, exit 1:
shellcaasi native sim --version
Error: No install for isaacsim found; register one with 'caasi config set tools.isaacsim...'.
exit code: 1
Fix it once and every Caasi command benefits:
shellcaasi config set tools.isaacsim.path ~/.local/share/ov/pkg/isaac-sim-5.1.0
Set tools.isaacsim.path = /home/robot/.local/share/ov/pkg/isaac-sim-5.1.0
caasi native sim --version
5.1.0
caasi native lab
caasi native lab [ARGS…]
Raw Isaac Lab launcher (isaaclab.sh), so its own subcommands and flags are all
available.
shellcaasi native lab --help
usage: isaaclab.sh [-h] {installconda,activateconda,...} ...
caasi native lab --install
[INFO] Installing Isaac Lab extensions...
caasi native lab -p source/standalone/workflows/rl_games/train.py --headless
... (this is exactly what 'caasi train' builds for backend lab) ...
Unregistered install →
Error: No install for isaaclab found; register one with 'caasi config set tools.isaaclab...'.
(exit 1).
caasi native ros
caasi native ros [ARGS…]
Raw ros2 CLI with the distro already located — no need to source
setup.bash by hand. This is the fallback for any ROS verb that
caasi ros does not wrap.
shellcaasi native ros topic list
/parameter_events
/rosout
/cmd_vel
caasi native ros pkg list | grep nav2_costmap
nav2_costmap_2d
caasi native ros service call /global_costmap/get_plan nav2_msgs/srv/GetPlan
requester: making request: ...
caasi native ros doctor --report
All 5 checks passed
No distro → Error: ros2 CLI not found; source a ROS 2 distro first. (exit 1).
caasi ros list|topic|node|graph add uniformity, --json and
tracked-run behaviour for long-lived things (ros launch, topic --echo).
caasi native ros adds nothing but the resolved binary — take it when you want the
real thing verbatim.
caasi native run
caasi native run SCRIPT [--tool sim|lab|python] [ARGS…]
Run your own script inside a chosen environment, without writing an experiment YAML.
--tool | Interpreter used | Command |
|---|---|---|
python default | the Python running Caasi | <sys.executable> SCRIPT ARGS… |
sim | tools.isaacsim.python if set, else the launcher | <python> SCRIPT ARGS… / <isaacsim>/python.sh SCRIPT ARGS… |
lab | tools.isaaclab.python if set, else the launcher | <python> SCRIPT ARGS… / <isaaclab>/isaaclab.sh -p SCRIPT ARGS… |
Arguments after the script are forwarded untouched; --tool may appear before or
after the script.
shellcaasi native run scripts/collect.py --tool sim --headless --count 50
collecting 50 episodes...
wrote /home/robot/datasets/demo/metadata.json
exit code: 0
caasi native run scripts/tune.py --tool lab --task Isaac-Velocity-Flat-G1-v0
[INFO] Task: Isaac-Velocity-Flat-G1-v0
caasi native run scripts/lint_local.py
all checks passed
# --tool python is the default: plain Python, no Isaac env
caasi native run scripts/report.py --tool nope
Error: Unknown --tool 'nope' (expected sim, lab or python).
exit code: 1
Registering an explicit interpreter avoids launcher overhead and is the recommended setup for script-heavy workflows:
shellcaasi config set tools.isaacsim.python /opt/isaac-sim/python.sh
Set tools.isaacsim.python = /opt/isaac-sim/python.sh
caasi native run scripts/collect.py --tool sim
# now runs as: /opt/isaac-sim/python.sh scripts/collect.py
Exit codes
| Code | Meaning |
|---|---|
0 | the underlying tool succeeded |
1 | Caasi could not resolve a tool (Error: …), bad --tool, or the tool was killed by a signal |
| mirrored | the tool's own non-zero exit code (2, 3, 134, …) is returned as-is |
2 | Caasi usage error, e.g. missing SCRIPT argument |
That mirroring is what makes native commands safe in CI:
ci/run.sh#!/usr/bin/env bash
set -euo pipefail
caasi doctor || exit 1 # environment gate
caasi native run tests/smoke.py --tool sim # fails the build with the tool's own code
caasi sim run exps/ci.yaml && caasi run status latest --json | jq -e '.status == "succeeded"'
caasi shell
caasi shell [--command|-c TEXT] [--json]
Opens a bash session whose environment already knows about your Isaac installs —
or runs a single command in that environment and returns.
What the environment contains
build_shell_env() starts from your current environment and, for each of
isaacsim and isaaclab that resolves in the registry:
- exports
ISAACSIM_PATH/ISAACLAB_PATH= the install path; - prepends
<install>/bintoPATH, when that directory exists.
Tools that are not registered simply contribute nothing — the shell still opens.
caasi shell does not source setup.bash, setup_python_env.sh
or activate a conda env, and it does not set up ROS. For ROS use caasi native ros …
or the ros commands, which locate the distro themselves.
Interactive mode
Without --command, Caasi replaces its own process with bash
(os.execvpe). You get a normal, fully interactive shell with a TTY — so editors,
launchers with GUIs and progress bars all behave. Exiting the shell returns you to your
original shell; there is nothing left of the Caasi process to return to.
shellcaasi shell
robot@ws:~/work$ echo "$ISAACSIM_PATH"
/home/robot/.local/share/ov/pkg/isaac-sim-5.1.0
robot@ws:~/work$ command -v python.sh
/home/robot/.local/share/ov/pkg/isaac-sim-5.1.0/bin/python.sh
robot@ws:~/work$ exit
# back in your original shell — no caasi process involved
--command: one-shot mode
Runs bash -c TEXT inside that environment (no timeout), prints stdout then stderr,
and exits with the command's exit code (negative → 1). With --json you get
the whole result as one object and the exit code is still mirrored:
{ "returncode": 0, "stdout": "…", "stderr": "…" }
shellcaasi shell -c 'echo "$ISAACSIM_PATH"; echo "$ISAACLAB_PATH"'
/opt/isaac-sim
/opt/isaaclab
caasi shell -c './python.sh -c "import omni.kit.app; print(1)"'
1
caasi shell -c 'false'
exit code: 1
caasi shell -c 'python -c "import torch; print(torch.__version__, torch.cuda.is_available())"' --json
{ "returncode": 0, "stdout": "2.7.0+cu128 true\n", "stderr": "" }
caasi shell -c 'ls /nope' --json
{ "returncode": 2, "stdout": "", "stderr": "ls: cannot access '/nope': No such file or directory\n" }
exit code: 2
One-shot mode is the natural fit for scripting and CI, because the exit code propagates:
shellcaasi shell -c 'cd "$ISAACLAB_PATH" && ./isaaclab.sh -p scripts/list_tasks.py' | head -5
Isaac-Velocity-Flat-G1-v0
Isaac-Navigation-Flat-G1-v0
...
caasi --quiet shell -c 'echo hidden'
# --quiet suppresses the re-printed output; the exit code still propagates
Both native and shell --command re-print captured output through
Caasi's printer, which honours the global --quiet. Use --json (always
printed, even under --quiet) when a script needs the text.
Options
| Option | Default | Effect |
|---|---|---|
--command, -c | none | run this text via bash -c instead of opening a shell; exit code mirrored |
--json | false | one-shot mode only: print {returncode, stdout, stderr} |
native vs. shell vs. tracked runs
caasi native … | caasi shell | caasi sim run / train / ros launch | |
|---|---|---|---|
| Runs in | foreground | foreground (or replaces the process) | background, detached |
| Environment | exactly the tool's own launcher | ISAACSIM_PATH/ISAACLAB_PATH + bin on PATH | launcher env + your env: block + CAASI_* vars |
| Recorded | no | no | yes — run dir with manifest, run.sh, logs |
| Exit code | mirrored from the tool | mirrored (one-shot) / bash's (interactive) | the launch's; the run's outcome is checked later |
| Best for | verbatim tool invocations, CI gates | exploring, multi-step manual work | anything long, repeatable or worth keeping |