← Back to Prompts

Skill Creator

A structured framework for designing modular, specialized skills to extend Claude's capabilities and workflows.

by OpenPrompts_Bot
--- name: skill-creator description: Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations. license: Complete terms in LICENSE.txt --- # Skill Creator This skill provides guidance for creating effective skills. ## About Skills Skills are modular, self-contained packages that extend Claude's capabilities by providing specialized knowledge, workflows, and tools. Think of them as "onboarding guides" for specific domains or tasksβ€”they transform Claude from a general-purpose agent into a specialized agent equipped with procedural knowledge that no model can fully possess. ### What Skills Provide 1. Specialized workflows - Multi-step procedures for specific domains 2. Tool integrations - Instructions for working with specific file formats or APIs 3. Domain expertise - Company-specific knowledge, schemas, business logic 4. Bundled resources - Scripts, references, and assets for complex and repetitive tasks ## Core Principles ### Concise is Key The context window is a public good. Skills share the context window with everything else Claude needs: system prompt, conversation history, other Skills' metadata, and the actual user request. **Default assumption: Claude is already very smart.** Only add context Claude doesn't already have. Challenge each piece of information: "Does Claude really need this explanation?" and "Does this paragraph justify its token cost?" Prefer concise examples over verbose explanations. ### Set Appropriate Degrees of Freedom Match the level of specificity to the task's fragility and variability: **High freedom (text-based instructions)**: Use when multiple approaches are valid, decisions depend on context, or heuristics guide the approach. **Medium freedom (pseudocode or scripts with parameters)**: Use when a preferred pattern exists, some variation is acceptable, or configuration affects behavior. **Low freedom (specific scripts, few parameters)**: Use when operations are fragile and error-prone, consistency is critical, or a specific sequence must be followed. Think of Claude as exploring a path: a narrow bridge with cliffs needs specific guardrails (low freedom), while an open field allows many routes (high freedom). ### Anatomy of a Skill Every skill consists of a required SKILL.md file and optional bundled resources: ``` skill-name/ β”œβ”€β”€ SKILL.md (required) β”‚ β”œβ”€β”€ YAML frontmatter metadata (required) β”‚ β”‚ β”œβ”€β”€ name: (required) β”‚ β”‚ └── description: (required) β”‚ └── Markdown instructions (required) └── Bundled Resources (optional) β”œβ”€β”€ scripts/ - Executable code (Python/Bash/etc.) β”œβ”€β”€ references/ - Documentation intended to be loaded into context as needed └── assets/ - Files used in output (templates, icons, fonts, etc.) ``` #### SKILL.md (required) Every SKILL.md consists of: - **Frontmatter** (YAML): Contains `name` and `description` fields. These are the only fields that Claude reads to determine when the skill gets used, thus it is very important to be clear and comprehensive in describing what the skill is, and when it should be used. - **Body** (Markdown): Instructions and guidance for using the skill. Only loaded AFTER the skill triggers (if at all). #### Bundled Resources (optional) ##### Scripts (`scripts/`) Executable code (Python/Bash/etc.) for tasks that require deterministic reliability or are repeatedly rewritten. - **When to include**: When the same code is being rewritten repeatedly or deterministic reliability is needed - **Example**: `scripts/rotate_pdf.py` for PDF rotation tasks - **Benefits**: Token efficient, deterministic, may be executed without loading into context - **Note**: Scripts may still need to be read by Claude for patching or environment-specific adjustments ##### References (`references/`) Documentation and reference material intended to be loaded as needed into context to inform Claude's process and thinking. - **When to include**: For documentation that Claude should reference while working - **Examples**: `references/finance.md` for financial schemas, `references/mnda.md` for company NDA template, `references/policies.md` for company policies, `references/api_docs.md` for API specifications - **Use cases**: Database schemas, API documentation, domain knowledge, company policies, detailed workflow guides - **Benefits**: Keeps SKILL.md lean, loaded only when Claude determines it's needed - **Best practice**: If files are large (>10k words), include grep search patterns in SKILL.md - **Avoid duplication**: Information should live in either SKILL.md or references files, not both. ##### Assets (`assets/`) Files not intended to be loaded into context, but rather used within the output Claude produces. - **When to include**: When the skill needs files that will be used in the final output - **Examples**: `assets/logo.png` for brand assets, `assets/slides.pptx` for PowerPoint templates - **Use cases**: Templates, images, icons, boilerplate code, fonts, sample documents ### Progressive Disclosure Design Principle Skills use a three-level loading system to manage context efficiently: 1. **Metadata (name + description)** - Always in context (~100 words) 2. **SKILL.md body** - When skill triggers (<5k words) 3. **Bundled resources** - As needed by Claude Keep SKILL.md body to the essentials and under 500 lines to minimize context bloat. ## Skill Creation Process Skill creation involves these steps: 1. Understand the skill with concrete examples 2. Plan reusable skill contents (scripts, references, assets) 3. Initialize the skill (run init_skill.py) 4. Edit the skill (implement resources and write SKILL.md) 5. Package the skill (run package_skill.py) 6. Iterate based on real usage ### Step 3: Initializing the Skill When creating a new skill from scratch, always run the `init_skill.py` script: ```bash scripts/init_skill.py <skill-name> --path <output-directory> ``` ### Step 4: Edit the Skill Consult these helpful guides based on your skill's needs: - **Multi-step processes**: See references/workflows.md for sequential workflows and conditional logic - **Specific output formats or quality standards**: See references/output-patterns.md for template and example patterns ### Step 5: Packaging a Skill ```bash scripts/package_skill.py <path/to/skill-folder> ``` The packaging script validates and creates a .skill file for distribution. FILE:references/workflows.md # Workflow Patterns ## Sequential Workflows For complex tasks, break operations into clear, sequential steps. It is often helpful to give Claude an overview of the process towards the beginning of SKILL.md: ```markdown Filling a PDF form involves these steps: 1. Analyze the form (run analyze_form.py) 2. Create field mapping (edit fields.json) 3. Validate mapping (run validate_fields.py) 4. Fill the form (run fill_form.py) 5. Verify output (run verify_output.py) ``` ## Conditional Workflows For tasks with branching logic, guide Claude through decision points: ```markdown 1. Determine the modification type: **Creating new content?** β†’ Follow "Creation workflow" below **Editing existing content?** β†’ Follow "Editing workflow" below 2. Creation workflow: [steps] 3. Editing workflow: [steps] ``` FILE:references/output-patterns.md # Output Patterns Use these patterns when skills need to produce consistent, high-quality output. ## Template Pattern Provide templates for output format. Match the level of strictness to your needs. **For strict requirements (like API responses or data formats):** ```markdown ## Report structure ALWAYS use this exact template structure: # [Analysis Title] ## Executive summary [One-paragraph overview of key findings] ## Key findings - Finding 1 with supporting data - Finding 2 with supporting data - Finding 3 with supporting data ## Recommendations 1. Specific actionable recommendation 2. Specific actionable recommendation ``` **For flexible guidance (when adaptation is useful):** ```markdown ## Report structure Here is a sensible default format, but use your best judgment: # [Analysis Title] ## Executive summary [Overview] ## Key findings [Adapt sections based on what you discover] ## Recommendations [Tailor to the specific context] Adjust sections as needed for the specific analysis type. ``` ## Examples Pattern For skills where output quality depends on seeing examples, provide input/output pairs: ```markdown ## Commit message format Generate commit messages following these examples: **Example 1:** Input: Added user authentication with JWT tokens Output: ``` feat(auth): implement JWT-based authentication Add login endpoint and token validation middleware ``` **Example 2:** Input: Fixed bug where dates displayed incorrectly in reports Output: ``` fix(reports): correct date formatting in timezone conversion Use UTC timestamps consistently across report generation ``` Follow this style: type(scope): brief description, then detailed explanation. ``` Examples help Claude understand the desired style and level of detail more clearly than descriptions alone. FILE:scripts/quick_validate.py #!/usr/bin/env python3 """ Quick validation script for skills - minimal version """ import sys import os import re import yaml from pathlib import Path def validate_skill(skill_path): """Basic validation of a skill""" skill_path = Path(skill_path) # Check SKILL.md exists skill_md = skill_path / 'SKILL.md' if not skill_md.exists(): return False, "SKILL.md not found" # Read and validate frontmatter content = skill_md.read_text() if not content.startswith('---'): return False, "No YAML frontmatter found" # Extract frontmatter match = re.match(r'^---\n(.*?)\n---', content, re.DOTALL) if not match: return False, "Invalid frontmatter format" frontmatter_text = match.group(1) # Parse YAML frontmatter try: frontmatter = yaml.safe_load(frontmatter_text) if not isinstance(frontmatter, dict): return False, "Frontmatter must be a YAML dictionary" except yaml.YAMLError as e: return False, f"Invalid YAML in frontmatter: {e}" # Define allowed properties ALLOWED_PROPERTIES = {'name', 'description', 'license', 'allowed-tools', 'metadata'} # Check for unexpected properties (excluding nested keys under metadata) unexpected_keys = set(frontmatter.keys()) - ALLOWED_PROPERTIES if unexpected_keys: return False, ( f"Unexpected key(s) in SKILL.md frontmatter: {', '.join(sorted(unexpected_keys))}. " f"Allowed properties are: {', '.join(sorted(ALLOWED_PROPERTIES))}" ) # Check required fields if 'name' not in frontmatter: return False, "Missing 'name' in frontmatter" if 'description' not in frontmatter: return False, "Missing 'description' in frontmatter" # Extract name for validation name = frontmatter.get('name', '') if not isinstance(name, str): return False, f"Name must be a string, got {type(name).__name__}" name = name.strip() if name: # Check naming convention (hyphen-case: lowercase with hyphens) if not re.match(r'^[a-z0-9-]+$', name): return False, f"Name '{name}' should be hyphen-case (lowercase letters, digits, and hyphens only)" if name.startswith('-') or name.endswith('-') or '--' in name: return False, f"Name '{name}' cannot start/end with hyphen or contain consecutive hyphens" # Check name length (max 64 characters per spec) if len(name) > 64: return False, f"Name is too long ({len(name)} characters). Maximum is 64 characters." # Extract and validate description description = frontmatter.get('description', '') if not isinstance(description, str): return False, f"Description must be a string, got {type(description).__name__}" description = description.strip() if description: # Check for angle brackets if '<' in description or '>' in description: return False, "Description cannot contain angle brackets (< or >)" # Check description length (max 1024 characters per spec) if len(description) > 1024: return False, f"Description is too long ({len(description)} characters). Maximum is 1024 characters." return True, "Skill is valid!" if __name__ == "__main__": if len(sys.argv) != 2: print("Usage: python quick_validate.py <skill_directory>") sys.exit(1) valid, message = validate_skill(sys.argv[1]) print(message) sys.exit(0 if valid else 1) FILE:scripts/init_skill.py #!/usr/bin/env python3 """ Skill Initializer - Creates a new skill from template Usage: init_skill.py <skill-name> --path <path> Examples: init_skill.py my-new-skill --path skills/public init_skill.py my-api-helper --path skills/private init_skill.py custom-skill --path /custom/location """ import sys from pathlib import Path SKILL_TEMPLATE = """--- name: {skill_name} description: [TODO: Complete and informative explanation of what the skill does and when to use it. Include WHEN to use this skill - specific scenarios, file types, or tasks that trigger it.] --- # {skill_title} ## Overview [TODO: 1-2 sentences explaining what this skill enables] ## Resources This skill includes example resource directories that demonstrate how to organize different types of bundled resources: ### scripts/ Executable code (Python/Bash/etc.) that can be run directly to perform specific operations. ### references/ Documentation and reference material intended to be loaded into context to inform Claude's process and thinking. ### assets/ Files not intended to be loaded into context, but rather used within the output Claude produces. --- **Any unneeded directories can be deleted.** Not every skill requires all three types of resources. """ EXAMPLE_SCRIPT = '''#!/usr/bin/env python3 """ Example helper script for {skill_name} This is a placeholder script that can be executed directly. Replace with actual implementation or delete if not needed. """ def main(): print("This is an example script for {skill_name}") # TODO: Add actual script logic here if __name__ == "__main__": main() ''' EXAMPLE_REFERENCE = """# Reference Documentation for {skill_title} This is a placeholder for detailed reference documentation. Replace with actual reference content or delete if not needed. """ EXAMPLE_ASSET = """# Example Asset File This placeholder represents where asset files would be stored. Replace with actual asset files (templates, images, fonts, etc.) or delete if not needed. """ def title_case_skill_name(skill_name): """Convert hyphenated skill name to Title Case for display.""" return ' '.join(word.capitalize() for word in skill_name.split('-')) def init_skill(skill_name, path): """Initialize a new skill directory with template SKILL.md.""" skill_dir = Path(path).resolve() / skill_name if skill_dir.exists(): print(f"❌ Error: Skill directory already exists: {skill_dir}") return None try: skill_dir.mkdir(parents=True, exist_ok=False) print(f"βœ… Created skill directory: {skill_dir}") except Exception as e: print(f"❌ Error creating directory: {e}") return None skill_title = title_case_skill_name(skill_name) skill_content = SKILL_TEMPLATE.format(skill_name=skill_name, skill_title=skill_title) skill_md_path = skill_dir / 'SKILL.md' try: skill_md_path.write_text(skill_content) print("βœ… Created SKILL.md") except Exception as e: print(f"❌ Error creating SKILL.md: {e}") return None try: scripts_dir = skill_dir / 'scripts' scripts_dir.mkdir(exist_ok=True) example_script = scripts_dir / 'example.py' example_script.write_text(EXAMPLE_SCRIPT.format(skill_name=skill_name)) example_script.chmod(0o755) print("βœ… Created scripts/example.py") references_dir = skill_dir / 'references' references_dir.mkdir(exist_ok=True) example_reference = references_dir / 'api_reference.md' example_reference.write_text(EXAMPLE_REFERENCE.format(skill_title=skill_title)) print("βœ… Created references/api_reference.md") assets_dir = skill_dir / 'assets' assets_dir.mkdir(exist_ok=True) example_asset = assets_dir / 'example_asset.txt' example_asset.write_text(EXAMPLE_ASSET) print("βœ… Created assets/example_asset.txt") except Exception as e: print(f"❌ Error creating resource directories: {e}") return None print(f"\nβœ… Skill '{skill_name}' initialized successfully at {skill_dir}") return skill_dir def main(): if len(sys.argv) < 4 or sys.argv[2] != '--path': print("Usage: init_skill.py <skill-name> --path <path>") sys.exit(1) skill_name = sys.argv[1] path = sys.argv[3] print(f"πŸš€ Initializing skill: {skill_name}") print(f" Location: {path}") print() result = init_skill(skill_name, path) sys.exit(0 if result else 1) if __name__ == "__main__": main() FILE:scripts/package_skill.py #!/usr/bin/env python3 """ Skill Packager - Creates a distributable .skill file of a skill folder Usage: python utils/package_skill.py <path/to/skill-folder> [output-directory] Example: python utils/package_skill.py skills/public/my-skill python utils/package_skill.py skills/public/my-skill ./dist """ import sys import zipfile from pathlib import Path from quick_validate import validate_skill def package_skill(skill_path, output_dir=None): """Package a skill folder into a .skill file.""" skill_path = Path(skill_path).resolve() if not skill_path.exists(): print(f"❌ Error: Skill folder not found: {skill_path}") return None if not skill_path.is_dir(): print(f"❌ Error: Path is not a directory: {skill_path}") return None skill_md = skill_path / "SKILL.md" if not skill_md.exists(): print(f"❌ Error: SKILL.md not found in {skill_path}") return None print("πŸ” Validating skill...") valid, message = validate_skill(skill_path) if not valid: print(f"❌ Validation failed: {message}") print(" Please fix the validation errors before packaging.") return None print(f"βœ… {message}\n") skill_name = skill_path.name if output_dir: output_path = Path(output_dir).resolve() output_path.mkdir(parents=True, exist_ok=True) else: output_path = Path.cwd() skill_filename = output_path / f"{skill_name}.skill" try: with zipfile.ZipFile(skill_filename, 'w', zipfile.ZIP_DEFLATED) as zipf: for file_path in skill_path.rglob('*'): if file_path.is_file(): arcname = file_path.relative_to(skill_path.parent) zipf.write(file_path, arcname) print(f" Added: {arcname}") print(f"\nβœ… Successfully packaged skill to: {skill_filename}") return skill_filename except Exception as e: print(f"❌ Error creating .skill file: {e}") return None def main(): if len(sys.argv) < 2: print("Usage: python utils/package_skill.py <path/to/skill-folder> [output-directory]") sys.exit(1) skill_path = sys.argv[1] output_dir = sys.argv[2] if len(sys.argv) > 2 else None print(f"πŸ“¦ Packaging skill: {skill_path}") if output_dir: print(f" Output directory: {output_dir}") print() result = package_skill(skill_path, output_dir) sys.exit(0 if result else 1) if __name__ == "__main__": main()
Added on March 31, 2026