Skip to main content

scripts-regenerate-skills-registry

#!/usr/bin/env python3 """ Regenerate skills/REGISTRY.json with all skills.

Task: AM.2.20 - Skills Registry Management Suite Created: 2026-01-27 """

import json import yaml import re import argparse from pathlib import Path from datetime import datetime, timezone from typing import Dict, List, Any, Optional

def extract_yaml_frontmatter(content: str) -> Dict[str, Any]: """Extract YAML frontmatter from markdown.""" match = re.match(r'^---\n(.*?)\n---', content, re.DOTALL) if match: try: return yaml.safe_load(match.group(1)) or {} except yaml.YAMLError: return {} return {}

def extract_description(content: str) -> str: """Extract description from content after frontmatter.""" content = re.sub(r'^---\n.*?\n---\n', '', content, flags=re.DOTALL) lines = content.strip().split('\n') for line in lines: line = line.strip() if line and not line.startswith('#'): return line[:500] return "No description available"

def scan_skills(skills_dir: Path, verbose: bool = False) -> List[Dict[str, Any]]: """Scan skills directory and return list of skill entries.""" skills = [] errors = []

for skill_path in sorted(skills_dir.iterdir()):
if not skill_path.is_dir():
continue

skill_file = skill_path / "SKILL.md"
if not skill_file.exists():
if verbose:
print(f" āš ļø No SKILL.md in {skill_path.name}")
continue

try:
content = skill_file.read_text()
frontmatter = extract_yaml_frontmatter(content)

name = frontmatter.get('name', skill_path.name)
description = frontmatter.get('description',
frontmatter.get('summary',
extract_description(content)))

skill_entry = {
"name": name,
"path": f".claude/skills/{skill_path.name}/SKILL.md",
"description": description[:500] if description else "No description",
"tags": frontmatter.get('tags', []),
"version": frontmatter.get('version', '1.0.0'),
"status": frontmatter.get('status', 'active')
}

if frontmatter.get('use_cases'):
skill_entry['use_cases'] = frontmatter['use_cases']

skills.append(skill_entry)
if verbose:
print(f" āœ“ {name}")
except Exception as e:
errors.append(f"{skill_path.name}: {e}")
if verbose:
print(f" āœ— {skill_path.name}: {e}")

return skills, errors

def regenerate_registry( skills_dir: Path, output_path: Optional[Path] = None, version: str = "2.1.0", dry_run: bool = False, verbose: bool = False ) -> Dict[str, Any]: """Regenerate the skills registry."""

if output_path is None:
output_path = skills_dir / "REGISTRY.json"

print(f"šŸ“‚ Scanning skills directory: {skills_dir}")
skills, errors = scan_skills(skills_dir, verbose)

# Load existing for comparison
old_count = 0
if output_path.exists():
try:
with open(output_path) as f:
old_registry = json.load(f)
old_count = len(old_registry.get('skills', []))
except:
pass

registry = {
"version": version,
"generated": datetime.now(timezone.utc).isoformat(),
"skills": skills
}

if dry_run:
print(f"\nšŸ” DRY RUN - would generate:")
print(f" Skills: {len(skills)}")
print(f" Previous: {old_count}")
print(f" Change: {len(skills) - old_count:+d}")
print(f" Output: {output_path}")
else:
with open(output_path, 'w') as f:
json.dump(registry, f, indent=2)

print(f"\nāœ… Generated REGISTRY.json")
print(f" Skills: {len(skills)}")
print(f" Previous: {old_count}")
print(f" Change: {len(skills) - old_count:+d}")
print(f" Output: {output_path}")

if errors:
print(f"\nāš ļø Errors ({len(errors)}):")
for err in errors[:10]:
print(f" - {err}")
if len(errors) > 10:
print(f" ... and {len(errors) - 10} more")

return registry

def main(): parser = argparse.ArgumentParser( description='Regenerate skills/REGISTRY.json with all skills' ) parser.add_argument( '--skills-dir', '-s', type=Path, default=Path(file).parent.parent / 'skills', help='Path to skills directory' ) parser.add_argument( '--output', '-o', type=Path, help='Output path (default: skills/REGISTRY.json)' ) parser.add_argument( '--version', '-V', default='2.1.0', help='Registry version (default: 2.1.0)' ) parser.add_argument( '--dry-run', '-n', action='store_true', help='Preview changes without writing' ) parser.add_argument( '--verbose', '-v', action='store_true', help='Show detailed output' )

args = parser.parse_args()

regenerate_registry(
skills_dir=args.skills_dir,
output_path=args.output,
version=args.version,
dry_run=args.dry_run,
verbose=args.verbose
)

if name == 'main': main()