garrytan/gstack · error · Error

{{INVOKE_SKILL}} requires a skill name, e.g. {{INVOKE_SKILL:

Error message

{{INVOKE_SKILL}} requires a skill name, e.g. {{INVOKE_SKILL:plan-ceo-review}}

What it means

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+].

Source

Thrown at scripts/resolvers/composition.ts:13

import type { TemplateContext } from './types';

/**
 * {{INVOKE_SKILL:skill-name}} — emits prose instructing Claude to read
 * another skill's SKILL.md and follow it, skipping preamble sections.
 *
 * Supports optional skip= parameter for additional sections to skip:
 *   {{INVOKE_SKILL:plan-ceo-review:skip=Outside Voice,Design Outside Voices}}
 */
export function generateInvokeSkill(ctx: TemplateContext, args?: string[]): string {
  const skillName = args?.[0];
  if (!skillName || skillName === '') {
    throw new Error('{{INVOKE_SKILL}} requires a skill name, e.g. {{INVOKE_SKILL:plan-ceo-review}}');
  }

  // Parse optional skip= parameter from args[1+]
  const extraSkips = (args?.slice(1) || [])
    .filter(a => a.startsWith('skip='))
    .flatMap(a => a.slice(5).split(','))
    .map(s => s.trim())
    .filter(Boolean);

  const DEFAULT_SKIPS = [
    'Preamble (run first)',
    'AskUserQuestion Format',
    'Completeness Principle — Boil the Ocean',
    'Search Before Building',
    'Contributor Mode',
    'Completion Status Protocol',
    'Telemetry (run last)',
    'Step 0: Detect platform and base branch',

View on GitHub (pinned to 94993f7401)

Solutions

  1. Provide the skill name: `{{INVOKE_SKILL:plan-ceo-review}}`
  2. Use the optional skip= parameter for additional sections: `{{INVOKE_SKILL:foo:skip=A,B}}`

Example fix

<!-- before -->
{{INVOKE_SKILL}}
<!-- after -->
{{INVOKE_SKILL:plan-ceo-review}}
Defensive patterns

Strategy: validation

Validate before calling

if (/\{\{INVOKE_SKILL(?::[^}]*)?\}\}/.test(tmplContent)) {
  for (const m of tmplContent.matchAll(/\{\{(INVOKE_SKILL:?[^}]*)\}\}/g)) {
    const arg = m[1].split(':')[1];
    if (!arg) console.error(`{{INVOKE_SKILL}} needs a name in ${relTmplPath}`);
  }
}

Prevention

When it happens

Trigger: Typing `{{INVOKE_SKILL}}` without the colon and name. Copy-paste dropping the name. Trimming a placeholder and accidentally removing the argument.

Common situations: Hand-editing a .tmpl and forgetting the argument. Misremembering the placeholder syntax.

Related errors


AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12). Data as JSON: /api/errors/73554c9ccdab7c55. Report an issue: GitHub.