{"record":{"id":"73554c9ccdab7c55","repo":"garrytan/gstack","slug":"invoke-skill-requires-a-skill-name-e-g-inv","errorCode":null,"errorMessage":"{{INVOKE_SKILL}} requires a skill name, e.g. {{INVOKE_SKILL:plan-ceo-review}}","messagePattern":"(.+?)\\} requires a skill name, e\\.g\\. (.+?)\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/resolvers/composition.ts","lineNumber":13,"sourceCode":"import type { TemplateContext } from './types';\n\n/**\n * {{INVOKE_SKILL:skill-name}} — emits prose instructing Claude to read\n * another skill's SKILL.md and follow it, skipping preamble sections.\n *\n * Supports optional skip= parameter for additional sections to skip:\n *   {{INVOKE_SKILL:plan-ceo-review:skip=Outside Voice,Design Outside Voices}}\n */\nexport function generateInvokeSkill(ctx: TemplateContext, args?: string[]): string {\n  const skillName = args?.[0];\n  if (!skillName || skillName === '') {\n    throw new Error('{{INVOKE_SKILL}} requires a skill name, e.g. {{INVOKE_SKILL:plan-ceo-review}}');\n  }\n\n  // Parse optional skip= parameter from args[1+]\n  const extraSkips = (args?.slice(1) || [])\n    .filter(a => a.startsWith('skip='))\n    .flatMap(a => a.slice(5).split(','))\n    .map(s => s.trim())\n    .filter(Boolean);\n\n  const DEFAULT_SKIPS = [\n    'Preamble (run first)',\n    'AskUserQuestion Format',\n    'Completeness Principle — Boil the Ocean',\n    'Search Before Building',\n    'Contributor Mode',\n    'Completion Status Protocol',\n    'Telemetry (run last)',\n    'Step 0: Detect platform and base branch',","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/scripts/resolvers/composition.ts#L1-L31","documentation":"generateInvokeSkill() in scripts/resolvers/composition.ts:13 requires a non-empty skill name as the first colon argument to {{INVOKE_SKILL:skill-name}}. Thrown when the placeholder appears without an argument ({{INVOKE_SKILL}} or {{INVOKE_SKILL:}}) in a .tmpl. Optional skip= arguments are parsed from args[1+].","triggerScenarios":"Typing `{{INVOKE_SKILL}}` without the colon and name. Copy-paste dropping the name. Trimming a placeholder and accidentally removing the argument.","commonSituations":"Hand-editing a .tmpl and forgetting the argument. Misremembering the placeholder syntax.","solutions":["Provide the skill name: `{{INVOKE_SKILL:plan-ceo-review}}`","Use the optional skip= parameter for additional sections: `{{INVOKE_SKILL:foo:skip=A,B}}`"],"exampleFix":"<!-- before -->\n{{INVOKE_SKILL}}\n<!-- after -->\n{{INVOKE_SKILL:plan-ceo-review}}","handlingStrategy":"validation","validationCode":"if (/\\{\\{INVOKE_SKILL(?::[^}]*)?\\}\\}/.test(tmplContent)) {\n  for (const m of tmplContent.matchAll(/\\{\\{(INVOKE_SKILL:?[^}]*)\\}\\}/g)) {\n    const arg = m[1].split(':')[1];\n    if (!arg) console.error(`{{INVOKE_SKILL}} needs a name in ${relTmplPath}`);\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair INVOKE_SKILL with a colon and skill name","Lint .tmpl files for empty-argument placeholders","Copy the canonical form {{INVOKE_SKILL:plan-ceo-review}} from working skills"],"tags":["template","resolver","composition"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}