Skip to content

Commit 0663419

Browse files
TMHSDigitalclaude
andcommitted
fix(distribution): move the rules exports out of agents/; check plugin installs in CI
5a56f5e put the AGENTS.md and Copilot exports under agents/. Claude Code loads every agents/*.md in a plugin as a subagent, so the plugin would have shipped a bogus AGENTS subagent. claude plugin validate --strict caught it ("No description in frontmatter ... this agent"). The exports now live in exports/, with a comment in build_plugin_dist.py saying why. The Claude marketplace also gains the metadata.description that --strict asked for. New plugin-install.yml (#497): build plugin-dist, run claude plugin validate --strict on the root plugin, live-session and the marketplace, then install both plugins into a throwaway CLAUDE_CONFIG_DIR and check they are listed. The weekly run also installs from the published plugin-dist branch. Verified locally with Claude Code 2.1.296: all three validate strictly, both plugins install from a fresh dist. Closes #497 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: TM Hospitality Strategies <TMHospitalityStrategies@gmail.com>
1 parent 82d500a commit 0663419

9 files changed

Lines changed: 102 additions & 13 deletions

File tree

‎.claude-plugin/marketplace.json‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
"name": "TMHSDigital",
55
"url": "https://github.com/TMHSDigital"
66
},
7+
"metadata": {
8+
"description": "Blender Python skills and rules for AI agents (blender-developer-tools), plus the opt-in Blender Lab MCP live session (blender-live-session)."
9+
},
710
"plugins": [
811
{
912
"name": "blender-developer-tools",
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
name: Plugin install check
2+
3+
# ROADMAP 1.0 criterion: "Install paths that work and are tested" (#497).
4+
# Builds the plugin-dist tree, validates every manifest with Claude Code's own
5+
# validator in --strict mode, then installs both plugins into a throwaway
6+
# config directory and checks they are listed and enabled. On the weekly run
7+
# it also installs from the published plugin-dist branch, which is what users
8+
# actually add. No account or API key is involved: plugin commands are local.
9+
10+
on:
11+
workflow_dispatch:
12+
schedule:
13+
- cron: "0 10 * * 3" # weekly, Wednesday 10:00 UTC
14+
push:
15+
branches: [main]
16+
paths:
17+
- ".claude-plugin/**"
18+
- ".cursor-plugin/**"
19+
- "live-session/**"
20+
- "skills/**"
21+
- "claude/**"
22+
- "exports/**"
23+
- "scripts/build_plugin_dist.py"
24+
- ".github/workflows/plugin-install.yml"
25+
pull_request:
26+
branches: [main]
27+
paths:
28+
- ".claude-plugin/**"
29+
- ".cursor-plugin/**"
30+
- "live-session/**"
31+
- "skills/**"
32+
- "claude/**"
33+
- "exports/**"
34+
- "scripts/build_plugin_dist.py"
35+
- ".github/workflows/plugin-install.yml"
36+
37+
permissions:
38+
contents: read
39+
40+
jobs:
41+
install:
42+
name: Validate and install the plugins (Claude Code)
43+
runs-on: ubuntu-latest
44+
timeout-minutes: 15
45+
env:
46+
CLAUDE_CODE_VERSION: "2.1.296"
47+
steps:
48+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
49+
50+
- name: Install the Claude Code CLI (pinned)
51+
run: npm install -g "@anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}"
52+
53+
- name: Build plugin-dist and validate it strictly
54+
run: |
55+
set -euo pipefail
56+
python3 scripts/build_plugin_dist.py --out "$RUNNER_TEMP/dist"
57+
for target in "$RUNNER_TEMP/dist" "$RUNNER_TEMP/dist/live-session" \
58+
"$RUNNER_TEMP/dist/.claude-plugin/marketplace.json"; do
59+
claude plugin validate --strict "$target"
60+
done
61+
62+
- name: Install both plugins from the build into a clean profile
63+
env:
64+
CLAUDE_CONFIG_DIR: ${{ runner.temp }}/claude-cfg-local
65+
run: |
66+
set -euo pipefail
67+
claude plugin marketplace add "$RUNNER_TEMP/dist"
68+
claude plugin install blender-developer-tools@blender-developer-tools
69+
claude plugin install blender-live-session@blender-developer-tools
70+
list=$(claude plugin list)
71+
echo "$list"
72+
for p in blender-developer-tools@blender-developer-tools blender-live-session@blender-developer-tools; do
73+
echo "$list" | grep -qF "$p" || { echo "::error::$p is not listed after install"; exit 1; }
74+
done
75+
76+
- name: Install from the published plugin-dist branch (weekly)
77+
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
78+
env:
79+
CLAUDE_CONFIG_DIR: ${{ runner.temp }}/claude-cfg-published
80+
run: |
81+
set -euo pipefail
82+
claude plugin marketplace add "TMHSDigital/Blender-Developer-Tools@plugin-dist"
83+
claude plugin install blender-developer-tools@blender-developer-tools
84+
claude plugin install blender-live-session@blender-developer-tools
85+
claude plugin list

‎.github/workflows/validate.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ jobs:
364364
exit 1
365365
fi
366366
367-
- name: Check the rules exports (claude/, agents/AGENTS.md, Copilot instructions) are regenerated from rules/*.mdc
367+
- name: Check the rules exports (claude/, exports/AGENTS.md, Copilot instructions) are regenerated from rules/*.mdc
368368
run: python3 scripts/build_claude_rules.py --check
369369

370370
- name: Check examples/index.json and each skill's Runnable examples section are regenerated

‎README.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,12 @@ Neither agent needs a clone of `main`: both install the slim `plugin-dist` build
8585
# Skills: agents that read .agents/skills/ (Codex, Cursor project skills)
8686
mkdir -p .agents/skills && cp -r bdt/skills/* .agents/skills/
8787
# Rules: agents that read AGENTS.md (Codex, Windsurf, Gemini CLI, Copilot's coding agent)
88-
cat bdt/agents/AGENTS.md >> AGENTS.md
88+
cat bdt/exports/AGENTS.md >> AGENTS.md
8989
# Rules: GitHub Copilot path-scoped instructions (applies to **/*.py)
90-
mkdir -p .github/instructions && cp bdt/agents/copilot/blender-python.instructions.md .github/instructions/
90+
mkdir -p .github/instructions && cp bdt/exports/copilot/blender-python.instructions.md .github/instructions/
9191
```
9292

93-
`agents/AGENTS.md` and the Copilot file are generated from `rules/` by `scripts/build_claude_rules.py`, and CI fails if they fall out of date. The plugin-dist build fails if either file is missing. The layouts follow each agent's documented conventions; CI does not run the agents themselves.
93+
`exports/AGENTS.md` and the Copilot file are generated from `rules/` by `scripts/build_claude_rules.py`, and CI fails if they fall out of date. The plugin-dist build fails if either file is missing. The layouts follow each agent's documented conventions; CI does not run the agents themselves.
9494

9595
### Live Blender session (MCP)
9696

File renamed without changes.
File renamed without changes.

‎scripts/build_claude_rules.py‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
second clone; Claude loads it when writing or reviewing bpy code.
1111
- claude/blender-rules.md: for always-on use, imported from a project's
1212
CLAUDE.md with ``@path/to/Blender-Developer-Tools/claude/blender-rules.md``.
13-
- agents/AGENTS.md: for agents that read AGENTS.md (Codex, Windsurf, Gemini
13+
- exports/AGENTS.md: for agents that read AGENTS.md (Codex, Windsurf, Gemini
1414
CLI, Copilot's coding agent); append it to a project's AGENTS.md (#376).
15-
- agents/copilot/blender-python.instructions.md: a GitHub Copilot path-scoped
15+
- exports/copilot/blender-python.instructions.md: a GitHub Copilot path-scoped
1616
instructions file (``applyTo: "**/*.py"``, the rules' own scope) for a
1717
project's .github/instructions/.
1818
@@ -32,8 +32,8 @@
3232
REPO = Path(__file__).resolve().parent.parent
3333
OUT = REPO / "claude" / "blender-rules.md"
3434
SKILL_OUT = REPO / "claude" / "skills" / "blender-rules" / "SKILL.md"
35-
AGENTS_OUT = REPO / "agents" / "AGENTS.md"
36-
COPILOT_OUT = REPO / "agents" / "copilot" / "blender-python.instructions.md"
35+
AGENTS_OUT = REPO / "exports" / "AGENTS.md"
36+
COPILOT_OUT = REPO / "exports" / "copilot" / "blender-python.instructions.md"
3737
COPILOT_FRONT = """---
3838
applyTo: "**/*.py"
3939
---
@@ -102,7 +102,7 @@ def main() -> int:
102102
print(f"{', '.join(stale)} stale; run python scripts/build_claude_rules.py",
103103
file=sys.stderr)
104104
return 1
105-
print("rules exports (claude/, agents/AGENTS.md, agents/copilot/) are up to date")
105+
print("rules exports (claude/, exports/AGENTS.md, exports/copilot/) are up to date")
106106
return 0
107107
for path, new in outputs().items():
108108
path.parent.mkdir(parents=True, exist_ok=True)

‎scripts/build_plugin_dist.py‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
# the Blender Lab MCP server (launched with uvx from a pinned upstream commit;
3636
# GPL, so referenced, never vendored) and its skill. It is opt-in, so the core
3737
# plugin starts no server (#483).
38-
DIRS = ("skills", "claude", "agents", "rules", "snippets", "templates", "live-session")
38+
DIRS = ("skills", "claude", "exports", "rules", "snippets", "templates", "live-session")
3939
# The Cursor manifest ships too, so Cursor users can install the same slim
4040
# tree as a local plugin (~/.cursor/plugins/local/) instead of the full repo.
4141
# assets/favicon.svg is the Cursor manifest's "logo".
@@ -168,8 +168,9 @@ def verify(out: Path, size: int) -> list[str]:
168168
errors.append(f"{d.relative_to(out)} has no SKILL.md")
169169
if not (out / "claude" / "skills" / "blender-rules" / "SKILL.md").is_file():
170170
errors.append("blender-rules skill missing")
171-
# The README's "Other agents" commands copy these (#376).
172-
for rel in ("agents/AGENTS.md", "agents/copilot/blender-python.instructions.md"):
171+
# The README's "Other agents" commands copy these (#376). Not agents/:
172+
# Claude Code would load every agents/*.md in the plugin as a subagent.
173+
for rel in ("exports/AGENTS.md", "exports/copilot/blender-python.instructions.md"):
173174
if not (out / rel).is_file():
174175
errors.append(f"{rel} missing (the README's other-agents commands copy it)")
175176
cursor = json.loads((out / ".cursor-plugin" / "plugin.json").read_text(encoding="utf-8"))

‎site.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"installSteps": [
2121
"<strong>Claude Code:</strong> <code>/plugin marketplace add TMHSDigital/Blender-Developer-Tools@plugin-dist</code> then <code>/plugin install blender-developer-tools@blender-developer-tools</code>. The 20 skills load when a task matches; the rules come along as the <code>blender-rules</code> skill",
2222
"<strong>Cursor:</strong> <code>git clone --branch plugin-dist --single-branch https://github.com/TMHSDigital/Blender-Developer-Tools.git ~/.cursor/plugins/local/blender-developer-tools</code>, then reload the window; Customize lists the 20 skills and 11 rules, and the plugin applies the rules for you. This clones only the 0.3 MB plugin build, not <code>main</code>",
23-
"<strong>Other agents (Codex, Copilot, Windsurf):</strong> clone the same slim build (<code>git clone --branch plugin-dist --single-branch https://github.com/TMHSDigital/Blender-Developer-Tools.git</code>) and copy its <code>skills/*</code> into <code>.agents/skills/</code>, append <code>agents/AGENTS.md</code> to your project's <code>AGENTS.md</code> for the rules, and for Copilot copy <code>agents/copilot/blender-python.instructions.md</code> into <code>.github/instructions/</code>",
23+
"<strong>Other agents (Codex, Copilot, Windsurf):</strong> clone the same slim build (<code>git clone --branch plugin-dist --single-branch https://github.com/TMHSDigital/Blender-Developer-Tools.git</code>) and copy its <code>skills/*</code> into <code>.agents/skills/</code>, append <code>exports/AGENTS.md</code> to your project's <code>AGENTS.md</code> for the rules, and for Copilot copy <code>exports/copilot/blender-python.instructions.md</code> into <code>.github/instructions/</code>",
2424
"<strong>Optional, live session:</strong> <code>/plugin install blender-live-session@blender-developer-tools</code> adds the official Blender Lab MCP server (needs <code>uv</code> and Blender 5.1+ with its add-on) so the agent can inspect and drive your open scene, plus a skill that has it read before it mutates and prove changes headless. See the README's <a href=\"https://github.com/TMHSDigital/Blender-Developer-Tools#live-blender-session-mcp\">Live Blender session</a>",
2525
"Grab <code>snippets/</code> and <code>templates/</code> as starting points for add-ons and headless batch jobs"
2626
],

0 commit comments

Comments
 (0)