From 9089acdea761478a31465439c3127dcdbad87b33 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 17 Oct 2026 22:30:14 +0000 Subject: [PATCH 1/2] fix(pstack): fail the harness generator when a skill name is not its folder Cursor runs a skill by its folder name. Claude Code lists it by its frontmatter `name`, so a skill named `Poteto Mode` shows up as `/pstack:Poteto Mode`, which parses as the unknown command `/pstack:Poteto`. The Agent Skills spec requires the two to match and limits them to lowercase words joined by hyphens, at most 64 characters. The generator now fails on any pstack skill that breaks that rule. CI runs it with --check. This commit fails on `make-bot-ui` and `poteto-mode`; the next commit renames them. --- scripts/generate-pstack-harness-trees.mjs | 6 ++++++ 1 file changed, 6 insertions(+) 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) { From 72e97b8b5f0d1e1de375093593a602d65189d807 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 17 Oct 2026 22:30:29 +0000 Subject: [PATCH 2/2] fix(pstack): name every skill after its folder `make-bot-ui` and `poteto-mode` had the display names `Make Bot UI` and `Poteto Mode` in their frontmatter. Claude Code listed them as `/pstack:Make Bot UI` and `/pstack:Poteto Mode`, which cannot run, and Cursor warned that the name did not match the folder. The fix is in the source, so Cursor, Claude Code, and the generated tree all read the same name and the generator needs no per-harness rewrite. Every skill was renamed by this script, run from the repository root. It changes only the two skills whose name differed: node -e 'const fs=require("fs");for(const d of fs.readdirSync("pstack/skills")){const p=`pstack/skills/${d}/SKILL.md`;if(fs.existsSync(p))fs.writeFileSync(p,fs.readFileSync(p,"utf8").replace(/^(---\n[\s\S]*?^name: ).*$/m,`$1${d}`))}' node scripts/generate-pstack-harness-trees.mjs --- harness/pstack/claude-code/skills/make-bot-ui/SKILL.md | 2 +- harness/pstack/claude-code/skills/poteto-mode/SKILL.md | 2 +- pstack/skills/make-bot-ui/SKILL.md | 2 +- pstack/skills/poteto-mode/SKILL.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) 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