AIMaks

Omniverse Kit: Extensions,
Apps, and the Python API

45 min readnotebookOmniverse Platform Fundamentals
4 of 50NVIDIA Omniverse & Robot Learning

Omniverse Kit: Extensions, Apps, and the Python API

Omniverse Kit is the application framework on which every Omniverse app is built — Isaac Sim, USD Composer, Audio2Face, and your own custom tools. Kit's superpower is its hot-reloadable extension system: every feature (viewport, physics, UI panel, action graph) is a composable extension that can be enabled, disabled, or swapped at runtime without restarting the application.

Anatomy of a Kit Extension

A Kit extension is a directory with at minimum two files:

bash
my_extension/
├── config/
   └── extension.toml   # Metadata: name, version, dependencies
└── my_extension/
    ├── __init__.py
    └── extension.py     # The Extension class
python
# extension.toml
# [package]
# title  = "My First Extension"
# version = "1.0.0"
# [dependencies]
# "omni.kit.uiapp" = {}

# extension.py
import omni.ext
import omni.ui as ui

class MyFirstExtension(omni.ext.IExt):
    'Minimal Kit extension that adds a window.'

    def on_startup(self, ext_id: str):
        print(f"[my_extension] Startup — ext_id={ext_id}")
        self._window = ui.Window("Hello Omniverse", width=300, height=120)
        with self._window.frame:
            with ui.VStack():
                ui.Label("Welcome to Kit!", alignment=ui.Alignment.CENTER)
                ui.Button("Click Me", clicked_fn=self._on_click)

    def _on_click(self):
        import omni.kit.notification_manager as nm
        nm.post_notification("Button clicked!", status=nm.NotificationStatus.INFO)

    def on_shutdown(self):
        print("[my_extension] Shutdown")
        if self._window:
            self._window.destroy()
            self._window = None

Extension Lifecycle

DISCOVERED LOADED STARTED STOPPED import on_startup on_shutdown Kit Extension Lifecycle

Working with USD from a Kit Extension

python
import omni.usd
from pxr import Usd, UsdGeom, Gf, PhysicsSchemaTools

def add_physics_sphere(stage: Usd.Stage, path: str, radius: float = 0.1,
                        mass: float = 1.0) -> UsdGeom.Sphere:
    'Add a rigid-body sphere to the active stage.'
    sphere = UsdGeom.Sphere.Define(stage, path)
    sphere.GetRadiusAttr().Set(radius)

    # Apply physics schemas
    from pxr import UsdPhysics
    UsdPhysics.RigidBodyAPI.Apply(sphere.GetPrim())
    mass_api = UsdPhysics.MassAPI.Apply(sphere.GetPrim())
    mass_api.GetMassAttr().Set(mass)

    # Enable collision
    UsdPhysics.CollisionAPI.Apply(sphere.GetPrim())
    sphere_collision = UsdPhysics.SphereShapeAPI.Apply(sphere.GetPrim())

    return sphere

# Usage inside on_startup
stage = omni.usd.get_context().get_stage()
add_physics_sphere(stage, "/World/Ball", radius=0.05, mass=0.5)

OmniGraph: Visual Scripting and Action Graphs

OmniGraph is Kit's node-based dataflow system. It powers ROS 2 bridge nodes, sensor processing pipelines, and animation state machines — all without writing Python. Graphs live in the USD stage as prim hierarchies under the schema OmniGraphSchema, so they are version-controlled and transferable like any other USD data.

python
import omni.graph.core as og

# Create a simple action graph that prints a message every frame
(graph, nodes, _, _) = og.Controller.edit(
    {"graph_path": "/World/ActionGraph", "evaluator_name": "execution"},
    {
        og.Controller.Keys.CREATE_NODES: [
            ("OnTick",   "omni.graph.action.OnTick"),
            ("PrintMsg", "omni.graph.debug.PrintText"),
        ],
        og.Controller.Keys.CONNECT: [
            ("OnTick.outputs:tick", "PrintMsg.inputs:execIn"),
        ],
        og.Controller.Keys.SET_VALUES: [
            ("PrintMsg.inputs:text", "Hello from OmniGraph!"),
        ],
    },
)
print("Graph created:", graph.get_path_to_graph())

Headless Kit: Running Without a GUI

bash
# Run a Python script inside Kit headlessly (useful for CI/CD)
~/.local/share/ov/pkg/isaac_sim-*/kit/kit \
    --no-window \
    --exec "my_script.py" \
    --ext-folder /path/to/my_extension \
    --enable my_extension

# Or use the Isaac Sim Python entry-point
~/.local/share/ov/pkg/isaac_sim-*/python.sh my_robot_script.py

Extension Dependency Resolution

Kit resolves extension dependencies at startup using a directed acyclic graph (DAG). If extension depends on , then is guaranteed to be started before . The total startup time for a set of extensions in a dependency chain of depth is:

where is the on_startup wall time of extension . Parallelising independent extensions (different DAG branches) can reduce total startup by up to .

Extension TypeTypical on_startup TimeNotes
Pure Python UI panel< 50 msUI widget creation is fast
Physics scene setup100–500 msPhysX context initialisation
RTX render delegate500 ms – 2 sShader compilation on first launch
ROS 2 bridge200–800 msDepends on ROS 2 middleware init

Key Takeaways

  • Every Omniverse application is an assembly of Kit extensions — you can build custom apps by selecting and configuring extensions in a .kit configuration file.
  • Extensions follow a clear lifecycle: discovered → loaded → started → stopped; always clean up resources in on_shutdown.
  • OmniGraph provides a no-code dataflow layer that complements Python scripting — use it for sensor pipelines and ROS 2 integration.
Up next · Quiz: Omniverse Platform Basics