Project Migration Audit#

Before editing code, run an inventory over the project. Isaac Sim 6.0 introduces changes in the following areas:

  • Extension names

  • Python APIs

  • Saved Action Graph inputs

  • ROS workspace package layout

  • Sensor timing behavior

  • Robot import/export APIs

  • Benchmark recorders

  • No-replacement tools

A static audit does not prove that the migration is complete, but it identifies the workflows that need runtime validation.

Audit Scope#

Include all project-owned files that can reference Isaac Sim behavior:

  • App .kit files and extension extension.toml files

  • Python scripts, tests, notebooks converted to scripts, benchmark entry points, and continuous integration (CI) smoke tests

  • Universal Scene Description (USD) and USDA stages that contain saved Action Graphs

  • ROS 2 launch files, package manifests, setup.py files, and CMakeLists.txt files in downstream workspaces

  • Robot assets and import scripts that use URDF, MJCF, mesh merge, or robot setup tools

  • Synthetic data and sensor configs, including MobilityGen recordings, RTX Lidar JSON configs, Replicator writers, and benchmark scripts

Static Audit Helper#

Use the helper from the Isaac Sim source repository (source/tools/isaac_sim_migration). It scans a project root for patterns that usually require manual 6.0 migration review.

Note

The Isaac Sim source repository also includes an agent-facing migration skill at skills/isaac-sim-migration/SKILL.md. The skill is part of the source checkout, not the installed Isaac Sim package. If you work from a source checkout and use an agent that supports SKILL.md workflows, load that skill before running this audit. The skill is aware of this script and gives the agent a concise workflow for running it, triaging findings, and planning follow-up runtime validation.

Note

This helper is not a complete migration analyzer. It can miss Isaac Sim usage hidden behind project wrappers, generated files, binary USD layers, dynamic imports, custom OmniGraph nodes, extension settings, or behavior that only appears at runtime. Treat a clean report as a starting point for manual review and runtime validation, not as proof that the project is fully migrated.

# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""Static inventory helper for Isaac Sim 6.0 migration planning.

Run this script against a project checkout before editing code. It reports
imports, extension dependencies, saved graph tokens, ROS workspace files, and
benchmark patterns that usually need manual migration review.

This script is not a complete migration analyzer. It can miss project wrappers,
generated files, binary USD layers, dynamic imports, custom OmniGraph nodes,
extension settings, and behavior that only appears at runtime.

By default, findings are reported as migration inventory and the script exits
successfully. Use ``--fail-on required`` or ``--fail-on any`` only when a CI
job intentionally gates on unresolved migration findings.
"""

from __future__ import annotations

import argparse
import json
import re
from dataclasses import asdict, dataclass
from pathlib import Path
from typing import Iterable

SKIP_DIRS = {
    ".git",
    ".hg",
    ".mypy_cache",
    ".ruff_cache",
    ".svn",
    ".venv",
    "__pycache__",
    "_build",
    "build",
    "dist",
    "install",
    "node_modules",
}

TEXT_SUFFIXES = {
    ".cfg",
    ".ini",
    ".json",
    ".kit",
    ".md",
    ".ogn",
    ".py",
    ".rst",
    ".toml",
    ".usda",
    ".usd",
    ".xml",
    ".yaml",
    ".yml",
}


@dataclass(frozen=True)
class Rule:
    category: str
    pattern: str
    message: str
    guide: str
    severity: str = "review"
    file_patterns: tuple[str, ...] = ()


@dataclass(frozen=True)
class Finding:
    file: str
    line: int
    category: str
    severity: str
    match: str
    message: str
    guide: str


RULES = [
    Rule(
        "Extension namespace",
        r"\bomni\.isaac\.[A-Za-z0-9_.]*",
        "Migrate old omni.isaac extension names and imports to isaacsim names before applying the 6.0 guides.",
        "isaac_sim_4_5/extensions_renaming",
        "required",
    ),
    Rule(
        "Python runtime",
        r"\b(python_requires|requires-python|python3\.11|Python 3\.11|cp311|py311|3\.11\.13)\b",
        "Review Python runtime pins and rebuild project environments, compiled wheels, ROS Python packages, and ML dependencies for Isaac Sim 6.0's Python 3.12 runtime.",
        "isaac_sim_6_0/migration_strategy",
    ),
    Rule(
        "Core API",
        r"\bisaacsim\.core\.(api|prims|utils)\b",
        "Move Core API, prim wrappers, and utilities to isaacsim.core.experimental.* or explicit managers.",
        "isaac_sim_6_0/core_api_to_core_experimental",
        "required",
    ),
    Rule(
        "Sensor API",
        r"\bisaacsim\.sensors\.(camera|rtx|physics|physx)\b",
        "Review sensor package migration, including RTX sensor authoring, physics sensors, and OmniGraph node namespaces.",
        "isaac_sim_6_0/sensors_camera_to_experimental_rtx",
        "required",
    ),
    Rule(
        "Camera prim RTX lidar",
        r"\b(RtxLidar|IsaacRtxLidarSensorAPI|lidar_config|json_config|config_file_name|Camera[^\n]{0,80}RTX|RTX[^\n]{0,80}Camera|OmniSensorGenericLidarCoreAPI)\b",
        "If this file configures RTX lidar assets, verify Camera-prim JSON sensors were converted to OmniSensor/OmniLidar assets.",
        "isaac_sim_6_0/sensor_timing_and_rtx_lidar_asset_migration",
    ),
    Rule(
        "RTX lidar tool path",
        r"\bsource/tools/isaacsim\.sensors\.rtx\b|convert_lidar_json_to_usda\.py|set_lidar_tick_rates\.py",
        "Use the packaged 6.0 lidar conversion tools under tools/isaacsim.sensors.rtx and validate converted OmniSensor/OmniLidar assets.",
        "isaac_sim_6_0/sensor_timing_and_rtx_lidar_asset_migration",
    ),
    Rule(
        "PhysX raycast sensor",
        r"\b(_range_sensor|get_linear_depth_data|get_point_cloud_data|get_prim_data|send_next_batch|set_next_batch_rays|sensor_pattern|origin_offsets|rotationRate|curtainLength|curtainAxis|numRays|forwardAxis)\b",
        "Migrate deprecated PhysX generic, lidar, or lightbeam raycast sensors to isaacsim.sensors.experimental.physics.RaycastSensor.",
        "isaac_sim_6_0/sensors_physx_lidar_to_physics_raycast",
        "required",
    ),
    Rule(
        "ROS 2 publisher graph",
        r"\b(ROS2PublishTransformTree|ROS2PublishJointState|ROS2PublishOdometry|IsaacComputeOdometry)\b",
        "Audit saved Action Graphs for deprecated prim-resolving ROS 2 publisher inputs.",
        "isaac_sim_6_0/ros2_omnigraph_migration",
        "required",
    ),
    Rule(
        "ROS 2 publisher graph prim inputs",
        r"\b(targetPrim|targetPrims)\b",
        "Review saved USD Action Graphs for deprecated prim-resolving ROS 2 publisher inputs.",
        "isaac_sim_6_0/ros2_omnigraph_migration",
        "review",
        ("*.usd", "*.usda"),
    ),
    Rule(
        "ROS 2 sensor graph",
        r"\b(frameSkipCount|fullScan|outputNormal|outputIntensity|outputTimestamp|outputObjectId)\b",
        "Review ROS 2 sensor helper, point-cloud, and metadata-output migration.",
        "isaac_sim_6_0/ros2_sensor_graph_migration",
        "required",
    ),
    Rule(
        "Multitick timing",
        r"\bomni:sensor:tickRate\b",
        "Review multitick and external simulation time ownership; sensor tick timing changed in 6.0.",
        "isaac_sim_6_0/sensor_timing_and_rtx_lidar_asset_migration",
        "review",
    ),
    Rule(
        "ROS 2 workspace",
        r"\b(isaacsim_bringup|cmdvel_to_ackermann|h1_fullbody_controller|isaac_moveit|ament_cmake|ament_python|run_isaacsim\.launch\.py|dds_type|use_internal_libs)\b",
        "Review ROS workspace package rename, ament_python layout, launcher parameters, and distro-specific validation.",
        "isaac_sim_6_0/ros2_workspace_package_migration",
    ),
    Rule(
        "Old ROS package name",
        r"<name>\s*isaacsim\s*</name>|\bget_package_share_directory\([\"']isaacsim[\"']\)|\bros2\s+launch\s+isaacsim\b",
        "Rename downstream references from the old isaacsim ROS package to isaacsim_bringup.",
        "isaac_sim_6_0/ros2_workspace_package_migration",
        "required",
    ),
    Rule(
        "Robot asset path",
        r"/Isaac/Robots/",
        "Review robot asset references for available /Isaac/Robots_Multiphysics catalog entries and validation status.",
        "isaac_sim_6_0/robot_asset_path_migration",
    ),
    Rule(
        "URDF importer API",
        r"\b(URDFImportFromROS2Node|URDFCreateImportConfig|URDFParseText|URDFParseFile|URDFParseAndImportFile|URDFImportRobot|acquire_urdf_interface|fix_base|merge_mesh)\b|_urdf\.ImportConfig|_mjcf\.ImportConfig",
        "Review URDF importer API changes, ROS 2 robot-description import, and tri-state base behavior.",
        "isaac_sim_6_0/urdf_mjcf_importer_exporter_pipeline",
        "required",
    ),
    Rule(
        "URDF mimic joint schema",
        r"\b(PhysxMimicJointAPI|PhysxSchema\.PhysxMimicJointAPI|physxMimicJoint|PhysxMimic|physx:mimic)\b",
        "Update mimic-joint validators and exporters for NewtonMimicAPI and newton:mimicJoint/newton:mimicCoef0/newton:mimicCoef1 attributes.",
        "isaac_sim_6_0/urdf_mjcf_importer_exporter_pipeline",
        "required",
    ),
    Rule(
        "Robot setup",
        r"\b(isaacsim\.robot_setup\.wizard|isaacsim\.util\.merge_mesh|MergeMeshRule|omni\.scene\.optimizer\.core)\b",
        "Split Robot Wizard and mesh-merge workflows across supported robot setup and Scene Optimizer tools.",
        "isaac_sim_6_0/robot_setup_wizard_and_mesh_merge",
        "required",
    ),
    Rule(
        "Robot control",
        r"\bisaacsim\.robot\.(manipulators|wheeled_robots)\b",
        "Migrate robot control packages to the experimental manipulator or wheeled robot packages.",
        "isaac_sim_6_0/robot_control_extensions_to_experimental",
        "required",
    ),
    Rule(
        "Robot motion",
        r"\bisaacsim\.robot_motion\.(lula|motion_generation|lula_test_widget)\b",
        "Migrate motion-generation code to experimental motion generation, cuMotion, or PINK.",
        "isaac_sim_6_0/robot_motion_to_experimental_motion_generation",
        "required",
    ),
    Rule(
        "Replicator",
        r"\bisaacsim\.replicator\.(domain_randomization|mobility_gen|scene_blox|agent)\b|state/common/.*\.npy",
        "Review Replicator domain randomization, MobilityGen recordings, Scene Blox removal, and Agent 1.x migration.",
        "isaac_sim_6_0/replicator_domain_randomization_to_experimental",
        "required",
    ),
    Rule(
        "Domain randomization registration",
        r"\bregister_(rigid_prim|articulation)_view\s*\(",
        'In Isaac Sim 6.0, register_rigid_prim_view and register_articulation_view require an explicit name argument, e.g. register_rigid_prim_view(view, "object_view").',
        "isaac_sim_6_0/replicator_domain_randomization_to_experimental",
        "required",
    ),
    Rule(
        "Replicator Agent config",
        r"\b(scene\.asset_path|nova_carter_num|iw_hub_num|camera_num|camera_list|command_file)\b",
        "Review Isaac Replicator Agent 0.x configs for the 1.x schema, including environment.base_stage_asset_path, named actor groups, and inline routines/triggers.",
        "isaac_sim_6_0/ext_isaacsim_replicator_agent_migration_guide",
    ),
    Rule(
        "Replicator Agent config",
        r"^\s{0,4}(response|incident):\s*(?:#.*)?$",
        "Review Isaac Replicator Agent 0.x response or incident config sections for the 1.x routine and trigger schema.",
        "isaac_sim_6_0/ext_isaacsim_replicator_agent_migration_guide",
        file_patterns=("*.yaml", "*.yml"),
    ),
    Rule(
        "Benchmark services",
        r"\b(gpu_frametime\s*=|IsaacUpdateFrametimeCollector)\b",
        "Remove removed gpu_frametime constructor arguments and legacy frame-time collectors.",
        "isaac_sim_6_0/benchmark_services_migration",
        "required",
    ),
    Rule(
        "Benchmark registry import",
        r"from\s+isaacsim\.benchmark\.services\s+import[^\n]*MeasurementDataRecorderRegistry",
        "Import MeasurementDataRecorderRegistry from isaacsim.benchmark.services.datarecorders.",
        "isaac_sim_6_0/benchmark_services_migration",
        "required",
    ),
    Rule(
        "Benchmark services inventory",
        r"\b(DEFAULT_RECORDERS|MeasurementDataRecorderRegistry|BaseIsaacBenchmark)\b|\brecorders\s*=",
        "Review benchmark recorder selection and custom recorder registration during migration.",
        "isaac_sim_6_0/benchmark_services_migration",
    ),
    Rule(
        "Removed tools",
        r"\b(isaacsim\.app\.selector|isaacsim\.benchmark\.examples|isaacsim\.replicator\.scene_blox|isaacsim\.asset\.browser|omni\.isaac\.ml_archive)\b",
        "Remove no-replacement tools or migrate to the documented replacement dependency.",
        "isaac_sim_6_0/removed_tools_and_replacements",
        "required",
    ),
    Rule(
        "Extension templates",
        r"\bisaacsim\.examples\.extension\b|Extension Template Generator",
        "Generate new extensions with ./repo.sh template new instead of the deprecated extension template UI.",
        "isaac_sim_6_0/extension_template_generator_to_cli_templates",
        "required",
    ),
]


def is_binary_usd_crate(path: Path) -> bool:
    try:
        with path.open("rb") as stream:
            return stream.read(8) == b"PXR-USDC"
    except OSError:
        return False


def should_scan(path: Path, relative_parts: tuple[str, ...]) -> bool:
    if any(part in SKIP_DIRS for part in relative_parts):
        return False
    if path.suffix == ".usd" and is_binary_usd_crate(path):
        return False
    return path.suffix in TEXT_SUFFIXES


def iter_files(root: Path) -> Iterable[Path]:
    for path in root.rglob("*"):
        if path.is_file() and should_scan(path, path.relative_to(root).parts):
            yield path


def read_text(path: Path) -> str:
    return path.read_text(encoding="utf-8", errors="ignore")


def scan_file(root: Path, path: Path, rules: list[tuple[Rule, re.Pattern[str]]]) -> list[Finding]:
    relative = path.relative_to(root).as_posix()
    try:
        text = read_text(path)
    except OSError:
        return []

    findings: list[Finding] = []
    applicable_rules = [
        (rule, regex)
        for rule, regex in rules
        if not rule.file_patterns or any(path.match(pattern) for pattern in rule.file_patterns)
    ]
    for line_number, line in enumerate(text.splitlines(), start=1):
        for rule, regex in applicable_rules:
            match = regex.search(line)
            if match:
                findings.append(
                    Finding(
                        file=relative,
                        line=line_number,
                        category=rule.category,
                        severity=rule.severity,
                        match=match.group(0),
                        message=rule.message,
                        guide=rule.guide,
                    )
                )
    return findings


def scan(root: Path) -> list[Finding]:
    compiled = [(rule, re.compile(rule.pattern)) for rule in RULES]
    findings: list[Finding] = []
    for path in iter_files(root):
        findings.extend(scan_file(root, path, compiled))
    return findings


def print_text(findings: list[Finding], max_results: int) -> None:
    shown = findings if max_results == 0 else findings[:max_results]
    if not findings:
        print("No Isaac Sim 6.0 migration patterns were found.")
        return

    for finding in shown:
        print(f"{finding.severity.upper()}: {finding.file}:{finding.line}: {finding.category}")
        print(f"  match: {finding.match}")
        print(f"  action: {finding.message}")
        print(f"  guide: {finding.guide}")

    hidden = len(findings) - len(shown)
    if hidden > 0:
        print(f"\n{hidden} additional findings hidden. Re-run with --max-results 0 to show all findings.")


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("root", type=Path, help="Project root to scan.")
    parser.add_argument("--json", action="store_true", help="Emit JSON instead of text.")
    parser.add_argument("--max-results", type=int, default=200, help="Maximum findings to print; use 0 for all.")
    parser.add_argument(
        "--fail-on",
        choices=("none", "required", "any"),
        default="none",
        help=(
            "Exit nonzero for matching findings. The default, 'none', treats "
            "the report as migration inventory rather than a CI gate."
        ),
    )
    return parser.parse_args()


def main() -> int:
    args = parse_args()
    root = args.root.expanduser().resolve()
    if not root.exists():
        raise SystemExit(f"Path does not exist: {root}")
    if not root.is_dir():
        raise SystemExit(f"Path is not a directory: {root}")

    findings = scan(root)
    findings.sort(key=lambda item: (item.severity != "required", item.file, item.line, item.category))
    if args.json:
        print(json.dumps([asdict(finding) for finding in findings], indent=2))
    else:
        print_text(findings, args.max_results)
    if args.fail_on == "any" and findings:
        return 1
    if args.fail_on == "required" and any(finding.severity == "required" for finding in findings):
        return 1
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

Run it from a source checkout:

python source/tools/isaac_sim_migration/audit_isaac_sim_6_0.py /path/to/project --max-results 0

The Isaac Sim 6.0.0 package does not bundle tools/isaac_sim_migration/. When no source checkout is available, copy audit_isaac_sim_6_0.py from the Isaac Sim repository into the project and run it with any Python 3; the script has no dependencies beyond the Python standard library.

Use --json when wiring the audit into CI. The default exit code is success so a raw audit run serves as migration inventory. Do not gate CI on review findings; inspect them manually. Treat required findings as workflow owners to investigate, not as automatic replacements. If a project intentionally wants CI to fail on unresolved migration inventory, pass --fail-on required or --fail-on any explicitly.

Finding Triage#

Finding class

What to inspect

Primary guide

omni.isaac.* extension names

App manifests, extension dependencies, imports, and tests that still use the old compatibility layer.

Renaming Extensions in Isaac Sim 4.5

Python runtime pins

Project virtual environments, compiled wheels, native extensions, ROS 2 Python packages, custom message workspaces, and ML dependencies pinned to Python 3.11.

Isaac Sim 6.0 Migration Strategy

Core API, prim wrappers, or utilities

Code that owns stages, simulation steps, render products, callbacks, semantics, rotations, and object helpers.

Core API to Core Experimental API

Camera, RTX, physics, or PhysX sensor packages

Sensor authoring APIs, saved sensor prims, OmniGraph nodes, PhysX raycast sensors, RTX Lidar conversion tools, and runtime read loops.

Sensor Timing and RTX Lidar Asset Migration

ROS 2 publisher Action Graphs

Saved graphs that connect prim paths directly to ROS publisher nodes.

ROS 2 OmniGraph Nodes

ROS 2 camera, Lidar, Radar, or point-cloud graphs

frameSkipCount, fullScan, point-cloud metadata, CameraInfo calibration, and render-product sizing.

ROS 2 Sensor Graph Migration

ROS 2 workspaces

Package names, ament_python conversion, console scripts, launcher parameters, and distro-specific dependencies.

ROS 2 Workspace Package Migration

URDF, MJCF, and robot asset pipeline

Importer/exporter scripts, ROS 2 robot-description import, base-type behavior, mimic joints, mesh merge, and Asset Transformer profiles.

URDF, MJCF, and Robot Asset Pipeline Changes

Robot asset paths

Hardcoded or configured /Isaac/Robots references that might have a multiphysics catalog replacement.

Robot Asset Path Migration

Robot control and motion packages

Manipulator, wheeled robot, motion-generation, and Lula dependencies that moved to experimental packages.

Manipulator and Wheeled Robot Extension Split, Robot Motion Generation APIs

Replicator workflows

Domain randomization registration, MobilityGen recordings, Replicator Agent 0.x configs, Scene Blox removal, and Agent 1.x migration.

Replicator Domain Randomization Extension, Replicator Agent (IRA)

Benchmark scripts

gpu_frametime=True, recorder selection, warmup frames, and custom collectors.

Benchmark Services Migration

Removed tools

Dependencies on app selector, benchmark examples, Scene Blox, asset browser, and omni.isaac.ml_archive.

Removed Tools and Replacements

Extension templates

Dependencies on the deprecated extension template UI or sample extension package.

Extension Template Generator to CLI Templates

Validation Gate#

The static audit is only the first gate. For every finding that maps to a customer workflow, run a matching runtime smoke test:

  • Extension or app startup with the migrated dependency set

  • One stage load, one reset if applicable, one simulation step, and one render when the workflow uses render products or RTX sensors

  • Saved USD graph open and save after deprecation-manager migration

  • ROS 2 message publication or launch validation for ROS workflows

  • Asset import/export round-trip for robot assets

  • Benchmark phase collection for performance workflows

  • Comparison against a small 5.x baseline metric, such as joint names, frame IDs, sensor frame cadence, PointCloud2 fields, writer rows, or KPI names

Do not clear a finding because imports resolve. Many 6.0 changes affect data flow, timing ownership, file layout, and generated USD authoring.

Record the validation evidence with the migration merge request (MR) or customer project:

  • Isaac Sim build or public release version used for the smoke test

  • Launch command, app experience, ROS environment, and any explicit launcher parameters

  • Input asset, scene, graph, or package under test

  • Expected 5.x behavior and observed 6.0 behavior

  • Pass/fail result, error log path, and owner for any remaining gap