{"record":{"id":"b194ab056007588f","repo":"anthropics/skills","slug":"skill-md-missing-frontmatter-no-opening","errorCode":null,"errorMessage":"SKILL.md missing frontmatter (no opening ---)","messagePattern":"SKILL\\.md missing frontmatter \\(no opening ---\\)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/skill-creator/scripts/utils.py","lineNumber":13,"sourceCode":"\"\"\"Shared utilities for skill-creator scripts.\"\"\"\n\nfrom pathlib import Path\n\n\n\ndef parse_skill_md(skill_path: Path) -> tuple[str, str, str]:\n    \"\"\"Parse a SKILL.md file, returning (name, description, full_content).\"\"\"\n    content = (skill_path / \"SKILL.md\").read_text()\n    lines = content.split(\"\\n\")\n\n    if lines[0].strip() != \"---\":\n        raise ValueError(\"SKILL.md missing frontmatter (no opening ---)\")\n\n    end_idx = None\n    for i, line in enumerate(lines[1:], start=1):\n        if line.strip() == \"---\":\n            end_idx = i\n            break\n\n    if end_idx is None:\n        raise ValueError(\"SKILL.md missing frontmatter (no closing ---)\")\n\n    name = \"\"\n    description = \"\"\n    frontmatter_lines = lines[1:end_idx]\n    i = 0\n    while i < len(frontmatter_lines):\n        line = frontmatter_lines[i]\n        if line.startswith(\"name:\"):\n            name = line[len(\"name:\"):].strip().strip('\"').strip(\"'\")","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/anthropics/skills/blob/f6656c1256d5a8adfa37db9110046ef20bac644c/skills/skill-creator/scripts/utils.py#L1-L31","documentation":"parse_skill_md() reads skills/<name>/SKILL.md and requires YAML frontmatter; it raises this ValueError when the first line is not `---`. Without an opening delimiter there is no frontmatter block, so name/description cannot be extracted.","triggerScenarios":"Calling parse_skill_md(path) on a SKILL.md that starts with a BOM, a title like `# My Skill`, a blank first line, or plain prose instead of `---` on line 1 (only surrounding whitespace is tolerated via .strip()).","commonSituations":"Hand-written skill files that skip frontmatter; copy-paste from a rendered markdown view that dropped the delimiters; editors saving a UTF-8 BOM before the first `---`; leading blank lines inserted by a formatter.","solutions":["Make line 1 of SKILL.md exactly `---`, then `name:` and `description:` lines, then a closing `---`","Check for a BOM or leading blank line: `head -c 20 SKILL.md | xxd` — re-save as UTF-8 without BOM","Scaffold new skills with the skill-creator tooling instead of authoring the file from scratch"],"exampleFix":"# before (SKILL.md)\n# My awesome skill\nDoes things.\n# after\n---\nname: my-awesome-skill\ndescription: Does things.\n---\n\n# My awesome skill","handlingStrategy":"validation","validationCode":"def has_frontmatter(skill_path: Path) -> bool:\n    with (skill_path / \"SKILL.md\").open(encoding=\"utf-8-sig\") as f:  # utf-8-sig strips a BOM\n        return f.readline().strip() == \"---\"","typeGuard":null,"tryCatchPattern":"try:\n    name, desc, content = parse_skill_md(path)\nexcept ValueError as e:\n    print(f\"{path}: invalid SKILL.md — {e}\")  # report file so the fix is obvious\n    continue","preventionTips":["Scaffold SKILL.md via the skill-creator tooling rather than by hand","Save as UTF-8 without BOM; keep `---` as the literal first line","Validate all skills in CI with the same parse_skill_md call you run in production"],"tags":["markdown","frontmatter","validation","skill-creator"],"backgroundTag":null,"analyzedSha":"f6656c1256d5a8adfa37db9110046ef20bac644c","analyzedAt":"2026-08-14T16:09:17.493Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}