Isaac Sim Script Executor is a development Claude Skill built by Sungmin Kim. Best for: Robotics engineers and simulation developers write low-level USD operations, raycasting, and batch transformations in Isaac Sim when granular MCP tools are insufficient..

What it does
Execute custom Python scripts in Isaac Sim 5.1.0 via TCP, accessing pxr/omni/isaacsim APIs with JSON output.
Category
development
Created by
Sungmin Kim
Last updated
developmentintermediate

Isaac Sim Script Executor

Execute custom Python scripts in Isaac Sim 5.1.0 via TCP, accessing pxr/omni/isaacsim APIs with JSON output.

Skill instructions


name: isaac-scripting description: This skill should be used when the user asks to "execute a script in Isaac Sim", "run Python in Isaac", "write a custom Isaac Sim script", "use the omni API", "use the pxr API", "use the isaacsim API", "execute_isaac_script", or needs to perform operations not covered by the granular MCP tools. version: 0.1.0

Isaac Sim Scripting via execute_isaac_script

When to Use This Tool vs Granular MCP Tools

Prefer granular MCP tools first. The simul plugin exposes purpose-built tools for the most common operations:

| Need | Use Instead | |------|-------------| | Create a prim | create_isaac_prim | | Move/rotate/scale | set_isaac_prim_transform | | Set an attribute | set_isaac_prim_attribute | | Add rigid body | add_isaac_rigid_body | | Add collision | add_isaac_collision | | Physics material | set_isaac_physics_material | | Start/stop sim | start_isaac_simulation, stop_isaac_simulation | | Query scene | get_isaac_scene_summary, get_isaac_prim_info |

Use execute_isaac_script when:

  • The required API is not exposed by any granular tool (e.g. creating lights, querying rigid body velocities, custom material shaders, bounding box computations, raycasting)
  • You need to batch multiple low-level USD operations in a single round-trip to reduce latency
  • You need full pxr.*, omni.*, or isaacsim.* API access
  • You are iterating over many prims (stage traversal, bulk attribute reads)

Execution Model

Scripts are sent over TCP to port 8226 (the stock isaacsim.code_editor.vscode extension). The executor runs your code with compile() inside Kit's Python process, giving full access to the global namespace including omni.*, pxr.*, and isaacsim.*.

Key rules:

  • stdout is captured and returned — use print() for all output
  • For structured results, always end with print(json.dumps({...})) as the final line
  • Top-level await is supported — the executor detects coroutines automatically
  • Each execution is independent: always import everything at the top of each script; do not rely on state from previous executions
  • Avoid long-running loops or time.sleep() calls that block the Kit main thread

Script Structure

Every script should follow the error-safe template:

import json
import traceback

try:
    # --- your logic here ---
    import omni.usd
    stage = omni.usd.get_context().get_stage()
    prim_count = len(list(stage.Traverse()))
    result = {"success": True, "prim_count": prim_count}
except Exception as e:
    result = {"success": False, "error": str(e), "traceback": traceback.format_exc()}

print(json.dumps(result))

Always wrap in try/except. Always end with print(json.dumps(result)). This ensures the tool always returns parseable JSON even when the script raises an exception.

Namespace: Isaac Sim 5.1.0

Isaac Sim 5.1.0 migrated the core package namespace. Use the new names — the old omni.isaac.* imports will fail:

| Old (pre-5.1) | New (5.1.0+) | |---------------|--------------| | omni.isaac.core | isaacsim.core.api | | omni.isaac.core.utils | isaacsim.core.utils | | omni.isaac.core.utils.prims | isaacsim.core.utils.prims | | omni.isaac.core.utils.stage | isaacsim.core.utils.stage | | omni.isaac.core.utils.xforms | isaacsim.core.utils.xforms | | omni.isaac.core.utils.bounds | isaacsim.core.utils.bounds | | omni.isaac.core.utils.rotations | isaacsim.core.utils.rotations | | omni.isaac.core.utils.collisions | isaacsim.core.utils.collisions | | omni.isaac.core.utils.viewports | isaacsim.core.utils.viewports |

Kit-level APIs are unchanged: omni.usd, omni.timeline, pxr.* (Usd, UsdGeom, UsdPhysics, UsdShade, UsdLux, Gf, Sdf, etc.) all import normally.

Common Script Patterns

Check simulation state

import json, omni.timeline
tl = omni.timeline.get_timeline_interface()
print(json.dumps({
    "playing": tl.is_playing(),
    "stopped": tl.is_stopped(),
    "current_time": tl.get_current_time(),
}))

Traverse and list all prims by type

import json, omni.usd
stage = omni.usd.get_context().get_stage()
prims = [
    {"path": str(p.GetPath()), "type": p.GetTypeName()}
    for p in stage.Traverse()
    if p.GetTypeName()  # skip pseudoroot and untyped
]
print(json.dumps({"prims": prims, "count": len(prims)}))

List all Mesh prims

import json, omni.usd
stage = omni.usd.get_context().get_stage()
meshes = [str(p.GetPath()) for p in stage.Traverse() if p.GetTypeName() == "Mesh"]
print(json.dumps({"meshes": meshes, "count": len(meshes)}))

Set prim transform via USD attribute

import json, traceback
try:
    from isaacsim.core.utils.prims import set_prim_attribute_value
    from pxr import Gf
    set_prim_attribute_value("/World/Box", "xformOp:translate", Gf.Vec3d(1.0, 2.0, 0.5))
    set_prim_attribute_value("/World/Box", "xformOp:scale", Gf.Vec3d(2.0, 2.0, 2.0))
    result = {"success": True}
except Exception as e:
    import traceback
    result = {"success": False, "error": str(e), "traceback": traceback.format_exc()}
print(json.dumps(result))

Get world pose

import json, traceback
try:
    from isaacsim.core.utils.xforms import get_world_pose
    pos, quat = get_world_pose("/World/Robot")
    result = {"success": True, "position": pos.tolist(), "orientation_wxyz": quat.tolist()}
except Exception as e:
    result = {"success": False, "error": str(e), "traceback": traceback.format_exc()}
print(json.dumps(result))

Compute bounding box

import json, traceback
try:
    from isaacsim.core.utils.bounds import create_bbox_cache, compute_aabb
    import numpy as np
    cache = create_bbox_cache()
    aabb = compute_aabb(cache, "/World/Robot")
    center = ((aabb[:3] + aabb[3:]) / 2).tolist()
    size = (aabb[3:] - aabb[:3]).tolist()
    result = {"success": True, "center": center, "size": size, "aabb": aabb.tolist()}
except Exception as e:
    result = {"success": False, "error": str(e), "traceback": traceback.format_exc()}
print(json.dumps(result))

Common Pitfalls

Do not reuse state between executions. Each execute_isaac_script call is isolated. Variables, imports, and objects from a previous call are not available. Always re-import.

Do not block the main thread. Never use while True, time.sleep(), or any blocking wait inside a script. For physics stepping, use world.step(render=True) in a bounded loop (e.g. for _ in range(10)), not an infinite one.

Use World.instance() not World() when the world already exists. Calling World() a second time raises an error. Always check:

from isaacsim.core.api import World
world = World.instance()
if world is None:
    world = World(physics_dt=1/60, rendering_dt=1/60)

JSON-serialise everything. pxr.Gf.Vec3d, numpy arrays, and USD types are not JSON-serialisable. Convert with .tolist() or list(v) before passing to json.dumps.

Attribute access requires the prim to be valid. Always check prim.IsValid() before calling methods on it. A prim retrieved from a path that does not exist returns an invalid prim that will raise on method calls.

Reference Files

  • references/api-quick-reference.md — full API task-to-module lookup table
  • references/namespace-migration.md — complete old-to-new namespace mapping
  • references/script-templates.md — copy-paste templates for common patterns

Install

/plugin install isaac-sim-script-executor@kickthemoon0817

Requires Claude Code CLI.

Use cases

Robotics engineers and simulation developers write low-level USD operations, raycasting, and batch transformations in Isaac Sim when granular MCP tools are insufficient.

Reviews

No reviews yet. Be the first to review this skill.

Stats

Installs0
GitHub Stars0
Forks0
LicenseApache License 2.0
UpdatedMar 25, 2026