Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
A comprehensive collection of Agent Skills for context engineering, multi-agent architectures, and production agent systems.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
researcher/scripts/skill_frontmatter.py
1"""Shared SKILL.md frontmatter parsing for researcher validation scripts."""23from __future__ import annotations45import json6import re7from typing import Any89try:10import yaml11except ImportError: # pragma: no cover - PyYAML is stdlib-adjacent in CI via setup12yaml = None # type: ignore[assignment]1314MIN_DESCRIPTION_LENGTH = 2015YAML_INDICATOR_ONLY = re.compile(r"^[>|]?-?$")161718def strip_bom(text: str) -> str:19return text[1:] if text.startswith("\ufeff") else text202122def split_frontmatter(text: str) -> tuple[str | None, str]:23"""Return (frontmatter_inner, body). Inner block excludes --- delimiters."""24text = strip_bom(text)25if not (text.startswith("---\n") or text.startswith("---\r\n")):26return None, text2728delimiter_len = 5 if text.startswith("---\r\n") else 429match = re.search(r"(?m)^---\s*$", text[delimiter_len:])30if match is None:31return None, text3233end = delimiter_len + match.start()34inner = text[delimiter_len:end].rstrip("\r")35body = text[delimiter_len + match.end() :]36if body.startswith("\r\n"):37body = body[2:]38elif body.startswith("\n"):39body = body[1:]40return inner, body414243def parse_frontmatter(text: str) -> tuple[dict[str, Any], list[str]]:44"""Parse SKILL.md frontmatter with strict YAML when available."""45issues: list[str] = []46inner, _body = split_frontmatter(text)47if inner is None:48return {}, ["missing or invalid frontmatter delimiters"]4950if yaml is None:51return _parse_frontmatter_fallback(inner, issues)5253try:54data = yaml.safe_load(inner)55except yaml.YAMLError as exc:56issues.append(f"invalid YAML frontmatter: {exc}")57return {}, issues5859if not isinstance(data, dict):60issues.append("frontmatter must be a YAML mapping")61return {}, issues6263normalized: dict[str, Any] = {}64for key, value in data.items():65if value is None:66continue67normalized[str(key)] = value6869_validate_required_fields(normalized, issues)70return normalized, issues717273def _parse_frontmatter_fallback(inner: str, issues: list[str]) -> tuple[dict[str, Any], list[str]]:74"""Line-based fallback when PyYAML is unavailable."""75data: dict[str, Any] = {}76in_description = False77description_lines: list[str] = []7879for raw in inner.splitlines():80line = raw.rstrip("\r")81if in_description:82if re.match(r"^[A-Za-z0-9_-]+:", line):83data["description"] = " ".join(description_lines).strip()84in_description = False85else:86trimmed = line.strip()87if trimmed and trimmed not in (">", ">-", "|", "|-"):88description_lines.append(trimmed)89continue9091if not line.strip() or line.startswith(" "):92continue93if ":" not in line:94continue95key, value = line.split(":", 1)96key = key.strip()97value = value.strip().strip('"').strip("'")98if key == "description" and value in (">", ">-", "|", "|-", ""):99in_description = True100continue101data[key] = value102103if in_description:104data["description"] = " ".join(description_lines).strip()105106_validate_required_fields(data, issues)107return data, issues108109110def _validate_required_fields(data: dict[str, Any], issues: list[str]) -> None:111raw_name = data.get("name", "")112raw_description = data.get("description", "")113114if raw_name and not isinstance(raw_name, str):115issues.append(f"name must be a string, got {type(raw_name).__name__}")116name = ""117else:118name = str(raw_name).strip()119120if raw_description and not isinstance(raw_description, str):121issues.append(f"description must be a string, got {type(raw_description).__name__}")122description = ""123else:124description = str(raw_description).strip()125126if not name:127issues.append("missing name")128if not description:129issues.append("missing description")130elif len(description) < MIN_DESCRIPTION_LENGTH:131issues.append(f"description too short ({len(description)} chars)")132elif YAML_INDICATOR_ONLY.match(description):133issues.append("description parsed as YAML indicator only")134135136def format_frontmatter(name: str, description: str, **extra: str) -> str:137"""Render a standards-compliant frontmatter block."""138lines = [f"name: {name}", f"description: {json.dumps(description, ensure_ascii=False)}"]139for key, value in extra.items():140lines.append(f"{key}: {json.dumps(value, ensure_ascii=False)}")141return "---\n" + "\n".join(lines) + "\n---\n"142