Skip to content

Commit 25bfcbc

Browse files
TMHSDigitalclaude
andcommitted
docs: add repository technical audit and roadmap
Adds docs/technical-audit.md capturing the architecture map, gap analysis, 3-stage roadmap, and the five issues filed as #28-#32. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent f70a286 commit 25bfcbc

1 file changed

Lines changed: 270 additions & 0 deletions

File tree

docs/technical-audit.md

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
# Blender Developer Tools — Technical Audit & Roadmap
2+
3+
_Audit date: 2026-06-20 · Repo @ v0.5.0 · Auditor: Principal Eng review_
4+
5+
## 0. Important reframing
6+
7+
The audit brief assumed a runnable add-on (operators, UI panels, a socket/file-watcher
8+
execution model). **That is not what this repo is.** This is a **content / knowledge-pack
9+
repository** — an AI "skill pack" of `SKILL.md` workflows, `.mdc` anti-pattern rules, copy-paste
10+
`snippets/`, starter `templates/`, and self-verifying `examples/` consumed by Cursor and Claude
11+
Code. The only executable code is (a) the templates/examples/snippets, which are *teaching
12+
artifacts*, and (b) the CI tooling (`tests/smoke/`, `scripts/build_gallery.py`).
13+
14+
So "core operator logic" and "UI panels" exist only as *demonstration* code in
15+
`templates/extension-addon-template/__init__.py` and the example scripts. The architectural
16+
gaps that matter are about **content correctness, validation coverage, and distribution**, not
17+
runtime robustness of a live tool.
18+
19+
## 1. Architecture map
20+
21+
| Layer | What it is | Notable detail |
22+
| --- | --- | --- |
23+
| `skills/` (12) | Markdown workflows w/ YAML frontmatter | `name` must match dir; `standards-version` gated in CI |
24+
| `rules/` (6) | `.mdc` anti-pattern rules | `alwaysApply` / scope globs for Cursor |
25+
| `snippets/` (17) | Standalone `.py` patterns | `py_compile`-checked only |
26+
| `templates/` (2) | extension add-on + headless batch | real, registerable add-on code |
27+
| `examples/` (4) | self-verifying demo scripts | run inside real Blender in CI, exit non-zero on failure |
28+
| `tests/smoke/` | headless Blender harness | **already exists** — runs on 5.1 + 4.5 matrix |
29+
| `scripts/build_gallery.py` | stdlib HTML generator | builds `docs/gallery/` Pages site |
30+
| `.github/workflows/` | 8 workflows | validate, blender-smoke, drift-check, release, pages, label-sync, stale, dependabot |
31+
| `.cursor-plugin/plugin.json` | distribution manifest | **stale: v0.2.3, missing arrays** |
32+
33+
**Architectural style:** static content pack + automated content-integrity CI. Distribution is
34+
"copy `skills/`+`rules/` into the workspace" or reference the checkout directly. **No MCP server**
35+
(explicitly noted in CLAUDE.md/AGENTS.md).
36+
37+
**Genuine strengths** (the brief assumed these were missing — they are not):
38+
- A real **headless Blender testing harness** already exists. `tests/smoke/run_smoke.py` asserts
39+
*content*, not just "no exception" (e.g. EEVEE engine-id polarity, slotted-actions boundary,
40+
driver `id_type` fix, SDF `GridToMesh` link validity, render-non-black). It deliberately
41+
**copies** content rather than importing it, to catch drift in shipped files.
42+
- `blender-smoke.yml` runs that harness on both the current stable and active LTS, plus runs the
43+
shipped templates and examples end-to-end (glTF magic-bytes check, exit-code-2 no-mesh path).
44+
- Conventional-commit-driven release automation with doc-sync; count-integrity gate in CI.
45+
46+
## 2. Gap analysis
47+
48+
### G1 — Distribution manifest drift (concrete bug)
49+
`.cursor-plugin/plugin.json` is frozen at `version: 0.2.3`, enumerates only `skills` (12) and
50+
`rules` (6), and has **no `snippets`, `templates`, or `examples` arrays**. Nothing in
51+
`validate.yml` checks the manifest against the filesystem, so it rotted silently while the repo
52+
reached v0.5.0. Consumers reading the manifest see a v0.2.0-era subset.
53+
54+
### G2 — Validation coverage holes
55+
`validate.yml` enforces structure, frontmatter, name=dir, `py_compile`, and README counts. It does
56+
**not**: (a) lint/run snippets beyond byte-compilation (no Blender import, no `ruff`); (b) verify
57+
every snippet/skill/template is referenced from README/ROADMAP/manifest (orphan detection);
58+
(c) check internal/external doc links; (d) validate `gallery.json` against the on-disk examples.
59+
The smoke harness covers a hand-picked subset, so a *new* snippet can ship un-exercised.
60+
61+
### G3 — Smoke harness selectivity (silent coverage cap)
62+
The harness exercises ~6 headline behaviors and 4 examples. 17 snippets + 12 skills are largely
63+
un-run. There is no manifest of "what is covered vs. not," so coverage erosion is invisible — a
64+
classic silent-truncation smell. No per-snippet smoke and no coverage report.
65+
66+
### G4 — No MCP / programmatic surface
67+
The brief's strongest forward-looking point. Today content is human/AI-read-only. There is no
68+
Model Context Protocol server exposing skills/rules/snippets as retrievable resources or tools
69+
(e.g. `get_skill`, `search_patterns`, `lint_blender_py`). This is the natural next-gen evolution
70+
and the cleanest way to make the pack first-class in MCP-aware clients beyond Cursor/Claude Code.
71+
72+
### G5 — Performance/dense-data guidance is pattern-level only
73+
Rules flag `bpy.ops`-in-loops and per-element loops, and snippets show `foreach_set/get`. But
74+
there is no skill on **profiling / scaling to dense meshes** (e.g. numpy buffer interop,
75+
`foreach_get` into preallocated numpy arrays, attribute-domain bulk ops, depsgraph cost). For a
76+
tool whose whole pitch is "do bulk work the fast way," this is a content gap.
77+
78+
### G6 — LTS/version sweep is manual and unpinned
79+
5.2 LTS lands ~mid-2026. The smoke matrix hard-codes `5.1`/`4.5`. There is no scheduled job to
80+
detect a new stable/LTS series and open a sweep issue, so the "5.2 sweep" depends on a human
81+
remembering.
82+
83+
## 3. Roadmap
84+
85+
### Stage 1 — Short-term / Quick Wins (days)
86+
- **Fix + gate the Cursor manifest** (G1). Regenerate `plugin.json` from the filesystem and add a
87+
CI check so it can't drift again.
88+
- **Orphan + link audit job** (G2). Fail CI if any snippet/skill/template/example is unreferenced
89+
by README/ROADMAP/manifest, or if a markdown link 404s.
90+
- **`gallery.json` ↔ disk validator** (G2). Assert every example dir + hero image referenced
91+
exists and vice-versa.
92+
- **Coverage manifest for smoke** (G3). Emit a printed "covered / not covered" table so gaps are
93+
visible in the CI log.
94+
95+
### Stage 2 — Mid-term / Core Enhancements (weeks)
96+
- **Per-snippet smoke harness** (G3): a generic runner that imports/execs each snippet in headless
97+
Blender behind a small `# smoke: skip` opt-out, closing the un-run-content gap.
98+
- **`ruff` + import-time lint** of all Python content with a Blender-aware config.
99+
- **New skill: `performance-and-dense-data`** (G5) — numpy `foreach_get`/`foreach_set` buffers,
100+
attribute domains, when bmesh beats data API, profiling with `time`/`cProfile` headless.
101+
- **New skills from the committed pool**: `modal-operators`, `mathutils-patterns`, `usd-pipelines`.
102+
- **Automated LTS-series watcher** (G6): scheduled job that diffs `download.blender.org` series
103+
against the matrix and opens a sweep issue.
104+
105+
### Stage 3 — Long-term / Next-Gen Capabilities (quarters)
106+
- **MCP server** (G4) exposing the pack as MCP resources + tools: `list_skills`, `get_skill`,
107+
`search_patterns`, and a `lint_blender_python` tool wrapping the `.mdc` rules as executable
108+
checks. Ships as an optional adjacent package so the content repo stays a pure pack.
109+
- **Rules-as-linter**: compile the 6 `.mdc` anti-patterns into an actual AST linter
110+
(`libcst`/`ast`) that runs in CI and is reusable by the MCP `lint` tool and by consumers.
111+
- **5.2 LTS parity sweep** once released; bump templates' `blender_version_min` where 5.2 APIs are
112+
used.
113+
- **Fleet Pages examples support** (already in ROADMAP) — lift `gallery.json` into the shared
114+
template, retire the local generator.
115+
116+
---
117+
118+
## 4. GitHub Issues (copy-paste ready)
119+
120+
### Issue 1 — Fix and CI-gate the stale `.cursor-plugin/plugin.json` manifest
121+
122+
**Labels:** `bug`, `ci`, `distribution`
123+
124+
**Context / Problem Statement**
125+
`.cursor-plugin/plugin.json` is pinned at `"version": "0.2.3"` while the repo is at v0.5.0
126+
(`VERSION`). It lists only the `skills` (12) and `rules` (6) arrays and omits `snippets`,
127+
`templates`, and `examples` entirely. No job in `.github/workflows/validate.yml` checks the
128+
manifest against the filesystem, so it has drifted silently. Consumers that read the manifest see a
129+
v0.2.0-era view of the pack.
130+
131+
**Proposed Solution / Implementation Steps**
132+
1. Decide the manifest schema for `snippets`/`templates`/`examples` (mirror the existing
133+
relative-path-array style used for `skills`/`rules`). If the upstream `cursor-plugin` schema
134+
only supports skills+rules, document that and instead just fix `version` + add the gate.
135+
2. Update `.cursor-plugin/plugin.json`: bump `version` to match `VERSION`, and add the missing
136+
arrays enumerating files under `snippets/`, `templates/`, `examples/`.
137+
3. Add a `validate-manifest` job to `validate.yml` (a `python3` heredoc like the existing
138+
`validate-counts` job) that:
139+
- loads `plugin.json`,
140+
- asserts every path in each array exists on disk,
141+
- asserts every `skills/*/SKILL.md` and `rules/*.mdc` on disk is present in the manifest,
142+
- asserts `plugin.json` `version` equals `VERSION` (or is intentionally decoupled — pick one and
143+
enforce it).
144+
4. If `version` should track releases, add it to the `release-doc-sync` owned-lines list so the
145+
release pipeline rewrites it; otherwise document why it is independent in `AGENTS.md`.
146+
147+
**Definition of Done**
148+
- [ ] `plugin.json` enumerates all current skills, rules, snippets, templates, examples.
149+
- [ ] `plugin.json` `version` reconciled with `VERSION` (synced or documented as independent).
150+
- [ ] New CI job fails on any manifest↔filesystem mismatch (proven by a deliberately broken commit).
151+
- [ ] `AGENTS.md` "CI/CD workflows" section documents the new job.
152+
153+
---
154+
155+
### Issue 2 — Add orphan-content and dead-link validation to CI
156+
157+
**Labels:** `ci`, `content-integrity`
158+
159+
**Context / Problem Statement**
160+
`validate.yml` checks structure, frontmatter, name=dir, `py_compile`, and README aggregate counts,
161+
but nothing detects a snippet/skill/template/example that ships **without being referenced** by
162+
`README.md`, `ROADMAP.md`, or the manifest, nor does anything catch broken markdown links. New
163+
content can land orphaned (discoverable only by directory listing), and doc links can rot.
164+
165+
**Proposed Solution / Implementation Steps**
166+
1. Add an `orphan-check` job to `validate.yml`: enumerate files under `snippets/`, `skills/`,
167+
`templates/`, `examples/`; for each, grep `README.md` + `ROADMAP.md` for its name; fail listing
168+
any unreferenced item.
169+
2. Add a lightweight link check: collect markdown links from `*.md`, validate that relative targets
170+
exist on disk; optionally check external `https://` links with a `--allow-fail` soft mode to
171+
avoid flakiness (or gate external checks behind the weekly `schedule`, not PRs).
172+
3. Keep it stdlib-only (consistent with `build_gallery.py`) so no new CI deps are needed.
173+
174+
**Definition of Done**
175+
- [ ] CI fails when a snippet/skill/template/example is unreferenced in README/ROADMAP.
176+
- [ ] CI fails on a broken **relative** markdown link.
177+
- [ ] External link checks run on the weekly schedule, not on every PR (no PR flakiness).
178+
- [ ] A deliberately orphaned test file proves the gate fires, then is removed.
179+
180+
---
181+
182+
### Issue 3 — Generalize the smoke harness to per-snippet coverage + emit a coverage table
183+
184+
**Labels:** `testing`, `enhancement`
185+
186+
**Context / Problem Statement**
187+
`tests/smoke/run_smoke.py` is excellent but exercises only ~6 hand-picked headline behaviors and
188+
`blender-smoke.yml` runs 4 examples. The 17 snippets and 12 skills are largely **un-run** in real
189+
Blender, and there is no record of what is covered. A new snippet can ship having only passed
190+
`py_compile`, and coverage can erode invisibly (silent-truncation risk).
191+
192+
**Proposed Solution / Implementation Steps**
193+
1. Add `tests/smoke/run_snippets.py`: iterate `snippets/*.py`, `exec` each inside a `reset()`
194+
factory-empty scene in headless Blender, treating any raised exception as failure (mirror the
195+
try/except wrapper already in `run_smoke.py`).
196+
2. Support a `# smoke: skip <reason>` first-line pragma for snippets that need scene state they
197+
can't self-provide; **print the skipped list** so skips are visible, never silent.
198+
3. Emit a coverage table at the end: `N snippets run, M skipped (reasons), K skills with a smoke
199+
check`. Print it to the CI log.
200+
4. Wire a new step into `blender-smoke.yml` after the existing smoke driver, on the same 5.1/4.5
201+
matrix, `xvfb-run`-wrapped.
202+
203+
**Definition of Done**
204+
- [ ] Every snippet is either executed in headless Blender or explicitly `# smoke: skip`-ged with a
205+
reason.
206+
- [ ] CI log prints a run/skip/coverage summary table.
207+
- [ ] A snippet that raises in Blender fails the job (proven once).
208+
- [ ] Runs green on both 5.1 and 4.5 matrix legs.
209+
210+
---
211+
212+
### Issue 4 — New skill: `performance-and-dense-data` (numpy buffer interop + profiling)
213+
214+
**Labels:** `content`, `skill`
215+
216+
**Context / Problem Statement**
217+
The pack's core thesis is "do bulk Blender work the fast way," and rules
218+
(`prefer-data-over-ops-in-loops`, `use-foreach-set-for-bulk-data`) plus the `foreach-*` snippets
219+
point that direction. But there is **no skill** that teaches scaling to dense meshes: numpy
220+
buffer interop with `foreach_get`/`foreach_set`, attribute-domain bulk operations, the
221+
bmesh-vs-data-API decision under load, and how to profile headless. AI agents currently get the
222+
"don't do it slow" rules without a positive "here is the fast, measured pattern" skill.
223+
224+
**Proposed Solution / Implementation Steps**
225+
1. Create `skills/performance-and-dense-data/SKILL.md` with the standard YAML frontmatter
226+
(`name: performance-and-dense-data`, one-line `description`, `standards-version: 1.10.0`).
227+
2. Cover: preallocated `numpy` arrays with `foreach_get`/`foreach_set` (`np.empty(n*3)`), reshaping
228+
conventions, attribute API bulk read/write across domains, when bmesh wins, and a headless
229+
`cProfile`/`time.perf_counter` measurement pattern. Show 5.1 and 4.5 paths where they diverge.
230+
3. Add 1–2 supporting snippets (e.g. `numpy-foreach-vertices.py`) and a self-verifying assertion in
231+
the smoke harness (roundtrip equality + a coarse timing sanity check).
232+
4. Update `README.md` aggregate counts, `ROADMAP.md` candidate pool, `AGENTS.md`, and
233+
`plugin.json`; commit with `feat:`.
234+
235+
**Definition of Done**
236+
- [ ] New skill passes frontmatter + name=dir CI checks.
237+
- [ ] Shows numpy buffer interop and at least one profiling pattern, with 4.5/5.1 branches where
238+
relevant.
239+
- [ ] Supporting snippet(s) added and smoke-exercised.
240+
- [ ] README counts, ROADMAP, AGENTS, and manifest updated (counts gate green).
241+
242+
---
243+
244+
### Issue 5 — Prototype an MCP server exposing the pack as resources + a Blender-Python lint tool
245+
246+
**Labels:** `enhancement`, `mcp`, `next-gen`
247+
248+
**Context / Problem Statement**
249+
CLAUDE.md and AGENTS.md both note "there is no MCP server." Today the content is consumable only by
250+
clients that natively read `skills/`+`rules/` (Cursor, Claude Code). An MCP server would make the
251+
pack first-class in any MCP-aware client and turn the 6 `.mdc` anti-pattern rules into an
252+
executable lint tool — a far stronger guarantee than prose rules.
253+
254+
**Proposed Solution / Implementation Steps**
255+
1. Add an **optional adjacent** package (e.g. `mcp-server/`) so the content repo stays a pure pack;
256+
the server reads `skills/`, `rules/`, `snippets/` from the repo at runtime.
257+
2. Expose MCP **resources**: `list_skills`, `get_skill(name)`, `list_snippets`, `get_snippet(name)`,
258+
`search_patterns(query)`.
259+
3. Expose an MCP **tool** `lint_blender_python(source)` implementing the rules as AST checks:
260+
`bpy.ops.*` inside loops, `bmesh.new()` without paired `free()`, prop assignment vs annotation,
261+
`bpy.context.copy()` override, per-element bulk loops. Reuse this checker in CI (see the
262+
rules-as-linter long-term item).
263+
4. Document install/usage in a `mcp-server/README.md`; keep it out of the count/validate gates
264+
(it's tooling, not pack content) but add its own minimal test job.
265+
266+
**Definition of Done**
267+
- [ ] MCP server lists and serves skills/rules/snippets as resources.
268+
- [ ] `lint_blender_python` flags all 6 anti-patterns on a fixture file and passes clean code.
269+
- [ ] Server runs against the live repo checkout with documented setup.
270+
- [ ] CI runs the server's own tests without touching the content-count gates.

0 commit comments

Comments
 (0)