scripts/quick_validate.py
scripts/quick_validate.pyBrowse 3 files
1,048 tokens
4,840 bytes
Token encoding: o200k_base
Snapshot 229ffef
← Back to SKILL.md
1#!/usr/bin/env python32"""Quick validation script for skills - minimal version.3 4For deepagents CLI, skills are located at:5~/.deepagents/<agent>/skills/<skill-name>/6 7Example:8```python9python quick_validate.py ~/.deepagents/agent/skills/my-skill10```11"""12 13import re14import sys15from pathlib import Path16 17import yaml18 19 20def validate_skill(skill_path):21 """Basic validation of a skill.22 23 Returns:24 Tuple of (is_valid, message) where is_valid is bool and message25 describes result.26 """27 skill_path = Path(skill_path)28 29 # Check SKILL.md exists30 skill_md = skill_path / "SKILL.md"31 if not skill_md.exists():32 return False, "SKILL.md not found"33 34 # Read and validate frontmatter35 content = skill_md.read_text()36 if not content.startswith("---"):37 return False, "No YAML frontmatter found"38 39 # Extract frontmatter40 match = re.match(r"^---\n(.*?)\n---", content, re.DOTALL)41 if not match:42 return False, "Invalid frontmatter format"43 44 frontmatter_text = match.group(1)45 46 # Parse YAML frontmatter47 try:48 frontmatter = yaml.safe_load(frontmatter_text)49 if not isinstance(frontmatter, dict):50 return False, "Frontmatter must be a YAML dictionary"51 except yaml.YAMLError as e:52 return False, f"Invalid YAML in frontmatter: {e}"53 54 # Define allowed properties55 ALLOWED_PROPERTIES = {56 "name",57 "description",58 "license",59 "compatibility",60 "allowed-tools",61 "metadata",62 }63 64 # Check for unexpected properties (excluding nested keys under metadata)65 unexpected_keys = {str(key) for key in frontmatter if key not in ALLOWED_PROPERTIES}66 if unexpected_keys:67 unexpected_str = ", ".join(sorted(unexpected_keys))68 allowed_str = ", ".join(sorted(ALLOWED_PROPERTIES))69 return False, (70 f"Unexpected key(s) in SKILL.md frontmatter: {unexpected_str}. "71 f"Allowed properties are: {allowed_str}"72 )73 74 # Check required fields75 if "name" not in frontmatter:76 return False, "Missing 'name' in frontmatter"77 if "description" not in frontmatter:78 return False, "Missing 'description' in frontmatter"79 80 # Extract name for validation81 name = frontmatter.get("name", "")82 if not isinstance(name, str):83 return False, f"Name must be a string, got {type(name).__name__}"84 name = name.strip()85 if name:86 # Check naming convention (hyphen-case: lowercase with hyphens)87 if not re.match(r"^[a-z0-9-]+$", name):88 return (89 False,90 (91 f"Name '{name}' should be hyphen-case "92 "(lowercase letters, digits, and hyphens only)"93 ),94 )95 if name.startswith("-") or name.endswith("-") or "--" in name:96 return (97 False,98 (99 f"Name '{name}' cannot start/end with hyphen "100 "or contain consecutive hyphens"101 ),102 )103 # Check name length (max 64 characters per spec)104 if len(name) > 64:105 return (106 False,107 f"Name is too long ({len(name)} characters). Maximum is 64 characters.",108 )109 110 # Extract and validate description111 description = frontmatter.get("description", "")112 if not isinstance(description, str):113 return False, f"Description must be a string, got {type(description).__name__}"114 description = description.strip()115 if description:116 # Check for angle brackets117 if "<" in description or ">" in description:118 return False, "Description cannot contain angle brackets (< or >)"119 # Check description length (max 1024 characters per spec)120 if len(description) > 1024:121 return (122 False,123 (124 f"Description is too long ({len(description)} characters). "125 "Maximum is 1024 characters."126 ),127 )128 129 # Extract and validate compatibility (max 500 characters per spec)130 compatibility = frontmatter.get("compatibility", "")131 if isinstance(compatibility, str):132 compatibility = compatibility.strip()133 if len(compatibility) > 500:134 return (135 False,136 (137 f"Compatibility is too long ({len(compatibility)} characters). "138 "Maximum is 500 characters."139 ),140 )141 142 return True, "Skill is valid!"143 144 145if __name__ == "__main__":146 if len(sys.argv) != 2:147 print("Usage: python quick_validate.py <skill_directory>")148 sys.exit(1)149 150 valid, message = validate_skill(sys.argv[1])151 print(message)152 sys.exit(0 if valid else 1)153