Skip to main content

blender-python-execution

Execute and validate Blender Python through a Blender MCP provider using small, context-safe, idempotent transactions. Use when an agent must inspect or mutate a Blender scene, translate a Blender task into bpy code, recover from Blender code execution errors, or prove that an MCP-driven edit actually changed the intended scene.

Source facts

Repository
NVIDIA-Omniverse/omniverse-labs
Last source activity
July 18, 2026 at 00:27
Detected SKILL.md language
English
Stars
60
Forks
15

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
7 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
blender-python-execution
description
Execute and validate Blender Python through a Blender MCP provider using small, context-safe, idempotent transactions. Use when an agent must inspect or mutate a Blender scene, translate a Blender task into bpy code, recover from Blender code execution errors, or prove that an MCP-driven edit actually changed the intended scene.
# Blender Python execution Use the provider's Blender tools as a transaction loop: inspect, execute one bounded change, inspect structured state, then inspect pixels when the result is visual. This skill owns execution discipline, not modeling or look-development decisions. ## Discover the adapter The known adapter exposes these schemas: ```text get_scene_info() execute_blender_code(code) get_object_info(object_name) get_viewport_screenshot(max_size=800) ``` Tool prefixes and provider aliases are discoverable and may differ. Match tools by schema and behavior; do not guess an endpoint or port. Read `references/mcp-call-contract.md` before the first mutation. ## Run the transaction loop 1. Call `get_scene_info()` before executing code. Identify the current file, scene, mode, active object, camera, engine, and objects in scope. Preserve existing content unless the user explicitly asks to replace it. 2. Run the read-only code in `scripts/scene_probe.py` through `execute_blender_code(code)` when the provider's scene summary is incomplete. Use `scripts/scene_audit.py` before rendering, export, or handoff. To prove camera coverage, prepend `BLENDER_AUDIT_REQUEST = {"targets": ["ROOT-subject"], "margin": 0.08, "include_descendants": True, "include_instances": True}` when executing through MCP, or pass `--targets GEO-subject --margin 0.08` after Blender's `--` delimiter; use `--no-descendants` or `--no-instances` only when those bounds are intentionally excluded. A camera merely existing is not a framing pass. 3. Define one transaction with named inputs, stable target names, a narrow mutation, and an expected postcondition. Prefer Blender's data API. Use an operator only when its context is prepared explicitly. 4. Send a small, self-contained code string to `execute_blender_code(code)`. Every call has a fresh Python namespace: re-import modules and reacquire datablocks from `bpy.data` by name. 5. End the code with one JSON object on standard output. Include `ok`, `operation`, target names, changed values or counts, and any warnings. Do not print credentials, environment variables, or unrelated paths. 6. Call `get_object_info(object_name)` for every primary target and `get_scene_info()` after scene-wide changes. Check the expected state rather than treating a successful tool response as proof. 7. For visible changes, call `get_viewport_screenshot(max_size=800)` or inspect the requested render. Verify framing, geometry, materials, and lighting. A screenshot can be stale or produced by another engine; it does not by itself prove that OVRTX rendered or accepted an edit. ## Execution rules - Never use `time.sleep()` or a polling loop inside Blender code. Return control to the agent and poll with provider/status tools outside Blender. - Keep each call bounded. Split creation, materials, lighting, rendering, and export into independently verifiable transactions. - Use stable names and explicit ownership. Do not rely on selection order, default names, or Python variables from a previous call. - Make mutations idempotent: get-or-create owned datablocks, set requested values absolutely, and avoid duplicate modifiers, links, handlers, or nodes. - Call `bpy.context.view_layer.update()` before reading evaluated transforms, bounds, or dependency-graph results. - Prefer direct data access. When an operator is necessary, set mode, selection, and active object explicitly or use `bpy.context.temp_override(...)` with a verified area/region. Restore user-visible context when practical. - Do not delete broadly, reset the scene or World, open another file, save over the source, enable scripts, install add-ons, or render to an arbitrary path unless the user requested that exact action. - Treat external `.blend`, USD, archives, scripts, drivers, and add-ons as untrusted content. Opening or enabling them is outside this execution skill. ## Mutation shape Use the patterns in `references/python-transaction-patterns.md`. A minimal transaction has this form: ```python import bpy, json name = "GEO-requested-target" obj = bpy.data.objects.get(name) if obj is None: raise RuntimeError(f"missing target: {name}") obj.hide_render = False bpy.context.view_layer.update() print(json.dumps({ "ok": True, "operation": "set_render_visibility", "object": obj.name, "hide_render": obj.hide_render, }, sort_keys=True)) ``` ## Failure handling - On a traceback, report the exception and failing line, reduce the transaction, reacquire state, and retry only the failed operation. - On timeout, do not resend the same large script. Inspect the scene, split the work, and remove blocking waits or expensive loops. - If structured state changed but pixels did not, check camera, view layer, visibility, dependency-graph evaluation, active engine, and stale viewport state before repeating the mutation. Use the interactive redraw/frame pattern in `references/python-transaction-patterns.md`, return control, then capture a new screenshot; use a render when background mode or freshness matters. - For reproducible render-camera coverage, route to `blender-camera-framing`. Viewport `view_selected` changes only `RegionView3D` and cannot prove that a render camera contains the subject. - If the provider lacks code execution, do not use shell Blender as a hidden substitute for mutating the user's live session. Stop and report the missing capability. A background Blender script is allowed only when the user explicitly authorizes an offline/caller-owned derivative or the routed workflow already declares background execution for a large build, frame loop, render, or round-trip test; keep it isolated from the live source. ## Completion gate Report success only when the requested postcondition passes structured inspection and every visual claim has current visual evidence. State the active engine and label screenshots, Blender renders, native renderer products, and postprocessed images separately.
View on GitHub