fix(skills): validate bundled SKILL.md front-matter in CI (fixes #2443) (#2457)

* fix(skills): validate bundled SKILL.md front-matter in CI (fixes #2443)

Adds a parametrized backend test that runs `_validate_skill_frontmatter`
against every bundled SKILL.md under `skills/public/`, so a broken
front-matter fails CI with a per-skill error message instead of
surfacing as a runtime gateway-load warning.

The new test caught two pre-existing breakages on `main` and fixes them:

* `bootstrap/SKILL.md`: the unquoted description had a second `:` mid-line
  ("Also trigger for updates: ..."), which YAML parses as a nested mapping
  ("mapping values are not allowed here"). Rewrites the description as a
  folded scalar (`>-`), which preserves the original wording (including the
  embedded colon, double quotes, and apostrophes) without further escaping.
  This complements PR #2436 (single-file colon→hyphen patch) with a more
  general convention that survives future edits.

* `chart-visualization/SKILL.md`: used `dependency:` which is not in
  `ALLOWED_FRONTMATTER_PROPERTIES`. Renamed to `compatibility:`, the
  documented field for "Required tools, dependencies" per skill-creator.
  No code reads `dependency` (verified by grep across backend/).

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Fix the lint error

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
d 🔹 2026-04-23 14:06:14 +08:00 committed by GitHub
parent 96d00f6073
commit b90f219bd1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 39 additions and 2 deletions

View File

@ -0,0 +1,31 @@
"""Validate every bundled SKILL.md under skills/public/.
Catches regressions like #2443 — a SKILL.md whose YAML front-matter fails to
parse (e.g. an unquoted description containing a colon, which YAML interprets
as a nested mapping). Each bundled skill is checked individually so the
failure message identifies the exact file.
"""
from pathlib import Path
import pytest
from deerflow.skills.validation import _validate_skill_frontmatter
SKILLS_PUBLIC_DIR = Path(__file__).resolve().parents[2] / "skills" / "public"
BUNDLED_SKILL_DIRS = sorted(p.parent for p in SKILLS_PUBLIC_DIR.rglob("SKILL.md"))
@pytest.mark.parametrize(
"skill_dir",
BUNDLED_SKILL_DIRS,
ids=lambda p: str(p.relative_to(SKILLS_PUBLIC_DIR)),
)
def test_bundled_skill_frontmatter_is_valid(skill_dir: Path) -> None:
valid, msg, name = _validate_skill_frontmatter(skill_dir)
assert valid, f"{skill_dir.relative_to(SKILLS_PUBLIC_DIR)}: {msg}"
assert name, f"{skill_dir.relative_to(SKILLS_PUBLIC_DIR)}: no name extracted"
def test_skills_public_dir_has_skills() -> None:
assert BUNDLED_SKILL_DIRS, f"no SKILL.md found under {SKILLS_PUBLIC_DIR}"

View File

@ -1,6 +1,12 @@
--- ---
name: bootstrap name: bootstrap
description: Generate a personalized SOUL.md through a warm, adaptive onboarding conversation. Trigger when the user wants to create, set up, or initialize their AI partner's identity — e.g., "create my SOUL.md", "bootstrap my agent", "set up my AI partner", "define who you are", "let's do onboarding", "personalize this AI", "make you mine", or when a SOUL.md is missing. Also trigger for updates: "update my SOUL.md", "change my AI's personality", "tweak the soul". description: >-
Generate a personalized SOUL.md through a warm, adaptive onboarding conversation.
Trigger when the user wants to create, set up, or initialize their AI partner's
identity — e.g., "create my SOUL.md", "bootstrap my agent", "set up my AI
partner", "define who you are", "let's do onboarding", "personalize this AI",
"make you mine", or when a SOUL.md is missing. Also trigger for updates:
"update my SOUL.md", "change my AI's personality", "tweak the soul".
--- ---
# Bootstrap Soul # Bootstrap Soul

View File

@ -1,7 +1,7 @@
--- ---
name: chart-visualization name: chart-visualization
description: This skill should be used when the user wants to visualize data. It intelligently selects the most suitable chart type from 26 available options, extracts parameters based on detailed specifications, and generates a chart image using a JavaScript script. description: This skill should be used when the user wants to visualize data. It intelligently selects the most suitable chart type from 26 available options, extracts parameters based on detailed specifications, and generates a chart image using a JavaScript script.
dependency: compatibility:
nodejs: ">=18.0.0" nodejs: ">=18.0.0"
--- ---