diff --git a/.github/workflows/scaffold-e2e.yml b/.github/workflows/scaffold-e2e.yml
index 1859cb050de..8f24a997a50 100644
--- a/.github/workflows/scaffold-e2e.yml
+++ b/.github/workflows/scaffold-e2e.yml
@@ -248,11 +248,23 @@ jobs:
# 2. Interactive `skills add …/framework` (no --all) relies on
# metadata.internal hiding — assert repo-root discovery surfaces
# exactly the curated set and nothing internal.
+ # The curated catalog is every skills/
/ holding a SKILL.md — the
+ # same tree @objectstack/skills ships whole (packages/skills/scripts/
+ # sync-catalog.mjs), read the same way as the package-catalog step
+ # below. ⛔ Never a name glob or an allow-list here: a skill added to
+ # skills/ would red this step until a governed edit of this file.
+ # An internal skill placed in skills/ still fails: the CLI hides
+ # metadata.internal skills, so the installed set (assertion 1) or the
+ # listed count (assertion 2) falls short of the directory set.
run: |
cd "$RUNNER_TEMP"
node "$GITHUB_WORKSPACE/packages/create-objectstack/bin/create-objectstack.js" skills-probe --skip-install --skip-skills
cd skills-probe
- expected=$(cd "$GITHUB_WORKSPACE/skills" && ls -d objectstack-*/ | tr -d '/' | sort)
+ expected=$(for d in "$GITHUB_WORKSPACE"/skills/*/; do if [ -f "${d}SKILL.md" ]; then basename "$d"; fi; done | sort)
+ if [ -z "$expected" ]; then
+ echo "::error::skills/ holds no /SKILL.md — the curated catalog this step compares against is empty"
+ exit 1
+ fi
expected_count=$(echo "$expected" | wc -l | tr -d ' ')
npx -y skills add "$GITHUB_WORKSPACE/skills" --all --copy