Omniverse Kit: Extensions,
Apps, and the Python API
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:
my_extension/
├── config/
│ └── extension.toml # Metadata: name, version, dependencies
└── my_extension/
├── __init__.py
└── extension.py # The Extension class
# 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
Working with USD from a Kit Extension
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.
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
# 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 Type | Typical on_startup Time | Notes |
|---|---|---|
| Pure Python UI panel | < 50 ms | UI widget creation is fast |
| Physics scene setup | 100–500 ms | PhysX context initialisation |
| RTX render delegate | 500 ms – 2 s | Shader compilation on first launch |
| ROS 2 bridge | 200–800 ms | Depends 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
.kitconfiguration 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.