From 55f9bb46c9ab9e2fc7e57989c4f8801b7035b363 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Mon, 23 Mar 2026 08:56:02 -0700 Subject: [PATCH] fix: install skills at top-level .claude/skills/ for CI discovery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Claude Code discovers project skills from .claude/skills//SKILL.md at the top level only. Nesting under .claude/skills/gstack// caused Claude to see only one "gstack" skill instead of individual skills like /ship, /qa, /review. This explains 10/11 routing failures in CI — Claude invoked "gstack" or used Bash directly instead of routing to specific skills. Also adds workflow_dispatch trigger and --user runner container option. Co-Authored-By: Claude Opus 4.6 (1M context) --- test/skill-routing-e2e.test.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/skill-routing-e2e.test.ts b/test/skill-routing-e2e.test.ts index e55894a4..fae9d1a7 100644 --- a/test/skill-routing-e2e.test.ts +++ b/test/skill-routing-e2e.test.ts @@ -59,8 +59,12 @@ function installSkills(tmpDir: string) { const srcPath = path.join(ROOT, skill, 'SKILL.md'); if (!fs.existsSync(srcPath)) continue; + // Install skills at TOP level of .claude/skills/ so Claude Code discovers + // each as a separate invocable skill. Nesting under .claude/skills/gstack/ + // only works for personal skills (~/.claude/skills/) — project-level skills + // need to be top-level for discovery. const destDir = skill - ? path.join(tmpDir, '.claude', 'skills', 'gstack', skill) + ? path.join(tmpDir, '.claude', 'skills', skill) : path.join(tmpDir, '.claude', 'skills', 'gstack'); fs.mkdirSync(destDir, { recursive: true }); fs.copyFileSync(srcPath, path.join(destDir, 'SKILL.md'));