Skip to content

[Core] Start simulation runtimes through backend launchers named by the config (1/2) - #8068

Merged
ooctipus merged 9 commits into
isaac-sim:developfrom
ooctipus:octi/minimal-kit-lifecycle
Sep 28, 2026
Merged

ooctipus merged 9 commits into
isaac-sim:developfrom
ooctipus:octi/minimal-kit-lifecycle

Conversation

@ooctipus

@ooctipus ooctipus commented Sep 26, 2026 •

Copy link
Copy Markdown
Collaborator

Description

Part 1 of 2: the design. The migration of every script and test is in the stacked follow-up, #8090. This PR keeps existing scripts running unchanged, so the two halves can be reviewed separately.

launch_simulation now starts each simulation runtime through the launcher that the runtime's own backend package provides. The resolved config says which launcher is needed, so core never imports one.

# isaaclab.app: the interface every backend runtime implements
class SimulationLauncher:
    device: str | None = None                 # optional device the runtime picked
    def __init__(self, launcher_args): ...    # constructing it starts the runtime
    def close(self, exit_code: int = 0): ...  # stops it

# backend configs name their launcher, resolved lazily like ``class_type``
class PhysxCfg(PhysicsCfg):
    launcher_type: ClassVar[str] = "isaaclab_physx.app:KitLauncher"
class OVRTXRendererCfg(RendererCfg):
    launcher_type: ClassVar[str] = "isaaclab_ov.app:OvrtxLauncher"

launch_simulation(cfg, args) scans the resolved config as it already did and collects launcher_type from the physics and renderer config instances it resolved. It constructs each launcher once and closes them in reverse order when the block exits. Kit needs that no config names (require_kit, no physics config, a Kit visualizer requested only on the CLI) fall back to KitLauncher.

  • isaaclab_physx.app.KitLauncher is the old AppLauncher body, minus dead code:
    • removed: argument-collision bookkeeping, the Isaac Sim 5 branch, and the hidden --cpu flag;
    • moved in from launch_simulation: the Isaac Sim availability check and the "Kit already running" guard.
  • isaaclab_ov.app.OvrtxLauncher registers the OVRTX USD schemas, which launch_simulation used to do inline.
  • Moved into sim_launcher.py because kitless launches need them too: argv fusing, visualizer argument normalization, and the visualizer-settings sync (no longer wrapped in a blanket suppress(Exception)).

Kit stays in isaaclab_physx

Core code no longer imports carb, omni, or omni.replicator. Kit concerns go through one of two owners, and no new global hook is added.

  • The SimulationContext backend registry owns anything tied to a simulation's lifetime:
    • isaaclab_physx.app.KitStageBackend is registered through get_or_create_backend when Kit runs;
    • it attaches the stage to Kit's USD context and closes Kit's context stage when clear_instance() closes the other backends;
    • core stage utilities never touch Kit: clear_stage()/close_stage() are Kit-free, and Kit's own consumers (PhysX reset/step, RTX render, the Kit visualizer) run the app updates they need.
  • No defensive None handling on invariants: a SimulationContext always has a stage, so consumers read SimulationContext.instance().stage directly (SceneDataProvider.usd_stage / get_usd_stage are removed).
  • KitLauncher owns one-time process setup:
    • SettingsManager.set_backend(carb.settings), replacing initialize_carb_settings and is_omniverse_mode;
    • sharing Isaac Sim's stage-helper context;
    • one app update in close(), so scripts no longer need their own.
  • Replicator is enabled by the Isaac RTX renderer and seeded by the Replicator event terms that use it. The env classes no longer import it.
  • show_stage_in_viewport moves to isaaclab_physx.app, since it only works under Kit.
  • Gravity: tasks set it through PhysxManager.set_gravity instead of carb.Float3.

Exit handling

The ~110-line _SimulationAppLifecycle class from #6636 is gone. I measured a real Kit process with no handlers installed, and only two exit paths needed help. Both are now handled by two lines in KitLauncher:

  • An unhandled exception exits with 1. Kit's exit path reported 0.
  • SIGINT raises KeyboardInterrupt. Kit's own handler exited 0.

SIGTERM, SIGABRT, and SIGSEGV keep their default actions. Fixes #7774, supersedes #7775 and #6531.

Constructing runtime objects after launch

Importing pxr.Usd before Kit starts makes Kit fail to start. Scripts therefore import only config classes and construct runtime objects with instantiate(cfg) (#8085), which resolves the config's lazy class_type after the runtime is up.

  • ManagerBasedEnvCfg and ManagerBasedRLEnvCfg gain class_type.
  • The 21 task configs with a custom env class name it. A registry test checks that all 126 match their registered entry point.
  • Fixed: {DIR} in an inherited class_type resolved against the module of a subclass missing @configclass, so the call failed with ModuleNotFoundError.

Compatibility in this PR

isaaclab.app.AppLauncher is deprecated. It now starts Kit through launch_simulation, so develop's scripts and tests run unchanged here. It still offers is_available, has_gui, and has_window, which unmigrated scripts use. The migration PR moves every caller and reduces it to an init-only shim.

isaaclab.test.utils.launch_test_simulation(**launcher_args) starts Kit for a test module through launch_simulation. It picks the test device by default.

Behavior changes

  • Removed (breaking; each only restated an invariant or forwarded elsewhere):
    • sim_utils.update_stage: the simulation's reset, step, and render process stage changes;
    • sim_utils.is_current_stage_in_memory: compare against SimulationContext.instance().stage;
    • sim_utils.show_stage_in_viewport: use isaaclab_physx.app.show_stage_in_viewport;
    • SettingsManager.initialize_carb_settings (and the module-level function) and is_omniverse_mode: KitLauncher sets the settings backend, and has_kit() checks for Kit;
    • SceneDataProvider.usd_stage / get_usd_stage;
    • the hidden --cpu flag: use --device cpu.
  • Replicator seeding: the Replicator event terms seed it with env.cfg.seed when they are built; _get_replicator() only loads it. Calling env.seed(x) later no longer reseeds Replicator.
  • Kit startup marker is now [ISAACLAB] KitLauncher initialization complete, and tools/conftest.py is updated to match.
  • SIGTERM ends the process immediately, without a Kit teardown.
  • Warp environments: render_mode="rgb_array" now warns and returns None, matching the core environments.

Net: +2,326 / −3,045 across 154 files.

Type of change

  • Breaking change (AppLauncher deprecated; Kit-coupled helpers removed; Kit exit and seeding behavior changed)

Validation

All runs on the display GPU (GPU 0), with develop's scripts and tests unchanged unless listed here.

  • Launcher, app, and config tests:
    • isaaclab/test/app (26) and isaaclab_physx/test/app (88);
    • test_runtime_compatibility (27), visualizer intent (8), distributed device (13), test_preset_kit_decision (6), test_preset_cli (11);
    • test_configclass (37), test_sb3_leapp_export, and the CLI tests (234).
  • Kit tests through the deprecated adapter:
    • test_simulation_context (30), PhysX test_rigid_object (44), test_camera (21);
    • stage utils (15), stage in memory (3), test_events (4), texture randomization (2), test_manager_based_env (4).
  • Training: train.py --task Isaac-Cartpole --max_iterations 2 exits 0 with isaacsim_physx and newton_mjwarp.
    • physics=physx (kitless ovphysx) fails with an observation batch mismatch.
    • Develop 93b6e7432 fails the same way, so it is unrelated to this PR.
  • Every script under scripts/ and examples/, compared against develop with the same invocation:
    • Scripts outside the standalone matrix (78): same outcome on develop and here. 52 run, 19 are blocked by an external resource (datasets, XR, Ray, gr00t, robomimic, moviepy), and 7 fail identically on develop.
    • Standalone matrix (361 cases): no regressions. The only case that first looked new was an old-style script with --visualizer newton_rtx. Kit and OVRTX cannot share a process, so the adapter now skips that visualizer with a warning, as Kit did on develop.
    • Newton-based visualizers next to Kit PhysX: those cases fail on develop too, when Newton builds its model from USD.
  • After rebasing onto the latest develop: the state machines, bin_packing, and Cartpole training still run.
  • Known pre-existing failure: test_visualizer_integration_newton has a flat-frame check that fails identically on develop.
  • Pre-commit passes. The changelog check only flags fragments from other PRs, because it compares against the fork's stale develop.

Release backport

  • Backport this pull request to the active release branch after it merges into develop

Checklist

  • I have read and understood the contribution guidelines
  • I have run the pre-commit checks
  • I have made corresponding changes to the documentation (API pages for isaaclab.app, isaaclab_physx.app, isaaclab_ov.app)
  • My changes generate no new warnings
  • I have added changelog fragments for every touched package

@ooctipus
ooctipus requested a review from a team September 26, 2026 19:44
@github-actions github-actions Bot added documentation Improvements or additions to documentation isaac-lab Related to Isaac Lab team labels Sep 26, 2026

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isaac Lab Review Bot

The lifecycle policy is cleanly relocated and documented, but dropping exception suppression around SimulationApp.close() changes failure behavior during shutdown and can prevent SIGTERM from producing the documented signal-derived status.

  • Design and architecture: The closure-based installer retains the prior lifecycle structure without a demonstrated layering or dependency break. The new isaaclab_physx.app entry point is integrated through the package’s lazy-export pattern.
  • API: The new public function is exported and documented consistently, and the removed lifecycle class was private. However, the documented SIGTERM exit-status guarantee is not maintained when app.close() raises.
  • Implementation: The normal status values, handler disarming, and post-close signal re-raise follow the prior implementation. Unlike the replaced class, the new callbacks do not suppress exceptions from app.close(); on SIGTERM this skips signal.raise_signal(signum), allowing a traceback, exit 1, or caller interception instead of the intended signal termination. Restore exception suppression while ensuring the re-raise remains unconditional.

Minor fixes needed. Posted 1 actionable finding inline.

Automated review; human maintainers own approval decisions.


def on_sigterm(signum: int, frame) -> None:
signal.signal(signum, signal.SIG_DFL)
app.close(exit_code=128 + signum)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Suggestion · Implementation — Close failure now skips the SIGTERM re-raise

The replaced handler wrapped close() in contextlib.suppress(Exception) precisely so a teardown failure still reached signal.raise_signal(signum). Here an exception from app.close(exit_code=128 + signum) escapes the handler into the interrupted frame, so the process can report a traceback/exit 1 (or be swallowed by user code) instead of the documented 128+signum. Restore the suppression around both close calls, keeping the re-raise unconditional.

@greptile-apps

greptile-apps Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 3/5

[Medium risk] Refactors process lifecycle handling for the simulation app.

The PR is not ready to merge because standalone core imports can fail and SIGTERM teardown can miss its required termination path.

Findings

  1. P1 Optional backend becomes required ▶
  2. P1 Close errors interrupt SIGTERM shutdown ▶

Summary

The PR moves Kit exit handling from AppLauncher into a small isaaclab_physx.app function, stops overriding SIGABRT, and updates lifecycle tests and API documentation.

  • The new core-to-PhysX import conflicts with the packages’ optional-dependency boundary.
  • SIGTERM teardown no longer guarantees the intended exit path if closing raises.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Import AppLauncher] --> B{isaaclab_physx installed?}
    B -->|No| C[ModuleNotFoundError]
    B -->|Yes| D[Launch SimulationApp]
    D --> E[Install exit handlers]
    E --> F{Exit path}
    F -->|Normal exit| G[Close app with exit code]
    F -->|SIGTERM| H[Restore SIGTERM default]
    H --> I[Close app with signal status]
    I -->|Returns| J[Re-raise SIGTERM]
    I -->|Raises| K[Re-raise skipped]
Loading

Reviews (1) · Last reviewed commit: "Replace AppLauncher lifecycle class with..."

@@ -33,6 +30,8 @@

SimulationApp = getattr(isaacsim, "SimulationApp", None)

from isaaclab_physx.app import install_exit_handlers

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Optional backend becomes required If an installation contains isaaclab but not the optional isaaclab_physx package, importing AppLauncher now raises ModuleNotFoundError. The import happens before callers can use the launcher or its argument helpers, even though isaaclab does not declare a dependency on isaaclab_physx.

Knowledge Base Used: Physics backend extensions

Comment on lines +41 to +43
app.close(exit_code=128 + signum)
# close() only returns when fast shutdown is disabled
signal.raise_signal(signum)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Close errors interrupt SIGTERM shutdown If app.close() raises during SIGTERM teardown, the handler never reaches signal.raise_signal(signum). It has already restored the default signal action but does not send the signal again, so this path no longer guarantees termination with the intended signal status. The previous handler continued to re-raise SIGTERM after a close error.

@ooctipus
ooctipus force-pushed the octi/minimal-kit-lifecycle branch from fc1fb4f to 0e9a048 Compare September 26, 2026 22:29
@github-actions github-actions Bot added asset New asset feature or request isaac-mimic Related to Isaac Mimic team infrastructure labels Sep 26, 2026
@ooctipus ooctipus changed the title [Core] Replace AppLauncher lifecycle class with a minimal Kit exit policy in isaaclab_physx [Core] Move AppLauncher to isaaclab_physx and reduce exit handling to two lines Sep 26, 2026

@StafaH StafaH left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can keep the app launcher in isaaclab core, now that I see the import change across the whole codebase, everyone has to import isaaclab_physx which doesn't look good

@ooctipus

Copy link
Copy Markdown
Collaborator Author

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Sep 28, 2026
launch_simulation constructs the launcher each resolved config names in
launcher_type: KitLauncher (isaaclab_physx.app, the former AppLauncher body)
for Isaac Sim / Kit and OvrtxLauncher (isaaclab_ov.app) for OVRTX. Core stays
free of Kit: KitLauncher installs the carb settings backend, the application
runtime hook, and the Replicator seed hook once Kit is up. The exit lifecycle
class is replaced by two lines in KitLauncher.

Env configs gain class_type so scripts can construct runtime objects after the
runtime starts. AppLauncher is deprecated and starts Kit through
launch_simulation, so existing scripts keep running until they migrate.
Kit's USD-context work for a simulation is now a backend in the simulation's
registry: KitStageBackend attaches the stage on construction, runs app updates
for update_stage(), and closes Kit's context stage on teardown. Isaac Sim's
stage-helper context is shared once by KitLauncher, show_stage_in_viewport moves
to isaaclab_physx.app, and Replicator is seeded by the event terms that use it,
so the global runtime and seed hooks are gone.
launch_simulation collects launcher_type from the physics and renderer config
instances it resolves, with one Kit fallback for needs no config names. The
visualizer-settings sync moves into sim_launcher without a blanket suppress,
and wait_for_stage_load leaves until a caller needs it. APIs this PR had
removed or moved now warn and forward instead: is_current_stage_in_memory,
show_stage_in_viewport, initialize_carb_settings, and is_omniverse_mode; the
hidden --cpu flag raises the same error as on develop.
A SimulationContext always has a stage, so SceneDataProvider.usd_stage returns
it directly and the Kit visualizer drops its missing-stage check. Stage
utilities no longer reach into Kit: the Kit stage backend closes Kit's USD
context with the simulation, and Kit's own consumers run app updates, so
update_stage() is deprecated and clear_stage()/close_stage() stay Kit-free.
clear_instance() closes native backends newest first, so the lifecycle test
expects that order. The Kit-free render-settings test stubs enable_extension
with the rest of Kit, and test_pva no longer reads the adapter's private
_headless (it always launched headless).
The interface is a few lines and only launch_simulation uses it, so it lives in
sim_launcher.py instead of a separate, near-identically named module.
_get_replicator() only loads Replicator again; the two Replicator event terms
seed it with the environment seed where they draw from its random streams.
The stage utilities, settings manager, and scene data provider lose helpers
that only restated an invariant or forwarded elsewhere: update_stage,
is_current_stage_in_memory, the show_stage_in_viewport forwarder,
initialize_carb_settings, is_omniverse_mode, and SceneDataProvider.usd_stage /
get_usd_stage. Callers read SimulationContext.instance().stage directly. The
hidden --cpu flag is gone as well.
A script that keeps no reference to AppLauncher or its app let the launch
context be garbage-collected, which closed Kit mid-run (Kit startup test
crashed). The adapter now holds the runtime at module level. Add the missing
isaaclab_newton changelog fragment.
@ooctipus
ooctipus force-pushed the octi/minimal-kit-lifecycle branch from 9b99c3f to 599e4ba Compare September 28, 2026 02:45
@ooctipus

Copy link
Copy Markdown
Collaborator Author

run-ci

@isaaclab-bot isaaclab-bot Bot added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Sep 28, 2026
@ooctipus
ooctipus merged commit c9f9e22 into isaac-sim:develop Sep 28, 2026
54 checks passed
@ooctipus
ooctipus deleted the octi/minimal-kit-lifecycle branch September 28, 2026 03:15
@isaaclab-bot

isaaclab-bot Bot commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

Backported to release/3.0.0 as 75137de.

isaaclab-bot Bot pushed a commit that referenced this pull request Sep 28, 2026
…he config (1/2) (#8068)

## Description

**Part 1 of 2: the design.** The migration of every script and test is
in the stacked follow-up, #8090. This PR keeps existing scripts running
unchanged, so the two halves can be reviewed separately.

`launch_simulation` now starts each simulation runtime through the
launcher that the runtime's own backend package provides. The resolved
config says which launcher is needed, so core never imports one.

```python
# isaaclab.app: the interface every backend runtime implements
class SimulationLauncher:
    device: str | None = None                 # optional device the runtime picked
    def __init__(self, launcher_args): ...    # constructing it starts the runtime
    def close(self, exit_code: int = 0): ...  # stops it

# backend configs name their launcher, resolved lazily like ``class_type``
class PhysxCfg(PhysicsCfg):
    launcher_type: ClassVar[str] = "isaaclab_physx.app:KitLauncher"
class OVRTXRendererCfg(RendererCfg):
    launcher_type: ClassVar[str] = "isaaclab_ov.app:OvrtxLauncher"
```

`launch_simulation(cfg, args)` scans the resolved config as it already
did and collects `launcher_type` from the physics and renderer config
instances it resolved. It constructs each launcher once and closes them
in reverse order when the block exits. Kit needs that no config names
(`require_kit`, no physics config, a Kit visualizer requested only on
the CLI) fall back to `KitLauncher`.

- **`isaaclab_physx.app.KitLauncher`** is the old `AppLauncher` body,
minus dead code:
- removed: argument-collision bookkeeping, the Isaac Sim 5 branch, and
the hidden `--cpu` flag;
- moved in from `launch_simulation`: the Isaac Sim availability check
and the "Kit already running" guard.
- **`isaaclab_ov.app.OvrtxLauncher`** registers the OVRTX USD schemas,
which `launch_simulation` used to do inline.
- **Moved into `sim_launcher.py`** because kitless launches need them
too: argv fusing, visualizer argument normalization, and the
visualizer-settings sync (no longer wrapped in a blanket
`suppress(Exception)`).

### Kit stays in `isaaclab_physx`

Core code no longer imports `carb`, `omni`, or `omni.replicator`. Kit
concerns go through one of two owners, and no new global hook is added.

- **The `SimulationContext` backend registry** owns anything tied to a
simulation's lifetime:
- `isaaclab_physx.app.KitStageBackend` is registered through
`get_or_create_backend` when Kit runs;
- it attaches the stage to Kit's USD context and closes Kit's context
stage when `clear_instance()` closes the other backends;
- core stage utilities never touch Kit: `clear_stage()`/`close_stage()`
are Kit-free, and Kit's own consumers (PhysX reset/step, RTX render, the
Kit visualizer) run the app updates they need.
- **No defensive `None` handling on invariants:** a `SimulationContext`
always has a stage, so consumers read
`SimulationContext.instance().stage` directly
(`SceneDataProvider.usd_stage` / `get_usd_stage` are removed).
- **`KitLauncher`** owns one-time process setup:
- `SettingsManager.set_backend(carb.settings)`, replacing
`initialize_carb_settings` and `is_omniverse_mode`;
  - sharing Isaac Sim's stage-helper context;
  - one app update in `close()`, so scripts no longer need their own.
- **Replicator** is enabled by the Isaac RTX renderer and seeded by the
Replicator event terms that use it. The env classes no longer import it.
- **`show_stage_in_viewport`** moves to `isaaclab_physx.app`, since it
only works under Kit.
- **Gravity:** tasks set it through `PhysxManager.set_gravity` instead
of `carb.Float3`.

### Exit handling

The ~110-line `_SimulationAppLifecycle` class from #6636 is gone. I
measured a real Kit process with no handlers installed, and only two
exit paths needed help. Both are now handled by two lines in
`KitLauncher`:

- An unhandled exception exits with 1. Kit's exit path reported 0.
- `SIGINT` raises `KeyboardInterrupt`. Kit's own handler exited 0.

`SIGTERM`, `SIGABRT`, and `SIGSEGV` keep their default actions. Fixes
#7774, supersedes #7775 and #6531.

### Constructing runtime objects after launch

Importing `pxr.Usd` before Kit starts makes Kit fail to start. Scripts
therefore import only config classes and construct runtime objects with
`instantiate(cfg)` (#8085), which resolves the config's lazy
`class_type` after the runtime is up.

- `ManagerBasedEnvCfg` and `ManagerBasedRLEnvCfg` gain `class_type`.
- The 21 task configs with a custom env class name it. A registry test
checks that all 126 match their registered entry point.
- **Fixed:** `{DIR}` in an inherited `class_type` resolved against the
module of a subclass missing `@configclass`, so the call failed with
`ModuleNotFoundError`.

### Compatibility in this PR

`isaaclab.app.AppLauncher` is deprecated. It now starts Kit through
`launch_simulation`, so develop's scripts and tests run unchanged here.
It still offers `is_available`, `has_gui`, and `has_window`, which
unmigrated scripts use. The migration PR moves every caller and reduces
it to an init-only shim.

`isaaclab.test.utils.launch_test_simulation(**launcher_args)` starts Kit
for a test module through `launch_simulation`. It picks the test device
by default.

### Behavior changes

- **Removed** (breaking; each only restated an invariant or forwarded
elsewhere):
- `sim_utils.update_stage`: the simulation's reset, step, and render
process stage changes;
- `sim_utils.is_current_stage_in_memory`: compare against
`SimulationContext.instance().stage`;
- `sim_utils.show_stage_in_viewport`: use
`isaaclab_physx.app.show_stage_in_viewport`;
- `SettingsManager.initialize_carb_settings` (and the module-level
function) and `is_omniverse_mode`: `KitLauncher` sets the settings
backend, and `has_kit()` checks for Kit;
  - `SceneDataProvider.usd_stage` / `get_usd_stage`;
  - the hidden `--cpu` flag: use `--device cpu`.
- **Replicator seeding:** the Replicator event terms seed it with
`env.cfg.seed` when they are built; `_get_replicator()` only loads it.
Calling `env.seed(x)` later no longer reseeds Replicator.
- **Kit startup marker** is now `[ISAACLAB] KitLauncher initialization
complete`, and `tools/conftest.py` is updated to match.
- **SIGTERM** ends the process immediately, without a Kit teardown.
- **Warp environments:** `render_mode="rgb_array"` now warns and returns
`None`, matching the core environments.

Net: +2,326 / −3,045 across 154 files.

## Type of change

- Breaking change (`AppLauncher` deprecated; Kit-coupled helpers
removed; Kit exit and seeding behavior changed)

## Validation

All runs on the display GPU (GPU 0), with develop's scripts and tests
unchanged unless listed here.

- **Launcher, app, and config tests:**
  - `isaaclab/test/app` (26) and `isaaclab_physx/test/app` (88);
- `test_runtime_compatibility` (27), visualizer intent (8), distributed
device (13), `test_preset_kit_decision` (6), `test_preset_cli` (11);
- `test_configclass` (37), `test_sb3_leapp_export`, and the CLI tests
(234).
- **Kit tests through the deprecated adapter:**
- `test_simulation_context` (30), PhysX `test_rigid_object` (44),
`test_camera` (21);
- stage utils (15), stage in memory (3), `test_events` (4), texture
randomization (2), `test_manager_based_env` (4).
- **Training:** `train.py --task Isaac-Cartpole --max_iterations 2`
exits 0 with `isaacsim_physx` and `newton_mjwarp`.
- `physics=physx` (kitless ovphysx) fails with an observation batch
mismatch.
- Develop `93b6e7432` fails the same way, so it is unrelated to this PR.
- **Every script under `scripts/` and `examples/`**, compared against
develop with the same invocation:
- **Scripts outside the standalone matrix (78):** same outcome on
develop and here. 52 run, 19 are blocked by an external resource
(datasets, XR, Ray, gr00t, robomimic, moviepy), and 7 fail identically
on develop.
- **Standalone matrix (361 cases):** no regressions. The only case that
first looked new was an old-style script with `--visualizer newton_rtx`.
Kit and OVRTX cannot share a process, so the adapter now skips that
visualizer with a warning, as Kit did on develop.
- **Newton-based visualizers next to Kit PhysX:** those cases fail on
develop too, when Newton builds its model from USD.
- **After rebasing onto the latest develop:** the state machines,
`bin_packing`, and Cartpole training still run.
- **Known pre-existing failure:** `test_visualizer_integration_newton`
has a flat-frame check that fails identically on develop.
- Pre-commit passes. The changelog check only flags fragments from other
PRs, because it compares against the fork's stale `develop`.

## Release backport

- [x] <!-- backport-active-release --> Backport this pull request to the
active release branch after it merges into `develop`

## Checklist

- [x] I have read and understood the contribution guidelines
- [x] I have run the pre-commit checks
- [x] I have made corresponding changes to the documentation (API pages
for `isaaclab.app`, `isaaclab_physx.app`, `isaaclab_ov.app`)
- [x] My changes generate no new warnings
- [x] I have added changelog fragments for every touched package

(cherry picked from commit c9f9e22)
ooctipus added a commit that referenced this pull request Sep 28, 2026
…mulation (3/3) (#8102)

## Description

**Part 3 of 3.** #8068 (merged) added the launcher design, and #8090
moves the scripts onto it. This PR does the same for the tests. It is
independent of #8090, so they can merge in either order.

### What changes

- **One-line launch:** test modules start the runtime with a single
`launch_test_simulation(...)` call. It replaces the `"""Launch Isaac Sim
Simulator first."""` preamble in about 125 modules.
- **`launch_test_simulation(cfg=None, **launcher_args)` is
config-driven.** It starts whatever runtime the test's simulation config
needs (the default `SimulationCfg()` when none is given) instead of
forcing Kit, and it returns `None`. It still picks the test device from
the multi-GPU mask by default. Every existing test gets the same runtime
as before, because the default config uses PhysX, which starts Kit; the
config makes that choice now, not the helper.
- **Core `isaaclab` tests no longer import `omni`, `carb`, or
`isaacsim`:**
- camera tests rely on the simulation's own cleanup instead of
Replicator's `destroy_hydra_textures`;
- tests that check Kit, PhysX, or Isaac Sim behavior move to
`isaaclab_physx`: the Isaac Sim `XformPrim` comparison, the Kit timeline
and app-update tests, stage-in-memory, the UI window, Kit startup
performance, and three Isaac Sim extension-path tests. No coverage is
deleted.
- **Tests that need the Kit app object** get it from `omni.kit.app` in
their own package: Newton fabric sync, teleop XR, and the visualizer
tests.

The remaining Kit mentions in core tests are the `isaacsim_ci` CI
markers, the `install_ci` installer checks, `omni.client`, and tests
that stub `omni` to exercise core code's own Kit branches without
starting Kit.

Net: +856 / −1,260 across 169 files.

## Type of change

- Breaking change (`launch_test_simulation` signature and return value)

## Validation

All runs on the display GPU (GPU 0).

- **Every changed or moved module passes,** including the app tests
(43), simulation context (26), the moved Kit context tests (4), camera
(21), Newton fabric sync (9), views, controllers, the other camera
tests, pink IK, and teleop XR.
- **Visualizer tests:** the integration and golden-image tests fail on
this machine exactly as they do without this PR (a known flat-frame
issue); CI is the check for those.

## Release backport

- [x] <!-- backport-active-release --> Backport this pull request to the
active release branch after it merges into `develop`

## Checklist

- [x] I have read and understood the contribution guidelines
- [x] I have run the pre-commit checks
- [x] My changes generate no new warnings
- [x] I have added changelog fragments for every touched package
isaaclab-bot Bot pushed a commit that referenced this pull request Sep 28, 2026
…mulation (3/3) (#8102)

## Description

**Part 3 of 3.** #8068 (merged) added the launcher design, and #8090
moves the scripts onto it. This PR does the same for the tests. It is
independent of #8090, so they can merge in either order.

### What changes

- **One-line launch:** test modules start the runtime with a single
`launch_test_simulation(...)` call. It replaces the `"""Launch Isaac Sim
Simulator first."""` preamble in about 125 modules.
- **`launch_test_simulation(cfg=None, **launcher_args)` is
config-driven.** It starts whatever runtime the test's simulation config
needs (the default `SimulationCfg()` when none is given) instead of
forcing Kit, and it returns `None`. It still picks the test device from
the multi-GPU mask by default. Every existing test gets the same runtime
as before, because the default config uses PhysX, which starts Kit; the
config makes that choice now, not the helper.
- **Core `isaaclab` tests no longer import `omni`, `carb`, or
`isaacsim`:**
- camera tests rely on the simulation's own cleanup instead of
Replicator's `destroy_hydra_textures`;
- tests that check Kit, PhysX, or Isaac Sim behavior move to
`isaaclab_physx`: the Isaac Sim `XformPrim` comparison, the Kit timeline
and app-update tests, stage-in-memory, the UI window, Kit startup
performance, and three Isaac Sim extension-path tests. No coverage is
deleted.
- **Tests that need the Kit app object** get it from `omni.kit.app` in
their own package: Newton fabric sync, teleop XR, and the visualizer
tests.

The remaining Kit mentions in core tests are the `isaacsim_ci` CI
markers, the `install_ci` installer checks, `omni.client`, and tests
that stub `omni` to exercise core code's own Kit branches without
starting Kit.

Net: +856 / −1,260 across 169 files.

## Type of change

- Breaking change (`launch_test_simulation` signature and return value)

## Validation

All runs on the display GPU (GPU 0).

- **Every changed or moved module passes,** including the app tests
(43), simulation context (26), the moved Kit context tests (4), camera
(21), Newton fabric sync (9), views, controllers, the other camera
tests, pink IK, and teleop XR.
- **Visualizer tests:** the integration and golden-image tests fail on
this machine exactly as they do without this PR (a known flat-frame
issue); CI is the check for those.

## Release backport

- [x] <!-- backport-active-release --> Backport this pull request to the
active release branch after it merges into `develop`

## Checklist

- [x] I have read and understood the contribution guidelines
- [x] I have run the pre-commit checks
- [x] My changes generate no new warnings
- [x] I have added changelog fragments for every touched package

(cherry picked from commit c7775bc)
ooctipus added a commit that referenced this pull request Sep 28, 2026
…8090)

## Description

**Part 2 of 3.** #8068 (merged) added the launcher design; this PR moves
every script, example, tutorial, benchmark, and doc page onto it. The
tests are in #8102. The two PRs are independent and can merge in either
order.

```python
from isaaclab.app import add_launcher_args, launch_simulation
from isaaclab.utils import instantiate

add_launcher_args(parser)
args_cli = parser.parse_args()
...
with launch_simulation(env_cfg, args_cli):   # the runtime follows the config
    env = instantiate(env_cfg)
```

### What changes

- **Every script, example, tutorial, and benchmark** starts the runtime
with `launch_simulation` and builds runtime objects with `instantiate`
(#8085). Nothing outside the shim below uses `AppLauncher` any more.
- **Kit calls leave the scripts:**
- the teleop, record, and replay scripts no longer load Replicator or
update the app after closing the env;
- `pick_and_place.py` uses `Se3Keyboard` instead of raw `carb.input`
(W/S/A/D move, Q/E height, K gripper, N/M aim). On develop it died
before stepping;
- the camera tutorials save PNGs with `save_images_to_file` instead of
Replicator writers.
- **The converter tools** (`convert_mesh`, `convert_urdf`,
`convert_mjcf`) preview the converted asset in the visualizer chosen
with `--viz`, Kit included, instead of a Kit-only viewport.
`isaaclab_physx.app.show_stage_in_viewport` has no callers left and is
removed.
- **The 14 `check_*` scripts** under the core and PhysX test folders,
which duplicated pytest coverage, are deleted.
- **`AppLauncher` shrinks to an init-only shim**, so scripts written
against the old API keep running:
- `AppLauncher.add_app_launcher_args(parser)` adds the launcher
arguments;
- `AppLauncher(args).app` starts Kit through `launch_simulation`, and
`app.close()` stops it;
  - `is_available`, `has_gui`, `has_window`, and `device` are removed.

The runtime is held for the process, so a script that drops the launcher
keeps Kit running. `test_app_launcher_shim.py` covers both a kept and a
dropped launcher; the dropped case fails without the fix.
- **Moved with their scripts:** the two converter tests and the
replay-loop test, which read script code, and `wait_for_stage_load`,
used by the teleop replay script.

Net: +2,367 / −4,334 across 121 files.

## Type of change

- Breaking change (`AppLauncher` reduced to a shim)

## Validation

All runs on the display GPU (GPU 0).

- **Every script under `scripts/` and `examples/`** was run on develop
and with these changes, using the same invocation. No script that runs
on develop fails here.
- Of the 78 scripts outside the standalone matrix, 52 run, 19 are
blocked by the same missing resource on both (datasets, XR, a Ray
cluster, gr00t, robomimic, moviepy), and 7 fail the same way on both.
  - The standalone matrix (361 cases) shows no new failures.
- **Converter tools:** each writes its USD. `--viz kit` and `--viz
newton_gl` keep rendering the asset until the window closes.
- **Tests:** the shim test (2), URDF converter (17), replay loop (1),
and RTX utils (10) pass.
- **Training:** Cartpole on `isaacsim_physx` runs 2 iterations.

## Release backport

- [x] <!-- backport-active-release --> Backport this pull request to the
active release branch after it merges into `develop`

## Checklist

- [x] I have read and understood the contribution guidelines
- [x] I have run the pre-commit checks
- [x] I have made corresponding changes to the documentation (tutorials
and how-to guides)
- [x] My changes generate no new warnings
- [x] I have added changelog fragments for every touched package
isaaclab-bot Bot pushed a commit that referenced this pull request Sep 28, 2026
…8090)

## Description

**Part 2 of 3.** #8068 (merged) added the launcher design; this PR moves
every script, example, tutorial, benchmark, and doc page onto it. The
tests are in #8102. The two PRs are independent and can merge in either
order.

```python
from isaaclab.app import add_launcher_args, launch_simulation
from isaaclab.utils import instantiate

add_launcher_args(parser)
args_cli = parser.parse_args()
...
with launch_simulation(env_cfg, args_cli):   # the runtime follows the config
    env = instantiate(env_cfg)
```

### What changes

- **Every script, example, tutorial, and benchmark** starts the runtime
with `launch_simulation` and builds runtime objects with `instantiate`
(#8085). Nothing outside the shim below uses `AppLauncher` any more.
- **Kit calls leave the scripts:**
- the teleop, record, and replay scripts no longer load Replicator or
update the app after closing the env;
- `pick_and_place.py` uses `Se3Keyboard` instead of raw `carb.input`
(W/S/A/D move, Q/E height, K gripper, N/M aim). On develop it died
before stepping;
- the camera tutorials save PNGs with `save_images_to_file` instead of
Replicator writers.
- **The converter tools** (`convert_mesh`, `convert_urdf`,
`convert_mjcf`) preview the converted asset in the visualizer chosen
with `--viz`, Kit included, instead of a Kit-only viewport.
`isaaclab_physx.app.show_stage_in_viewport` has no callers left and is
removed.
- **The 14 `check_*` scripts** under the core and PhysX test folders,
which duplicated pytest coverage, are deleted.
- **`AppLauncher` shrinks to an init-only shim**, so scripts written
against the old API keep running:
- `AppLauncher.add_app_launcher_args(parser)` adds the launcher
arguments;
- `AppLauncher(args).app` starts Kit through `launch_simulation`, and
`app.close()` stops it;
  - `is_available`, `has_gui`, `has_window`, and `device` are removed.

The runtime is held for the process, so a script that drops the launcher
keeps Kit running. `test_app_launcher_shim.py` covers both a kept and a
dropped launcher; the dropped case fails without the fix.
- **Moved with their scripts:** the two converter tests and the
replay-loop test, which read script code, and `wait_for_stage_load`,
used by the teleop replay script.

Net: +2,367 / −4,334 across 121 files.

## Type of change

- Breaking change (`AppLauncher` reduced to a shim)

## Validation

All runs on the display GPU (GPU 0).

- **Every script under `scripts/` and `examples/`** was run on develop
and with these changes, using the same invocation. No script that runs
on develop fails here.
- Of the 78 scripts outside the standalone matrix, 52 run, 19 are
blocked by the same missing resource on both (datasets, XR, a Ray
cluster, gr00t, robomimic, moviepy), and 7 fail the same way on both.
  - The standalone matrix (361 cases) shows no new failures.
- **Converter tools:** each writes its USD. `--viz kit` and `--viz
newton_gl` keep rendering the asset until the window closes.
- **Tests:** the shim test (2), URDF converter (17), replay loop (1),
and RTX utils (10) pass.
- **Training:** Cartpole on `isaacsim_physx` runs 2 iterations.

## Release backport

- [x] <!-- backport-active-release --> Backport this pull request to the
active release branch after it merges into `develop`

## Checklist

- [x] I have read and understood the contribution guidelines
- [x] I have run the pre-commit checks
- [x] I have made corresponding changes to the documentation (tutorials
and how-to guides)
- [x] My changes generate no new warnings
- [x] I have added changelog fragments for every touched package

(cherry picked from commit 443dc47)
ooctipus added a commit that referenced this pull request Sep 29, 2026
## Description

A follow-up to #8068, #8090, and #8102: it inlines or removes
launch-stack helpers whose names cost the reader more than their bodies
do. This PR is pure cleanup with no behavior change; every public
removal is listed below with its replacement.

### Launcher (`isaaclab.app.sim_launcher`)

- **Arguments become a dict once.** `launch_simulation` and `scan`
convert launcher args with `vars(args_cli)`, the namespace's live
`__dict__`, so values resolved at launch (for example
`args_cli.headless`) still reach the caller. That removes `_get_arg` /
`_set_arg` and their three-way Namespace/dict/None branching on every
read.
- **Resolved once instead of twice:**
- the livestream mode is resolved during argument normalization and read
back afterwards;
- the "explicit `--viz` overrides the config" rule for the Kit
visualizer is part of the scan's visualizer intent.
- **Inlined:** the logging-level resolver (now private here), the
one-line `_is_*` config predicates, and the Kit-source list formatter.
- **`make_physics_cfg` is private** (`_make_physics_cfg`); only `scan`
used it.

### Settings (`isaaclab.app.settings_manager`)

- **One accessor:** `SettingsManager.instance()` is removed. It was
identical to `get_settings_manager()`.
- **One setter:** `set_bool` / `set_int` / `set_float` / `set_string`
are removed. They only called `set()`, which already dispatches on the
value's type. Only calls on Isaac Lab's settings manager changed; calls
on carb's settings interface are untouched.

### Kit launcher (`isaaclab_physx.app.KitLauncher`)

- **Inlined:** three single-use helpers (spectator-view check,
experience dependency check, deferred CUDA device).
- **Merged:** the stop-button and play-button toolbar helpers become one
`_set_toolbar_button_visible`, with each button's current behavior kept.
- **Renamed:** `add_app_launcher_args` → `add_launcher_args`, and
`ExplicitAction` → `_ExplicitAction` (internal).

Net: +239 / −405 (about −165 lines).

## Type of change

- Breaking change (removed `SettingsManager.instance`, the typed
`SettingsManager.set_*` forwarders, and `isaaclab.app.make_physics_cfg`;
renamed `KitLauncher.add_app_launcher_args`)

## Validation

All runs on GPU 0.

- **Launcher and runtime tests:**
- Kit launcher (84), visualizer intent (8), distributed device
resolution (11), runtime compatibility (27), `require_kit` (10);
- preset Kit decision (6), preset CLI (11), RL entrypoints (44), CLI
tests (234);
- app tests, including the `AppLauncher` shim, exit status, and Kit
startup;
- simulation context (26), Isaac RTX renderer contract (26), and the
changed contact-sensor and OvPhysX scene-data tests.
- **`test_simulation_context_visualizers`:** 44 passed, 1 failed. The
failing test needs `carb`, which only CI's image has, and it fails
identically on develop.
- **Training:** Cartpole runs 2 iterations with `isaacsim_physx` (Kit
starts) and with `newton_mjwarp` (no Kit).
- **Tutorial:** `create_empty.py` reaches setup and runs.
- **Not run:** the toolbar-button and livestream `isaacsim.exp.full`
paths need a GUI or a livestream.
- **Removed test:**
`test_deferred_cuda_device_synchronizes_torch_and_warp`. Its helper is
now inlined into Kit-only startup code.

## Release backport

- [x] <!-- backport-active-release --> Backport this pull request to the
active release branch after it merges into `develop`

## Checklist

- [x] I have read and understood the contribution guidelines
- [x] I have run the pre-commit checks
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added changelog fragments for every touched package
isaaclab-bot Bot pushed a commit that referenced this pull request Sep 29, 2026
## Description

A follow-up to #8068, #8090, and #8102: it inlines or removes
launch-stack helpers whose names cost the reader more than their bodies
do. This PR is pure cleanup with no behavior change; every public
removal is listed below with its replacement.

### Launcher (`isaaclab.app.sim_launcher`)

- **Arguments become a dict once.** `launch_simulation` and `scan`
convert launcher args with `vars(args_cli)`, the namespace's live
`__dict__`, so values resolved at launch (for example
`args_cli.headless`) still reach the caller. That removes `_get_arg` /
`_set_arg` and their three-way Namespace/dict/None branching on every
read.
- **Resolved once instead of twice:**
- the livestream mode is resolved during argument normalization and read
back afterwards;
- the "explicit `--viz` overrides the config" rule for the Kit
visualizer is part of the scan's visualizer intent.
- **Inlined:** the logging-level resolver (now private here), the
one-line `_is_*` config predicates, and the Kit-source list formatter.
- **`make_physics_cfg` is private** (`_make_physics_cfg`); only `scan`
used it.

### Settings (`isaaclab.app.settings_manager`)

- **One accessor:** `SettingsManager.instance()` is removed. It was
identical to `get_settings_manager()`.
- **One setter:** `set_bool` / `set_int` / `set_float` / `set_string`
are removed. They only called `set()`, which already dispatches on the
value's type. Only calls on Isaac Lab's settings manager changed; calls
on carb's settings interface are untouched.

### Kit launcher (`isaaclab_physx.app.KitLauncher`)

- **Inlined:** three single-use helpers (spectator-view check,
experience dependency check, deferred CUDA device).
- **Merged:** the stop-button and play-button toolbar helpers become one
`_set_toolbar_button_visible`, with each button's current behavior kept.
- **Renamed:** `add_app_launcher_args` → `add_launcher_args`, and
`ExplicitAction` → `_ExplicitAction` (internal).

Net: +239 / −405 (about −165 lines).

## Type of change

- Breaking change (removed `SettingsManager.instance`, the typed
`SettingsManager.set_*` forwarders, and `isaaclab.app.make_physics_cfg`;
renamed `KitLauncher.add_app_launcher_args`)

## Validation

All runs on GPU 0.

- **Launcher and runtime tests:**
- Kit launcher (84), visualizer intent (8), distributed device
resolution (11), runtime compatibility (27), `require_kit` (10);
- preset Kit decision (6), preset CLI (11), RL entrypoints (44), CLI
tests (234);
- app tests, including the `AppLauncher` shim, exit status, and Kit
startup;
- simulation context (26), Isaac RTX renderer contract (26), and the
changed contact-sensor and OvPhysX scene-data tests.
- **`test_simulation_context_visualizers`:** 44 passed, 1 failed. The
failing test needs `carb`, which only CI's image has, and it fails
identically on develop.
- **Training:** Cartpole runs 2 iterations with `isaacsim_physx` (Kit
starts) and with `newton_mjwarp` (no Kit).
- **Tutorial:** `create_empty.py` reaches setup and runs.
- **Not run:** the toolbar-button and livestream `isaacsim.exp.full`
paths need a GUI or a livestream.
- **Removed test:**
`test_deferred_cuda_device_synchronizes_torch_and_warp`. Its helper is
now inlined into Kit-only startup code.

## Release backport

- [x] <!-- backport-active-release --> Backport this pull request to the
active release branch after it merges into `develop`

## Checklist

- [x] I have read and understood the contribution guidelines
- [x] I have run the pre-commit checks
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added changelog fragments for every touched package

(cherry picked from commit 24e1b46)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

asset New asset feature or request documentation Improvements or additions to documentation infrastructure isaac-lab Related to Isaac Lab team isaac-mimic Related to Isaac Mimic team isaac-sim Related to Isaac Sim team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug Report] AppLauncher's Python SIGSEGV handler turns any segfault into an unkillable infinite fault loop with no core dump

2 participants