{"record":{"id":"974b43ea06142ab1","repo":"garrytan/gstack","slug":"gen-llms-txt-t-tmpl-is-missing-name-or-descrip","errorCode":null,"errorMessage":"gen-llms-txt: ${t.tmpl} is missing name or description in frontmatter","messagePattern":"gen-llms-txt: (.+?) is missing name or description in frontmatter","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/gen-llms-txt.ts","lineNumber":143,"sourceCode":"  skills: SkillEntry[];\n  browseCommands: string[];\n  designCommands: string[];\n  warnings: string[];\n}\n\nexport async function generateLlmsTxt(opts: GenerateOptions = {}): Promise<GenerateResult> {\n  const root = opts.root ?? ROOT;\n  const warnings: string[] = [];\n\n  const templates = discoverTemplates(root);\n  const skills: SkillEntry[] = [];\n  for (const t of templates) {\n    const filePath = path.join(root, t.tmpl);\n    const entry = parseSkillFrontmatter(filePath);\n    if (!entry) {\n      warnings.push(`skill ${t.tmpl}: missing name or description in frontmatter`);\n      if (opts.strict) {\n        throw new Error(`gen-llms-txt: ${t.tmpl} is missing name or description in frontmatter`);\n      }\n      continue;\n    }\n    skills.push(entry);\n  }\n  skills.sort((a, b) => a.name.localeCompare(b.name));\n\n  const browseCommands = Object.keys(BROWSE_COMMANDS).sort();\n  const designCommands = Object.keys(await readDesignCommands()).sort();\n\n  const lines: string[] = [];\n  lines.push('# gstack');\n  lines.push('');\n  lines.push(\"> gstack is Garry's Stack: AI coding skills + a fast headless browser binary + a design CLI. This file indexes every capability so agents can discover and invoke them without crawling individual SKILL.md files.\");\n  lines.push('');\n  lines.push('Conventions:');\n  lines.push('- Skills are invoked by name (e.g. `/ship`, `/plan-ceo-review`).');\n  lines.push('- Browse commands run as `browse <command> [args]` (or `$B` shorthand).');","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/scripts/gen-llms-txt.ts#L125-L161","documentation":"Thrown by generateLlmsTxt() under opts.strict when parseSkillFrontmatter(filePath) returns null for a discovered skill template — i.e. the template's YAML frontmatter is missing a `name` or `description` field. Without strict, the skill is skipped with a warning; with strict, the build fails so llms.txt never ships a malformed entry. The template file path is included.","triggerScenarios":"Running gen-llms-txt with --strict over a templates tree where at least one .tmpl file has empty/incomplete frontmatter (missing name or description key, or a YAML parse failure that parseSkillFrontmatter treats as null).","commonSituations":"A newly added skill template whose author forgot the description; a YAML indentation error that breaks parsing; a refactor that renamed the frontmatter keys; CI running gen-llms-txt --strict to enforce completeness; a merged template that passed review without frontmatter validation.","solutions":["Open the template file named in the message and add both `name:` and `description:` to its frontmatter.","Validate YAML indentation (frontmatter parse failures also yield null).","Re-run without --strict to see all warnings at once, then fix each before re-enabling strict.","Add a pre-commit hook that runs parseSkillFrontmatter on changed .tmpl files."],"exampleFix":"<!-- before: templates/my-skill.md.tmpl -->\n---\nname: my-skill\n---\n# My Skill\n...\n\n<!-- after -->\n---\nname: my-skill\ndescription: Does X for Y so the agent can Z.\n---\n# My Skill\n...","handlingStrategy":"validation","validationCode":"import fs from 'node:fs';\n\nfunction parseFrontmatter(filePath: string): { name?: string; description?: string } | null {\n  const text = fs.readFileSync(filePath, 'utf8');\n  const m = text.match(/^---\\n([\\s\\S]*?)\\n---/);\n  if (!m) return null;\n  const fm: Record<string, string> = {};\n  for (const line of m[1].split('\\n')) {\n    const mm = line.match(/^([a-zA-Z_][\\w-]*):\\s*(.*)$/);\n    if (mm) fm[mm[1]] = mm[2].trim().replace(/^\"(.*)\"$/, '$1');\n  }\n  if (!fm.name || !fm.description) return null;\n  return fm;\n}\n\n// pre-check every template before calling generateLlmsTxt({strict:true})\nfor (const t of templates) {\n  if (!parseFrontmatter(path.join(root, t.tmpl))) throw new Error(`missing frontmatter: ${t.tmpl}`);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Add `name:` and `description:` to every new .tmpl file at creation time.","Enforce frontmatter completeness in a pre-commit hook.","Run gen-llms-txt with --strict in CI so incomplete templates fail the build.","Document the required frontmatter keys in the skill-author guide."],"tags":["scripts","gen-llms-txt","frontmatter","yaml","build","validation"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}