diff --git a/harness/pstack/claude-code/skills/make-bot-ui/SKILL.md b/harness/pstack/claude-code/skills/make-bot-ui/SKILL.md index 4688ff45f..7f05b0504 100644 --- a/harness/pstack/claude-code/skills/make-bot-ui/SKILL.md +++ b/harness/pstack/claude-code/skills/make-bot-ui/SKILL.md @@ -1,5 +1,5 @@ --- -name: Make Bot UI +name: make-bot-ui description: >- Use when building a custom UI (page, dashboard, buttons) that should wake a Grok Bot over a webhook, when the user must provide a webhook sender key, or diff --git a/harness/pstack/claude-code/skills/poteto-mode/SKILL.md b/harness/pstack/claude-code/skills/poteto-mode/SKILL.md index 717dff62d..1bb3884a5 100644 --- a/harness/pstack/claude-code/skills/poteto-mode/SKILL.md +++ b/harness/pstack/claude-code/skills/poteto-mode/SKILL.md @@ -1,5 +1,5 @@ --- -name: Poteto Mode +name: poteto-mode description: poteto's agent style for concise, detailed responses, deliberate subagents, unslopped prose, simple code, and verified work. Use for poteto, /poteto-mode, or requests to work in this style. disable-model-invocation: true icon: crown diff --git a/pstack/skills/make-bot-ui/SKILL.md b/pstack/skills/make-bot-ui/SKILL.md index 285df7569..446342ca3 100644 --- a/pstack/skills/make-bot-ui/SKILL.md +++ b/pstack/skills/make-bot-ui/SKILL.md @@ -1,5 +1,5 @@ --- -name: Make Bot UI +name: make-bot-ui description: >- Use when building a custom UI (page, dashboard, buttons) that should wake a Grok Bot over a webhook, when the user must provide a webhook sender key, or diff --git a/pstack/skills/poteto-mode/SKILL.md b/pstack/skills/poteto-mode/SKILL.md index 9295b7e4f..21993f546 100644 --- a/pstack/skills/poteto-mode/SKILL.md +++ b/pstack/skills/poteto-mode/SKILL.md @@ -1,5 +1,5 @@ --- -name: Poteto Mode +name: poteto-mode description: poteto's agent style for concise, detailed responses, deliberate subagents, unslopped prose, simple code, and verified work. Use for poteto, /poteto-mode, or requests to work in this style. disable-model-invocation: true icon: crown diff --git a/scripts/generate-pstack-harness-trees.mjs b/scripts/generate-pstack-harness-trees.mjs index 691116d74..a3ae88e7f 100644 --- a/scripts/generate-pstack-harness-trees.mjs +++ b/scripts/generate-pstack-harness-trees.mjs @@ -49,6 +49,7 @@ const TERMS = [ { key: "Cursor-only features", re: /Bugbot|Cursor [Aa]utomation|cursor\.(sh|com)\/automations|[Cc]loud [Aa]gent/ }, ]; const ROUTE_KEY = "Run another pstack skill"; +const SKILL_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/; function walk(dir) { return readdirSync(dir).flatMap((name) => { @@ -88,6 +89,11 @@ const users = new Map(); for (const [skill, { usesCursorNames, wrap }] of classes) { if (usesCursorNames.size > 0 && !wrap) problems.push(`skills/${skill}/SKILL.md uses Cursor names but has no H1`); for (const key of usesCursorNames) users.set(key, [...(users.get(key) ?? []), skill]); + // Cursor runs a skill by its folder name and Claude Code lists it by its frontmatter `name`, so the two must match. The Agent Skills spec limits both to SKILL_NAME. + const frontmatter = readFileSync(join(SKILLS, skill, "SKILL.md"), "utf8").match(/^---\n([\s\S]*?)\n---/)?.[1] ?? ""; + const name = frontmatter.match(/^name:(.*)$/m)?.[1].trim().replace(/^(["'])(.*)\1$/, "$2"); + if (name !== skill) problems.push(`skills/${skill}/SKILL.md has name ${JSON.stringify(name ?? "")}, not its folder name ${skill}`); + if (!SKILL_NAME.test(skill) || skill.length > 64) problems.push(`skills/${skill} is not lowercase words joined by hyphens, at most 64 characters`); } const adapter = readFileSync(join(PSTACK, ADAPTER), "utf8"); for (const [key, using] of users) {