blender-rules · git:20261012.5a56f5e · 2026-10-12 · sha256 b4dcd649835ec5d0

blender-rules git:20261012.5a56f5eA

Immutable. This exact content never changes and is served at /api/v1/blob/b4dcd649835ec5d0.

---
name: blender-rules
description: Blender Python anti-pattern rules (bmesh leaks, bpy.ops in loops, deprecated context-copy overrides, bulk mesh writes, prop annotations and context guards, Extensions manifest, import scale, export modifiers, glTF/FBX axis RNA, the removed bgl module, the normals API removed in 4.1). Use when writing, reviewing or fixing any bpy / Blender add-on or script code.
---

# Blender Developer Tools rules (Claude Code)

<!-- Generated by scripts/build_claude_rules.py from rules/*.mdc. Do not edit. -->

Apply these when writing or reviewing Blender Python. Each rule links to the
full version with Wrong/Right examples.

## always-free-bmesh

Flag bmesh.new() calls without a paired bm.free() in a try/finally block. Blender frees an unreferenced BMesh only when its Python wrapper dies, which a traceback, global, closure or modal operator can delay for the whole session; an explicit free() in finally releases it deterministically.

Applies to: `**/*.py`. Full rule: [`rules/always-free-bmesh.mdc`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/rules/always-free-bmesh.mdc).

## no-bgl

Flag `import bgl` and any `bgl.` call. The `bgl` OpenGL wrapper was deprecated in 3.x and is gone in Blender 5.x (`importlib.util.find_spec('bgl')` is `None` on 5.0, 5.1 and 5.2), so an add-on that imports it fails to register. Draw with the `gpu` module, `gpu.state` and `gpu_extras.batch` instead; see the gpu-drawing-and-overlays skill.

Applies to: `**/*.py`. Full rule: [`rules/no-bgl.mdc`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/rules/no-bgl.mdc).

## no-removed-normals-api

Flag the mesh normals API removed in Blender 4.1 — `use_auto_smooth`, `auto_smooth_angle`, `calc_normals_split()`, `free_normals_split()`, `create_normals_split()`. Each raises AttributeError on 4.5 LTS and 5.x. Use `Mesh.set_sharp_from_angle`, `object.shade_auto_smooth`, and `Mesh.corner_normals` (always current) instead.

Applies to: `**/*.py`. Full rule: [`rules/no-removed-normals-api.mdc`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/rules/no-removed-normals-api.mdc).

## no-unapplied-modifiers-on-export

Flag an export call on objects that still carry unapplied modifiers when the export arguments do not request evaluated geometry. The engine then receives the authored cage, not the modifier result.

Applies to: `**/*.py`. Full rule: [`rules/no-unapplied-modifiers-on-export.mdc`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/rules/no-unapplied-modifiers-on-export.mdc).

## prefer-data-over-ops-in-loops

Flag bpy.ops.* calls inside iteration over many objects, meshes, or frames. Each bpy.ops call triggers a full depsgraph evaluation and UI redraw; loops slow down by orders of magnitude. Use bpy.data.* and bmesh instead.

Applies to: `**/*.py`. Full rule: [`rules/prefer-data-over-ops-in-loops.mdc`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/rules/prefer-data-over-ops-in-loops.mdc).

## prefer-temp-override-over-context-copy

Flag uses of `bpy.context.copy()` to override context for an operator call. Passing a context dict to an operator was deprecated in Blender 3.2 and removed in 4.0, so it already fails on the 4.5 LTS fallback. Use `bpy.context.temp_override(**overrides)` as a context manager instead.

Applies to: `**/*.py`. Full rule: [`rules/prefer-temp-override-over-context-copy.mdc`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/rules/prefer-temp-override-over-context-copy.mdc).

## target-extensions-platform-format

Flag new Blender add-ons that ship only a legacy bl_info dict without a blender_manifest.toml. New add-ons must use the Extensions Platform format. bl_info may appear alongside as a fallback for backward compatibility, but the manifest is the source of truth.

Applies to: `**/__init__.py`, `**/blender_manifest.toml`. Full rule: [`rules/target-extensions-platform-format.mdc`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/rules/target-extensions-platform-format.mdc).

## type-annotate-props-and-defend-context

Flag two related anti-patterns. (1) bpy.props defined as class-level assignments instead of type annotations (deprecated since 2.8). (2) Code that touches bpy.context.active_object without guarding for None, or that assumes the active object is selected.

Applies to: `**/*.py`. Full rule: [`rules/type-annotate-props-and-defend-context.mdc`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/rules/type-annotate-props-and-defend-context.mdc).

## use-correct-axis-rna-per-exporter

Flag export_scene.gltf calls that pass FBX axis_forward or axis_up, and export_scene.fbx calls that pass glTF export_yup. The two exporters do not share axis RNA.

Applies to: `**/*.py`. Full rule: [`rules/use-correct-axis-rna-per-exporter.mdc`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/rules/use-correct-axis-rna-per-exporter.mdc).

## use-foreach-set-for-bulk-data

Flag Python loops that set vertex coordinates, normals, UVs, or other bulk per-element data one element at a time. For meshes of more than a few thousand elements, this is 100x to 1000x slower than `mesh.vertices.foreach_set("co", flat_array)`, which writes through to C-level storage in one pass.

Applies to: `**/*.py`. Full rule: [`rules/use-foreach-set-for-bulk-data.mdc`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/rules/use-foreach-set-for-bulk-data.mdc).

## validate-imported-mesh-scale

Flag a glTF or FBX import followed by mesh operations with no transform_apply and no unit-scale check. Generated files often arrive with non-identity object scale or a non-meter scene scale; mesh edits then bake the wrong size.

Applies to: `**/*.py`. Full rule: [`rules/validate-imported-mesh-scale.mdc`](https://github.com/TMHSDigital/Blender-Developer-Tools/blob/main/rules/validate-imported-mesh-scale.mdc).