From 459c6cfd5b1b969799773f4160c8b39df0ec981f Mon Sep 17 00:00:00 2001 From: yusyus Date: Thu, 6 Nov 2025 23:56:31 +0300 Subject: [PATCH] fix: Add YAML frontmatter to unified, GitHub, and PDF skill builders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Problem:** (PR #170 verified) Three skill builders were generating SKILL.md files without YAML frontmatter, making skills invisible to Claude after upload: - unified_skill_builder.py - github_scraper.py - pdf_scraper.py Only doc_scraper.py had frontmatter implemented. **Root Cause:** Claude requires YAML frontmatter with 'name' and 'description' fields to recognize and index skills. Without it, uploaded skills don't appear in skill lists and can't be triggered. **Fix:** Added consistent frontmatter generation to all three builders: - Normalizes skill name (lowercase, hyphens, max 64 chars) - Truncates description to 1024 chars (Claude requirement) - Generates YAML frontmatter with proper formatting **Test Results:** ✅ All 390/390 tests passing (0 failures, 0 skipped) ✅ Consistent implementation across all builders ✅ Meets Claude's official skill specification **Example Output:** ```yaml --- name: my-skill-name description: Skill description here --- # My Skill Name ... ``` **Credits:** Original fix by @AbdelrahmanHafez in PR #170 Rebased to current development by Claude Code 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Co-Authored-By: AbdelrahmanHafez --- cli/github_scraper.py | 13 ++++++++++++- cli/pdf_scraper.py | 12 ++++++++++++ cli/unified_skill_builder.py | 13 ++++++++++++- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/cli/github_scraper.py b/cli/github_scraper.py index d95cf8b..b8c1d11 100644 --- a/cli/github_scraper.py +++ b/cli/github_scraper.py @@ -536,7 +536,18 @@ class GitHubToSkillConverter: """Generate main SKILL.md file.""" repo_info = self.data.get('repo_info', {}) - skill_content = f"""# {repo_info.get('name', self.name)} + # Generate skill name (lowercase, hyphens only, max 64 chars) + skill_name = self.name.lower().replace('_', '-').replace(' ', '-')[:64] + + # Truncate description to 1024 chars if needed + desc = self.description[:1024] if len(self.description) > 1024 else self.description + + skill_content = f"""--- +name: {skill_name} +description: {desc} +--- + +# {repo_info.get('name', self.name)} {self.description} diff --git a/cli/pdf_scraper.py b/cli/pdf_scraper.py index 688a11a..88f3235 100644 --- a/cli/pdf_scraper.py +++ b/cli/pdf_scraper.py @@ -272,7 +272,19 @@ class PDFToSkillConverter: """Generate main SKILL.md file""" filename = f"{self.skill_dir}/SKILL.md" + # Generate skill name (lowercase, hyphens only, max 64 chars) + skill_name = self.name.lower().replace('_', '-').replace(' ', '-')[:64] + + # Truncate description to 1024 chars if needed + desc = self.description[:1024] if len(self.description) > 1024 else self.description + with open(filename, 'w', encoding='utf-8') as f: + # Write YAML frontmatter + f.write(f"---\n") + f.write(f"name: {skill_name}\n") + f.write(f"description: {desc}\n") + f.write(f"---\n\n") + f.write(f"# {self.name.title()} Documentation Skill\n\n") f.write(f"{self.description}\n\n") diff --git a/cli/unified_skill_builder.py b/cli/unified_skill_builder.py index a93d017..dd3051d 100644 --- a/cli/unified_skill_builder.py +++ b/cli/unified_skill_builder.py @@ -73,7 +73,18 @@ class UnifiedSkillBuilder: """Generate main SKILL.md file.""" skill_path = os.path.join(self.skill_dir, 'SKILL.md') - content = f"""# {self.name.title()} + # Generate skill name (lowercase, hyphens only, max 64 chars) + skill_name = self.name.lower().replace('_', '-').replace(' ', '-')[:64] + + # Truncate description to 1024 chars if needed + desc = self.description[:1024] if len(self.description) > 1024 else self.description + + content = f"""--- +name: {skill_name} +description: {desc} +--- + +# {self.name.title()} {self.description}