# 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.

- Skill: `nvidia-omniverse/blender-python-execution` (Agent Skill, multi-file: 7 files)
- Install (CLI): `npx skillmds@latest add nvidia-omniverse/blender-python-execution`
- Raw SKILL.md: https://api.skillmd.com/api/skills/nvidia-omniverse/blender-python-execution/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: NVIDIA-Omniverse (https://skillmd.com/u/nvidia-omniverse)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/nvidia-omniverse/blender-python-execution

---


# 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.

