Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,18 @@ Rules are `.mdc` files in `rules/`. Frontmatter:
```yaml
---
description: <one-line>
alwaysApply: true
alwaysApply: false
globs:
- "**/*.py"
standards-version: 1.10.0
---
```

`alwaysApply: false` plus `globs` is the scoping contract: the rule loads only
when a matching file is in context. Setting `alwaysApply: true` makes `globs`
decorative and applies the rule everywhere, so the documented scope stops
describing behavior. Choose globs that cover every file the rule guards.

Rules encode anti-patterns. Each rule should show the wrong way, the right
way, and a one-paragraph rationale. 30 to 80 lines is the right size.

Expand Down
6 changes: 5 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,13 @@ VERSION - Source of truth for the repo version

## Rules (9)

Every rule sets `alwaysApply: false`, so the Scope column below is the rule's
actual load condition, not a description: a rule enters context only when a file
matching its `globs` does. Changing a glob changes when the rule fires.

| Rule | Scope | What it flags |
| --- | --- | --- |
| prefer-data-over-ops-in-loops | Always on | `bpy.ops.*` calls inside iteration over many objects |
| prefer-data-over-ops-in-loops | `*.py` | `bpy.ops.*` calls inside iteration over many objects |
| always-free-bmesh | `*.py` | `bmesh.new()` without paired `bm.free()` in a `try`/`finally` block |
| target-extensions-platform-format | Add-on roots | Legacy `bl_info` only add-ons missing `blender_manifest.toml` |
| type-annotate-props-and-defend-context | `*.py` | `bpy.props` defined as assignments, unguarded `context.active_object` |
Expand Down
10 changes: 9 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,21 @@ showcase/
```yaml
---
description: One-line summary for humans and tooling.
alwaysApply: true
alwaysApply: false
globs:
- "**/*.py"
standards-version: <current meta-repo STANDARDS_VERSION>
---
```

`alwaysApply: false` is deliberate and is what makes `globs` load-bearing:
the rule enters context only when a file it matches does. `alwaysApply:
true` would apply the rule in every context and make `globs` decorative, so
the two must never both be set as if they compose. Pick globs that cover
every file the rule is meant to guard before setting this — a glob that is
too narrow means the rule silently stops firing, which is worse than
over-applying. Record the scope in the `CLAUDE.md` rules table to match.

3. Write 30 to 80 lines: the anti-pattern, a code example showing it wrong, a code example showing it right, and a short "Why it matters" section.

## Adding a Snippet
Expand Down
2 changes: 1 addition & 1 deletion rules/always-free-bmesh.mdc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: Flag bmesh.new() calls without a paired bm.free() in a try/finally block. BMesh allocates C-side memory that Python's garbage collector cannot reclaim; missing free() leaks and eventually crashes Blender.
alwaysApply: true
alwaysApply: false
globs:
- "**/*.py"
standards-version: 1.10.0
Expand Down
2 changes: 1 addition & 1 deletion rules/no-unapplied-modifiers-on-export.mdc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: 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.
alwaysApply: true
alwaysApply: false
globs:
- "**/*.py"
standards-version: 1.10.0
Expand Down
2 changes: 1 addition & 1 deletion rules/prefer-data-over-ops-in-loops.mdc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: 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.
alwaysApply: true
alwaysApply: false
globs:
- "**/*.py"
standards-version: 1.10.0
Expand Down
2 changes: 1 addition & 1 deletion rules/prefer-temp-override-over-context-copy.mdc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: Flag uses of `bpy.context.copy()` to override context for an operator call. The copy-and-pass pattern was deprecated in Blender 4.x and the override semantics were removed in 5.x. Use `bpy.context.temp_override(**overrides)` as a context manager instead.
alwaysApply: true
alwaysApply: false
globs:
- "**/*.py"
standards-version: 1.10.0
Expand Down
2 changes: 1 addition & 1 deletion rules/target-extensions-platform-format.mdc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: 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.
alwaysApply: true
alwaysApply: false
globs:
- "**/__init__.py"
- "**/blender_manifest.toml"
Expand Down
2 changes: 1 addition & 1 deletion rules/type-annotate-props-and-defend-context.mdc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: 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.
alwaysApply: true
alwaysApply: false
globs:
- "**/*.py"
standards-version: 1.10.0
Expand Down
2 changes: 1 addition & 1 deletion rules/use-correct-axis-rna-per-exporter.mdc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: 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.
alwaysApply: true
alwaysApply: false
globs:
- "**/*.py"
standards-version: 1.10.0
Expand Down
2 changes: 1 addition & 1 deletion rules/use-foreach-set-for-bulk-data.mdc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: 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.
alwaysApply: true
alwaysApply: false
globs:
- "**/*.py"
standards-version: 1.10.0
Expand Down
2 changes: 1 addition & 1 deletion rules/validate-imported-mesh-scale.mdc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: 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.
alwaysApply: true
alwaysApply: false
globs:
- "**/*.py"
standards-version: 1.10.0
Expand Down
Loading