Skip to content

Commit 077cdd9

Browse files
TMHSDigitalclaude
andcommitted
feat: five skills for stranded examples, and CI that runs snippets and skill blocks in place
#456: every example now maps to a skill (Validate rejects a new []). New skills, each grounded in the examples that prove it: - grease-pencil-v3 (grease-pencil-rosette, gp-lineart-contour) - constraints-and-parenting (damped-track-aim, parent-inverse-orrery, socket-attach-points) - images-and-pixels (image-pixels-testcard, png-exr-alpha) - curves-and-text (curve-bevel-arc, text-version-stamp) - compositor-nodes (compositor-glare) plus a Light linking section in procedural-materials-and-shaders and a sculpt automasking section in mesh-editing-and-bmesh. Counts 20 -> 25. #447: tests/smoke/run_content.py execs every snippets/*.py from its own source (no frozen copy) and asserts one fact per snippet (tests/smoke/snippet_checks.py), then reapplies a source edit that must make the check fail. Several falsifiers reintroduce past bugs: Godot export_yup=False (#346), the hull's loose verts (#386), the image format save_render ignores (#332), Unreal FBX scale (#297). It also runs every SKILL.md block tagged <!-- smoke: run -->. content-smoke.yml runs it on 5.2 and 4.5 with a positive paths filter (blender-smoke ignores **.md), and release-gate.sh waits for it on pushes touching skills or snippets. Validate's check_content_catalog.py requires an entry per snippet and compiles all 143 SKILL.md python blocks (one stray top-level return fixed). Live runs of run_content.py, 31 snippets + 31 falsifiers + 9 skill blocks, 0 failed, on 4.5.14 LTS, 5.1.2 and 5.2.1 LTS. Running it caught three wrong claims, now fixed: Image.save() drops the buffer only for float images (byte images keep has_data), extension_path_user rejects only non-bl_ext packages, and USD export writes a subsurf as a USD subdivision scheme rather than applying it, so the check uses a render-only Array instead. Closes #447 Closes #456 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 8d4cd16 commit 077cdd9

26 files changed

Lines changed: 2001 additions & 46 deletions

File tree

‎.cursor-plugin/plugin.json‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,12 @@
3939
"skills/bl-info-migration/SKILL.md",
4040
"skills/vse-python/SKILL.md",
4141
"skills/gpu-drawing-and-overlays/SKILL.md",
42-
"skills/porting-to-blender-5/SKILL.md"
42+
"skills/porting-to-blender-5/SKILL.md",
43+
"skills/grease-pencil-v3/SKILL.md",
44+
"skills/constraints-and-parenting/SKILL.md",
45+
"skills/images-and-pixels/SKILL.md",
46+
"skills/curves-and-text/SKILL.md",
47+
"skills/compositor-nodes/SKILL.md"
4348
],
4449
"rules": [
4550
"rules/prefer-data-over-ops-in-loops.mdc",

‎.github/scripts/release-gate.sh‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,26 @@ smoke_applies() {
7070
return 1
7171
}
7272

73+
# content_smoke_applies: 0 when some changed file matches content-smoke.yml's
74+
# positive `paths` filter (skills, snippets, the content runner). Same
75+
# fail-toward-waiting rules as smoke_applies.
76+
content_smoke_applies() {
77+
local files
78+
if [ -n "${BEFORE:-}" ] && [ "${BEFORE}" != "0000000000000000000000000000000000000000" ]; then
79+
files=$(gh api "repos/$repo/compare/$BEFORE...$sha" --jq '.files[].filename' 2>/dev/null) || return 0
80+
else
81+
files=$(gh api "repos/$repo/commits/$sha" --jq '.files[].filename' 2>/dev/null) || return 0
82+
fi
83+
[ -n "$files" ] || return 0
84+
[ "$(printf '%s\n' "$files" | wc -l)" -lt 300 ] || return 0
85+
while IFS= read -r f; do
86+
case "$f" in
87+
skills/*|snippets/*|tests/smoke/run_content.py|tests/smoke/snippet_checks.py|.github/workflows/content-smoke.yml) return 0 ;;
88+
esac
89+
done <<< "$files"
90+
return 1
91+
}
92+
7393
wait_green validate.yml Validate "${GATE_TIMEOUT:-1500}"
7494

7595
pr=$(gh api "repos/$repo/commits/$sha/pulls" --jq '.[0].number // empty')
@@ -79,6 +99,9 @@ if [ -z "$pr" ]; then
7999
else
80100
echo "Direct push changed only smoke-ignored paths; Validate alone gates this release"
81101
fi
102+
if content_smoke_applies; then
103+
wait_green content-smoke.yml "Content Smoke" "${CONTENT_TIMEOUT:-2700}"
104+
fi
82105
exit 0
83106
fi
84107

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
name: Content Smoke
2+
3+
# Runs the shipped snippets and the `<!-- smoke: run -->` blocks in
4+
# skills/*/SKILL.md in place, on 5.2 LTS and 4.5 LTS (#447). A positive
5+
# `paths` filter, not blender-smoke.yml's paths-ignore: that one ignores
6+
# "**.md", so a SKILL.md-only change would never reach Blender.
7+
# release-gate.sh waits for this run on a direct push that touches these paths.
8+
9+
on:
10+
workflow_dispatch:
11+
schedule:
12+
- cron: "30 7 * * 1" # weekly, after blender-smoke: catches upstream API drift
13+
push:
14+
branches: [main]
15+
paths:
16+
- "skills/**"
17+
- "snippets/**"
18+
- "tests/smoke/run_content.py"
19+
- "tests/smoke/snippet_checks.py"
20+
- ".github/workflows/content-smoke.yml"
21+
pull_request:
22+
branches: [main]
23+
paths:
24+
- "skills/**"
25+
- "snippets/**"
26+
- "tests/smoke/run_content.py"
27+
- "tests/smoke/snippet_checks.py"
28+
- ".github/workflows/content-smoke.yml"
29+
30+
permissions:
31+
contents: read
32+
33+
concurrency:
34+
group: content-smoke-${{ github.event.pull_request.number || (github.event_name == 'push' && github.sha) || github.ref }}
35+
cancel-in-progress: true
36+
37+
jobs:
38+
content:
39+
name: Blender ${{ matrix.series }} content smoke
40+
runs-on: ubuntu-latest
41+
timeout-minutes: 30
42+
strategy:
43+
fail-fast: false
44+
matrix:
45+
series: ["5.2", "4.5"]
46+
steps:
47+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
48+
49+
- name: Install Blender runtime libraries
50+
run: |
51+
set -euo pipefail
52+
sudo apt-get update
53+
sudo apt-get install -y --no-install-recommends \
54+
xvfb libgl1 libegl1 libxrender1 libxxf86vm1 libxfixes3 libxi6 \
55+
libxkbcommon0 libsm6 libice6
56+
57+
- name: Resolve Blender ${{ matrix.series }}
58+
id: resolve
59+
run: |
60+
set -euo pipefail
61+
series="${{ matrix.series }}"
62+
base="https://download.blender.org/release/Blender${series}/"
63+
file=$(curl -fsSL "$base" \
64+
| grep -oE "blender-${series}\.[0-9]+-linux-x64\.tar\.xz" \
65+
| sort -V | uniq | tail -1)
66+
if [ -z "$file" ]; then
67+
echo "::error::Could not resolve a linux-x64 build for Blender ${series} at $base"
68+
exit 1
69+
fi
70+
version="${file#blender-}"
71+
version="${version%-linux-x64.tar.xz}"
72+
echo "base=$base" >> "$GITHUB_OUTPUT"
73+
echo "file=$file" >> "$GITHUB_OUTPUT"
74+
echo "version=$version" >> "$GITHUB_OUTPUT"
75+
echo "Resolved Blender $version"
76+
77+
- name: Restore Blender ${{ steps.resolve.outputs.version }} from cache
78+
id: bl-cache
79+
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
80+
with:
81+
path: ${{ runner.temp }}/bl
82+
key: blender-${{ steps.resolve.outputs.version }}-linux-x64
83+
84+
- name: Download Blender and verify its published sha256
85+
if: steps.bl-cache.outputs.cache-hit != 'true'
86+
run: |
87+
set -euo pipefail
88+
base="${{ steps.resolve.outputs.base }}"
89+
file="${{ steps.resolve.outputs.file }}"
90+
version="${{ steps.resolve.outputs.version }}"
91+
mkdir -p "$RUNNER_TEMP/bl"
92+
curl -fSL --retry 3 -o "$RUNNER_TEMP/bl.tar.xz" "${base}${file}"
93+
curl -fsSL --retry 3 -o "$RUNNER_TEMP/bl.sha256" "${base}blender-${version}.sha256"
94+
expected=$(grep -E " ${file}$" "$RUNNER_TEMP/bl.sha256" | awk '{print $1}')
95+
if [ -z "$expected" ]; then
96+
echo "::error::no published sha256 for ${file}"
97+
exit 1
98+
fi
99+
echo "${expected} $RUNNER_TEMP/bl.tar.xz" | sha256sum -c - \
100+
|| { echo "::error::sha256 mismatch for ${file}; refusing to extract"; exit 1; }
101+
tar -xf "$RUNNER_TEMP/bl.tar.xz" -C "$RUNNER_TEMP/bl"
102+
103+
- name: Locate Blender binary
104+
run: |
105+
set -euo pipefail
106+
bl=$(find "$RUNNER_TEMP/bl" -maxdepth 2 -type f -name blender | head -1)
107+
if [ -z "$bl" ]; then
108+
echo "::error::blender binary not found"
109+
exit 1
110+
fi
111+
echo "BLENDER=$bl" >> "$GITHUB_ENV"
112+
"$bl" --version | head -1 | grep -q "Blender ${{ matrix.series }}\." \
113+
|| { echo "::error::version does not match series ${{ matrix.series }}"; exit 1; }
114+
115+
- name: Run every snippet (and its falsifier) and every tagged SKILL.md block
116+
run: |
117+
set -euo pipefail
118+
xvfb-run -a "$BLENDER" --background --factory-startup --python-exit-code 1 \
119+
--python tests/smoke/run_content.py

‎.github/workflows/validate.yml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,9 @@ jobs:
385385
- name: Check skill file references resolve outside a checkout
386386
run: python3 tests/check_skill_refs.py
387387

388+
- name: Check every snippet has a smoke check and falsifier, and every skill python block compiles
389+
run: python3 tests/check_content_catalog.py
390+
388391
validate-counts:
389392
name: Validate content counts
390393
runs-on: ubuntu-latest

‎AGENTS.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ a `.cursor-plugin/plugin.json` manifest so the ecosystem drift checker
2020
classifies it as a `cursor-plugin`. This is content the AI loads when the user
2121
asks Blender questions or works on Blender add-ons in Cursor or Claude Code.
2222

23-
The content base is 20 skills, 12 rules, 3 templates, 31 snippets, 66
23+
The content base is 25 skills, 12 rules, 3 templates, 31 snippets, 66
2424
examples, and 80 showcase pieces (counts are CI-enforced across README.md, the agent docs, ROADMAP.md,
2525
`site.json` and the site templates). The full inventory tables and per-item purposes live in
2626
`CLAUDE.md`. Example anatomy and authoring rules: copy `examples/bmesh-gear/`;
@@ -32,7 +32,7 @@ in `docs/VISUAL-STYLE.md`; the canonical run prompt is
3232

3333
```
3434
Blender-Developer-Tools/
35-
skills/<skill-name>/SKILL.md # 20 skill files
35+
skills/<skill-name>/SKILL.md # 25 skill files
3636
rules/<rule-name>.mdc # 12 rule files
3737
templates/<template-name>/ # 3 starter templates
3838
snippets/<snippet-name>.py # 31 standalone Python snippets

‎CLAUDE.md‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ The **Blender Developer Tools** repository is at **v0.157.0**. It packages skill
1717
## Repository Architecture
1818

1919
```
20-
skills/<skill-name>/SKILL.md - AI workflow definitions, 20 total
20+
skills/<skill-name>/SKILL.md - AI workflow definitions, 25 total
2121
rules/<rule-name>.mdc - Anti-pattern rules, 12 total
2222
templates/<template-name>/ - Starter projects, 3 total
2323
snippets/<snippet-name>.py - Standalone code patterns, 31 total
@@ -30,7 +30,7 @@ docs/gallery/ - Committed generated gallery pages + hero render
3030
VERSION - Source of truth for the repo version
3131
```
3232

33-
## Skills (20)
33+
## Skills (25)
3434

3535
| Skill | Purpose |
3636
| --- | --- |
@@ -54,6 +54,11 @@ VERSION - Source of truth for the repo version
5454
| timers-modal-and-threading | `bpy.app.timers` return values and `persistent`, modal operators on `event_timer_add`, worker thread + queue + main-thread drain, no timers in `--background` |
5555
| porting-to-blender-5 | Index of every 4.x → 5.x break the pack covers (bgl, `action.fcurves`, `use_auto_smooth`, Principled sockets, `.sequences`, ID properties, compositor, NodesModifier inputs, ...), each linked to the skill, rule or example that owns the fix; headless triage recipe |
5656
| gpu-drawing-and-overlays | `gpu` instead of the removed `bgl`: `draw_handler_add`/`remove`, builtin shader names, `gpu.state` blending and depth, `POLYLINE_*` line width, `blf` text, `GPUOffScreen` with 5.2's `gpu.init()` headless |
57+
| grease-pencil-v3 | Grease Pencil v3: `grease_pencils_v3` (4.5) vs `grease_pencils` (5.x), layers/frames/drawings, point attributes, Line Art modifier |
58+
| constraints-and-parenting | `.parent` vs `matrix_parent_inverse`, stale `matrix_world`, constraints via `constraints.new` checked on the evaluated pose, `SKT_*` socket empties |
59+
| images-and-pixels | `Image.pixels` layout and bulk `foreach_*`, byte vs float buffers, colorspace, `save()` vs `save_render()`, PNG vs EXR alpha |
60+
| curves-and-text | Curve and TextCurve datablocks: splines, bevel/extrude closed forms, `body`, Bfont, evaluated mesh read-back |
61+
| compositor-nodes | 4.5 `scene.node_tree` vs 5.x `scene.compositing_node_group`, Glare node enum-to-menu-socket change, `use_compositing` |
5762

5863
## Rules (12)
5964

@@ -197,6 +202,13 @@ The host runner is `tests/smoke/run_example.py`. Shipped examples are listed in
197202
(`tests/check_falsifier_targets.py --run --shard K/4`, four jobs; dispatch
198203
with `sweep: true` to run it by hand), and a red or cancelled weekly run
199204
opens or comments on a "Weekly Blender smoke run failed" issue.
205+
- **Content smoke (#447):** `content-smoke.yml` runs every `snippets/*.py` in place
206+
(its check and falsifier live in `tests/smoke/snippet_checks.py`) and every
207+
SKILL.md ```python block tagged `<!-- smoke: run -->`, via
208+
`tests/smoke/run_content.py`, on 5.2 and 4.5. It has a positive `paths` filter
209+
because blender-smoke ignores `**.md`; `release-gate.sh` waits for it on pushes
210+
touching skills or snippets. Validate's `tests/check_content_catalog.py`
211+
compiles every SKILL.md block and requires a catalog entry per snippet.
200212
- **Summary:** `tests/smoke/summarize.py` prints passed/skipped/failed. Zero
201213
PASSes makes the job red even if every example skipped cleanly. Falsifier
202214
runs are tabled separately and never count toward that PASS.

‎CONTRIBUTING.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ showcase/
101101

102102
3. Aim for 150 to 350 lines covering the canonical pattern, common AI mistakes, version-correctness notes, and one or two worked code examples. Cite Blender API doc URLs where relevant. Avoid encyclopedic API tours.
103103
4. The skill `name` in frontmatter must match the directory name exactly (CI enforces this).
104+
5. Every ```python block must compile (`tests/check_content_catalog.py`). Put `<!-- smoke: run -->` on the line directly above a block that is self-contained, so Content Smoke executes it on 4.5 and 5.2 in a factory-startup scene: no input files, no render, and it ends with `assert`s on what it built. Tag at least one block per skill where the API allows it.
105+
6. Map at least one example to the skill in `examples/skills.json`; an example mapped to no skill fails Validate.
104106

105107
## Adding a Rule
106108

@@ -131,7 +133,7 @@ showcase/
131133

132134
1. Add a `.py` file under `snippets/`, e.g. `snippets/depsgraph-evaluated-mesh.py`.
133135
2. Keep it 5 to 75 lines, fully working code, with a header comment naming the snippet and citing the relevant Blender doc URL or research section.
134-
3. Snippets are validated for Python syntax in CI.
136+
3. Add an entry to `tests/smoke/snippet_checks.py`: a `check` that calls the snippet's functions and asserts one observable fact, and a `falsify` (old, new) source edit that must make the check fail. Content Smoke (`.github/workflows/content-smoke.yml`) runs the snippet in place on 4.5 and 5.2; Validate fails a snippet without an entry. Run it locally with `blender --background --factory-startup --python tests/smoke/run_content.py -- --only <name>`.
135137

136138
## Adding a Template
137139

@@ -292,7 +294,7 @@ The drift-check workflow enforces these on every push and PR.
292294

293295
## Aggregate Counts
294296

295-
`README.md` declares aggregate counts (e.g. "20 skills, 12 rules, 3 templates, 31 snippets, 69 examples, and 80 showcase pieces"). The `validate-counts` job in `.github/workflows/validate.yml` enforces these substrings against the filesystem on every push and PR. Showcase pieces are counted separately from examples. When you add or remove content, update the README counts in the same commit.
297+
`README.md` declares aggregate counts (e.g. "25 skills, 12 rules, 3 templates, 31 snippets, 69 examples, and 80 showcase pieces"). The `validate-counts` job in `.github/workflows/validate.yml` enforces these substrings against the filesystem on every push and PR. Showcase pieces are counted separately from examples. When you add or remove content, update the README counts in the same commit.
296298

297299
## Pull Request Process
298300

‎README.md‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
</p>
2626

2727
<p align="center">
28-
<strong>20 skills</strong> &nbsp;&bull;&nbsp; <strong>12 rules</strong> &nbsp;&bull;&nbsp; <strong>3 templates</strong> &nbsp;&bull;&nbsp; <strong>31 snippets</strong> &nbsp;&bull;&nbsp; <strong>69 examples</strong> &nbsp;&bull;&nbsp; <strong>80 showcase pieces</strong>
28+
<strong>25 skills</strong> &nbsp;&bull;&nbsp; <strong>12 rules</strong> &nbsp;&bull;&nbsp; <strong>3 templates</strong> &nbsp;&bull;&nbsp; <strong>31 snippets</strong> &nbsp;&bull;&nbsp; <strong>69 examples</strong> &nbsp;&bull;&nbsp; <strong>80 showcase pieces</strong>
2929
</p>
3030

3131
<p align="center">
@@ -44,7 +44,7 @@
4444

4545
## Overview
4646

47-
This repository ships **20 skills, 12 rules, 3 templates, 31 snippets, 69 examples, and 80 showcase pieces** for Blender Python development targeting Blender 5.2 LTS (current stable) with Blender 4.5 LTS fallback support. Blender 5.1 is prior stable.
47+
This repository ships **25 skills, 12 rules, 3 templates, 31 snippets, 69 examples, and 80 showcase pieces** for Blender Python development targeting Blender 5.2 LTS (current stable) with Blender 4.5 LTS fallback support. Blender 5.1 is prior stable.
4848

4949
The content is consumed by AI coding agents, installed as a plugin or read from a checkout. An optional second plugin registers the official [Blender Lab MCP server](https://www.blender.org/lab/mcp-server/) for live sessions (see [Live Blender session](#live-blender-session-mcp)); the server is referenced from upstream, not part of this repository, and nothing else depends on it. Cursor and Claude Code both install it as a plugin (see [Quick start](#quick-start)): Cursor loads the skills and applies `rules/*.mdc` wherever their scope globs match; Claude Code loads the skills and gets the rules through a generated `blender-rules` skill, since it does not read Cursor `.mdc` files. An agent picks a skill up when its description matches the task. Any agent that can read files in a workspace can use it the same way. There is no build step for the content — edit the Markdown and Python files directly.
5050

@@ -61,14 +61,14 @@ The content is consumed by AI coding agents, installed as a plugin or read from
6161

6262
Neither agent needs a clone of `main`: both install the slim `plugin-dist` build. Clone the full repository only to [run the examples or contribute](#run-the-examples-or-contribute).
6363

64-
- **Cursor** — install it as a local plugin from the slim `plugin-dist` branch, then run **Developer: Reload Window**. **Customize** lists the 20 skills and 12 rules; the rules apply by glob scope and the agent loads a skill when its description matches the task.
64+
- **Cursor** — install it as a local plugin from the slim `plugin-dist` branch, then run **Developer: Reload Window**. **Customize** lists the 25 skills and 12 rules; the rules apply by glob scope and the agent loads a skill when its description matches the task.
6565

6666
```bash
6767
git clone --branch plugin-dist --single-branch https://github.com/TMHSDigital/Blender-Developer-Tools.git ~/.cursor/plugins/local/blender-developer-tools
6868
```
6969

7070
(On Windows the folder is `%USERPROFILE%\.cursor\plugins\local\`. Cursor skips symlinks that point outside that folder, so clone or copy rather than link.) Teams can import the repository as a team marketplace instead; it carries `.cursor-plugin/marketplace.json`. The plugin already applies the rules, so there is nothing to copy. Only to scope the pack to one project without the plugin, copy `skills/*` into that project's `.cursor/skills/` and `rules/*.mdc` into `.cursor/rules/` from a checkout; copying only the rules gives you no skills.
71-
- **Claude Code** — install as a plugin, then run `/skills` to see all 20 skills plus `blender-rules`:
71+
- **Claude Code** — install as a plugin, then run `/skills` to see all 25 skills plus `blender-rules`:
7272

7373
```text
7474
/plugin marketplace add TMHSDigital/Blender-Developer-Tools@plugin-dist
@@ -188,7 +188,7 @@ Browse both, with filters, full-size renders and each script's README, in the **
188188
## How content is organized
189189

190190
```
191-
skills/<name>/SKILL.md - 20 skill files, YAML frontmatter, one canonical pattern each
191+
skills/<name>/SKILL.md - 25 skill files, YAML frontmatter, one canonical pattern each
192192
rules/<name>.mdc - 12 rule files, anti-pattern + correction
193193
templates/<name>/ - 3 template directories (extension-addon-template, headless-batch-script-template, ai-asset-pipeline-template)
194194
snippets/<name>.py - 31 standalone Python snippets, 5 to 75 lines each

‎ROADMAP.md‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,7 @@
99
The skill, rule and example work planned for what the plugin teaches, separate from the
1010
showcase pool further down. Each item is an open issue; nothing here is pinned to a version.
1111

12-
- **New skills:** teach the API contracts that shipped examples prove but no skill covers yet, such as Grease Pencil v3, the 5.x compositor, constraints and image pixels ([#456](https://github.com/TMHSDigital/Blender-Developer-Tools/issues/456))
13-
- **Skill corrections:** the full Principled BSDF v2 socket rename table in `procedural-materials-and-shaders` ([#382](https://github.com/TMHSDigital/Blender-Developer-Tools/issues/382))
14-
- **Verification:** run the shipped snippets and SKILL.md code blocks in CI instead of frozen copies ([#447](https://github.com/TMHSDigital/Blender-Developer-Tools/issues/447)); a weekly, non-gating smoke run against Blender daily builds to catch API breaks before a release ([#457](https://github.com/TMHSDigital/Blender-Developer-Tools/issues/457))
15-
- **More agents:** first-class support for Codex, Copilot, Windsurf and Gemini through `.agents/skills` and an AGENTS.md rules export ([#376](https://github.com/TMHSDigital/Blender-Developer-Tools/issues/376))
12+
- None open. New items start as issues labelled `skills`, `rules`, `snippets` or `examples`.
1613

1714
## Themes
1815

@@ -40,6 +37,7 @@ derives the actual version from conventional-commit types.
4037
| Removed normals API rule (pre-4.1 auto smooth) | 19 | 11 | 3 | 29 | Shipped |
4138
| Porting index skill (`porting-to-blender-5`) | 20 | 11 | 3 | 29 | Shipped |
4239
| Porting snippets and the legacy VSE `.sequences` rule | 20 | 12 | 3 | 31 | Shipped |
40+
| Skills for stranded examples: Grease Pencil v3, constraints and parenting, images and pixels, curves and text, compositor nodes | 25 | 12 | 3 | 31 | Shipped |
4341
| Live-session bridge (opt-in `blender-live-session` plugin, upstream Blender Lab MCP) | - | - | - | - | Shipped |
4442
| Stable (1.0) | — | — | — | — | Upcoming; criteria below |
4543

0 commit comments

Comments
 (0)