Initial commit
This commit is contained in:
691
commands/specweave-tooling-skill-create.md
Normal file
691
commands/specweave-tooling-skill-create.md
Normal file
@@ -0,0 +1,691 @@
|
||||
---
|
||||
name: specweave-tooling:skill-create
|
||||
description: Create new Claude Code skill with proper YAML frontmatter, directory structure, and activation triggers. Interactive wizard for skill creation with validation and best practices.
|
||||
---
|
||||
|
||||
# Create New Skill
|
||||
|
||||
**Interactive Wizard**: From concept to production-ready skill with proper structure and validation.
|
||||
|
||||
You are helping the user create a new Claude Code skill following best practices and the required structure.
|
||||
|
||||
## Critical Structure Rules (Get This Right First!)
|
||||
|
||||
### 1. Directory Structure
|
||||
|
||||
**MANDATORY format**:
|
||||
```
|
||||
~/.claude/skills/ ← Personal skills
|
||||
└── your-skill-name/ ← MUST be in subdirectory!
|
||||
└── SKILL.md ← Must be named exactly SKILL.md
|
||||
|
||||
.claude/skills/ ← Project skills (in project root)
|
||||
└── your-skill-name/ ← MUST be in subdirectory!
|
||||
└── SKILL.md ← Must be named exactly SKILL.md
|
||||
```
|
||||
|
||||
**Common mistake**: Putting `SKILL.md` directly in `~/.claude/skills/` ❌
|
||||
|
||||
### 2. SKILL.md Format (Mandatory YAML Frontmatter)
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: your-skill-name
|
||||
description: What it does AND when to use it. Include trigger keywords users might say.
|
||||
---
|
||||
|
||||
# Your Skill Title
|
||||
|
||||
Rest of your markdown content here...
|
||||
```
|
||||
|
||||
**Critical rules**:
|
||||
- Opening `---` MUST be on line 1
|
||||
- `name` field: lowercase, hyphens only, max 64 chars
|
||||
- `description` field: max 1024 chars, MUST include activation triggers
|
||||
- Closing `---` before any markdown content
|
||||
- No YAML frontmatter = skill won't work!
|
||||
|
||||
## Steps
|
||||
|
||||
### Step 1: Gather Skill Information
|
||||
|
||||
Ask the user for the following information (use AskUserQuestion if appropriate):
|
||||
|
||||
1. **Skill Name**:
|
||||
- Lowercase, hyphens only
|
||||
- Max 64 characters
|
||||
- Example: `python-data-science`, `kubernetes-expert`, `react-hooks`
|
||||
|
||||
2. **Skill Purpose**:
|
||||
- What expertise does this skill provide?
|
||||
- What questions should it answer?
|
||||
- Example: "Python data science best practices"
|
||||
|
||||
3. **Activation Triggers**:
|
||||
- Keywords users might say
|
||||
- Commands or patterns to detect
|
||||
- Example: "pandas, numpy, matplotlib, jupyter notebooks, Python data analysis"
|
||||
|
||||
4. **Skill Location**:
|
||||
- Personal skill: `~/.claude/skills/`
|
||||
- Project skill: `.claude/skills/` (in project root)
|
||||
|
||||
5. **Optional Tool Restrictions**:
|
||||
- Should this skill be read-only?
|
||||
- Allowed tools: Read, Grep, Glob, WebSearch, etc.
|
||||
- Leave empty for no restrictions
|
||||
|
||||
### Step 2: Validate Skill Name
|
||||
|
||||
**Validation rules**:
|
||||
```bash
|
||||
# Check format (lowercase, hyphens only)
|
||||
if [[ ! "$skill_name" =~ ^[a-z0-9-]+$ ]]; then
|
||||
echo "❌ Invalid name: must be lowercase with hyphens only"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check length (max 64 chars)
|
||||
if [ ${#skill_name} -gt 64 ]; then
|
||||
echo "❌ Invalid name: must be 64 characters or less"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check no consecutive hyphens
|
||||
if [[ "$skill_name" =~ -- ]]; then
|
||||
echo "❌ Invalid name: no consecutive hyphens allowed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check doesn't start/end with hyphen
|
||||
if [[ "$skill_name" =~ ^- ]] || [[ "$skill_name" =~ -$ ]]; then
|
||||
echo "❌ Invalid name: cannot start or end with hyphen"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### Step 3: Generate Skill Description
|
||||
|
||||
**Requirements**:
|
||||
- Max 1024 characters
|
||||
- Must include activation triggers
|
||||
- Must explain when to use the skill
|
||||
- Include keyword variations (e.g., "k8s, kubernetes, kubectl")
|
||||
|
||||
**Template**:
|
||||
```
|
||||
[What the skill does]. [When to use it]. Activates for: [keyword1], [keyword2], [keyword3], [phrase1], [phrase2].
|
||||
```
|
||||
|
||||
**Examples**:
|
||||
|
||||
```yaml
|
||||
# Command-based skill
|
||||
description: Kubernetes expert. Explains kubectl commands, pod management, deployments. Activates for: kubectl, k8s, kubernetes, pods, deployments, services, namespaces.
|
||||
|
||||
# Framework skill
|
||||
description: React expert for hooks, components, state management. Activates for: React, useState, useEffect, components, JSX, props, virtual DOM, React hooks.
|
||||
|
||||
# Project-specific skill
|
||||
description: MyCompany API documentation. Explains endpoints, authentication, rate limits. Activates for: MyCompany API, /api/v1, authentication token, rate limit, API key.
|
||||
```
|
||||
|
||||
### Step 4: Create Skill Content Structure
|
||||
|
||||
**Recommended sections**:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: your-skill-name
|
||||
description: [Generated description with triggers]
|
||||
---
|
||||
|
||||
# [Skill Title]
|
||||
|
||||
## What I Know
|
||||
|
||||
[Bullet list of expertise areas]
|
||||
- Topic 1
|
||||
- Topic 2
|
||||
- Topic 3
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Ask me about:
|
||||
- "How do I [use case 1]..."
|
||||
- "What's the best way to [use case 2]..."
|
||||
- "[Topic] tips and best practices"
|
||||
|
||||
## Key Concepts
|
||||
|
||||
### [Concept 1]
|
||||
|
||||
[Explanation]
|
||||
|
||||
### [Concept 2]
|
||||
|
||||
[Explanation]
|
||||
|
||||
## Examples
|
||||
|
||||
### [Example 1: Common Task]
|
||||
|
||||
```[language]
|
||||
[code example]
|
||||
```
|
||||
|
||||
**Explanation**: [Why this works]
|
||||
|
||||
### [Example 2: Advanced Usage]
|
||||
|
||||
```[language]
|
||||
[code example]
|
||||
```
|
||||
|
||||
**Explanation**: [When to use this pattern]
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. ✅ **[Practice 1]**: [Explanation]
|
||||
2. ✅ **[Practice 2]**: [Explanation]
|
||||
3. ⚠️ **[Anti-pattern to avoid]**: [Why to avoid]
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### [Pattern 1]
|
||||
[Implementation details]
|
||||
|
||||
### [Pattern 2]
|
||||
[Implementation details]
|
||||
|
||||
## Resources
|
||||
|
||||
- [Documentation link]
|
||||
- [Tutorial link]
|
||||
- [Reference link]
|
||||
```
|
||||
|
||||
### Step 5: Handle Optional Tool Restrictions
|
||||
|
||||
**If user wants read-only skill**:
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: documentation-helper
|
||||
description: Documentation expert for project docs
|
||||
allowed-tools: Read, Grep, Glob, WebSearch
|
||||
---
|
||||
```
|
||||
|
||||
**Available tools**:
|
||||
- `Read` - Read files
|
||||
- `Write` - Create/overwrite files
|
||||
- `Edit` - Edit existing files
|
||||
- `Grep` - Search file contents
|
||||
- `Glob` - Find files by pattern
|
||||
- `Bash` - Execute bash commands
|
||||
- `WebSearch` - Search the web
|
||||
- `WebFetch` - Fetch web content
|
||||
- `TodoWrite` - Manage todos
|
||||
- `AskUserQuestion` - Ask user questions
|
||||
|
||||
**Tool restriction patterns**:
|
||||
|
||||
```yaml
|
||||
# Read-only (no modifications)
|
||||
allowed-tools: Read, Grep, Glob, WebSearch
|
||||
|
||||
# Documentation expert (can create docs)
|
||||
allowed-tools: Read, Grep, Glob, Write, Edit
|
||||
|
||||
# Analysis expert (no file modifications)
|
||||
allowed-tools: Read, Grep, Glob, Bash
|
||||
|
||||
# Full access (no restrictions)
|
||||
# (omit allowed-tools field)
|
||||
```
|
||||
|
||||
### Step 6: Create Skill Directory and File
|
||||
|
||||
**Implementation**:
|
||||
|
||||
```bash
|
||||
# Determine full path
|
||||
if [ "$location" = "personal" ]; then
|
||||
skill_dir="$HOME/.claude/skills/$skill_name"
|
||||
else
|
||||
skill_dir="$PWD/.claude/skills/$skill_name"
|
||||
fi
|
||||
|
||||
# Create directory
|
||||
mkdir -p "$skill_dir"
|
||||
|
||||
# Create SKILL.md
|
||||
cat > "$skill_dir/SKILL.md" <<'EOF'
|
||||
---
|
||||
name: $skill_name
|
||||
description: $description
|
||||
$allowed_tools_line
|
||||
---
|
||||
|
||||
# $skill_title
|
||||
|
||||
$skill_content
|
||||
EOF
|
||||
|
||||
echo "✅ Skill created at: $skill_dir/SKILL.md"
|
||||
```
|
||||
|
||||
### Step 7: Validate Skill Structure
|
||||
|
||||
**Validation checklist**:
|
||||
|
||||
```bash
|
||||
# 1. Check SKILL.md exists
|
||||
if [ ! -f "$skill_dir/SKILL.md" ]; then
|
||||
echo "❌ SKILL.md not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 2. Check YAML frontmatter
|
||||
if ! head -1 "$skill_dir/SKILL.md" | grep -q '^---$'; then
|
||||
echo "❌ SKILL.md must start with '---'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 3. Check required fields
|
||||
if ! grep -q '^name:' "$skill_dir/SKILL.md"; then
|
||||
echo "❌ Missing 'name' field in YAML frontmatter"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q '^description:' "$skill_dir/SKILL.md"; then
|
||||
echo "❌ Missing 'description' field in YAML frontmatter"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 4. Check closing ---
|
||||
if ! sed -n '2,10p' "$skill_dir/SKILL.md" | grep -q '^---$'; then
|
||||
echo "❌ Missing closing '---' in YAML frontmatter"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 5. Check description length
|
||||
desc_length=$(grep '^description:' "$skill_dir/SKILL.md" | sed 's/^description: *//' | wc -c)
|
||||
if [ "$desc_length" -gt 1024 ]; then
|
||||
echo "⚠️ Warning: Description is ${desc_length} characters (max 1024)"
|
||||
fi
|
||||
|
||||
echo "✅ Skill structure validated successfully"
|
||||
```
|
||||
|
||||
### Step 8: Provide Next Steps
|
||||
|
||||
**User instructions**:
|
||||
|
||||
```
|
||||
✅ Skill created successfully!
|
||||
|
||||
📁 Location: $skill_dir/SKILL.md
|
||||
|
||||
📝 Next steps:
|
||||
|
||||
1. Review the skill content and customize as needed
|
||||
2. Test the skill by asking a trigger question
|
||||
3. Restart Claude Code to load the skill
|
||||
4. Verify activation with a test question
|
||||
|
||||
🔄 To restart Claude Code:
|
||||
- Close and reopen the application
|
||||
- OR use /restart command (if available)
|
||||
|
||||
🧪 Test your skill:
|
||||
Ask: "[example trigger question based on description]"
|
||||
|
||||
📚 Documentation:
|
||||
- Skill format: ~/CLAUDE.md (your quick reference)
|
||||
- Activation patterns: Description keywords determine when skill loads
|
||||
- Tool restrictions: Optional 'allowed-tools' field limits capabilities
|
||||
|
||||
⚠️ Common issues:
|
||||
- Skill doesn't activate → Check description has clear triggers
|
||||
- YAML errors → Verify frontmatter format (opening/closing ---)
|
||||
- File not found → Ensure SKILL.md is in subdirectory
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Python Data Science Skill
|
||||
|
||||
**Input**:
|
||||
- Name: `python-data-science`
|
||||
- Purpose: "Python best practices for data science projects"
|
||||
- Triggers: "pandas, numpy, matplotlib, jupyter notebooks, Python data analysis"
|
||||
- Location: Personal
|
||||
- Tool restrictions: None
|
||||
|
||||
**Output** (`~/.claude/skills/python-data-science/SKILL.md`):
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: python-data-science
|
||||
description: Python best practices for data science projects. Explains pandas DataFrame operations, NumPy arrays, matplotlib visualizations, and Jupyter notebook workflows. Activates for: pandas, numpy, matplotlib, jupyter notebooks, Python data analysis, data science, scientific computing.
|
||||
---
|
||||
|
||||
# Python Data Science Skill
|
||||
|
||||
## What I Know
|
||||
|
||||
- Pandas DataFrame operations and transformations
|
||||
- NumPy array manipulation and vectorization
|
||||
- Matplotlib and Seaborn visualizations
|
||||
- Jupyter notebook best practices
|
||||
- Data cleaning and preprocessing
|
||||
- Statistical analysis and modeling
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Ask me about:
|
||||
- "How do I use pandas to..."
|
||||
- "What's the best way to visualize..."
|
||||
- "Python data analysis tips"
|
||||
- "NumPy array operations"
|
||||
- "Jupyter notebook shortcuts"
|
||||
|
||||
## Key Concepts
|
||||
|
||||
### Pandas DataFrames
|
||||
|
||||
DataFrames are the core data structure for tabular data in Python:
|
||||
- Rows and columns with labels
|
||||
- Rich indexing and selection capabilities
|
||||
- Built-in aggregation and transformation methods
|
||||
|
||||
### NumPy Arrays
|
||||
|
||||
Efficient numerical computing with multi-dimensional arrays:
|
||||
- Vectorized operations (avoid loops!)
|
||||
- Broadcasting for element-wise operations
|
||||
- Linear algebra and statistical functions
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Loading and Exploring Data
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
|
||||
# Load CSV file
|
||||
df = pd.read_csv('data.csv')
|
||||
|
||||
# Quick exploration
|
||||
print(df.head()) # First 5 rows
|
||||
print(df.info()) # Column types and nulls
|
||||
print(df.describe()) # Statistical summary
|
||||
```
|
||||
|
||||
**Explanation**: Always start with exploration to understand your data structure, types, and missing values.
|
||||
|
||||
### Example 2: Data Cleaning
|
||||
|
||||
```python
|
||||
# Handle missing values
|
||||
df_clean = df.dropna() # Drop rows with any nulls
|
||||
df_filled = df.fillna(0) # Fill nulls with 0
|
||||
df_ffill = df.fillna(method='ffill') # Forward fill
|
||||
|
||||
# Remove duplicates
|
||||
df_unique = df.drop_duplicates()
|
||||
```
|
||||
|
||||
**Explanation**: Choose the right strategy based on your data and analysis goals.
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. ✅ **Use vectorized operations**: Avoid Python loops, use pandas/numpy methods
|
||||
2. ✅ **Chain operations**: `df.groupby('col').agg('mean').sort_values()`
|
||||
3. ✅ **Copy data explicitly**: Use `.copy()` to avoid SettingWithCopyWarning
|
||||
4. ⚠️ **Avoid iterrows()**: Extremely slow, use `.apply()` or vectorization instead
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Groupby-Aggregation
|
||||
```python
|
||||
df.groupby('category').agg({
|
||||
'sales': 'sum',
|
||||
'quantity': 'mean',
|
||||
'price': ['min', 'max']
|
||||
})
|
||||
```
|
||||
|
||||
### Time Series Resampling
|
||||
```python
|
||||
df.set_index('date').resample('M').mean()
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- [Pandas Documentation](https://pandas.pydata.org/docs/)
|
||||
- [NumPy User Guide](https://numpy.org/doc/stable/user/)
|
||||
- [Matplotlib Gallery](https://matplotlib.org/stable/gallery/index.html)
|
||||
```
|
||||
|
||||
### Example 2: Read-Only Documentation Skill
|
||||
|
||||
**Input**:
|
||||
- Name: `project-docs-helper`
|
||||
- Purpose: "Project documentation expert"
|
||||
- Triggers: "documentation, docs, readme, API reference"
|
||||
- Location: Project (`.claude/skills/`)
|
||||
- Tool restrictions: Read, Grep, Glob, WebSearch
|
||||
|
||||
**Output** (`.claude/skills/project-docs-helper/SKILL.md`):
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: project-docs-helper
|
||||
description: Project documentation expert. Helps find and explain documentation, API references, and README files. Read-only access for safe documentation browsing. Activates for: documentation, docs, readme, API reference, how to use, user guide.
|
||||
allowed-tools: Read, Grep, Glob, WebSearch
|
||||
---
|
||||
|
||||
# Project Documentation Helper
|
||||
|
||||
## What I Know
|
||||
|
||||
- Location of all project documentation
|
||||
- API reference structure
|
||||
- README and getting started guides
|
||||
- Architecture documentation
|
||||
- Contributing guidelines
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Ask me about:
|
||||
- "Where is the documentation for..."
|
||||
- "How do I use [feature]..."
|
||||
- "What APIs are available..."
|
||||
- "Getting started with this project"
|
||||
|
||||
## Documentation Structure
|
||||
|
||||
This project follows standard documentation patterns:
|
||||
- `/docs/` - Main documentation folder
|
||||
- `README.md` - Getting started guide
|
||||
- `API.md` - API reference
|
||||
- `CONTRIBUTING.md` - Contribution guidelines
|
||||
- `ARCHITECTURE.md` - System design
|
||||
|
||||
## How to Find Information
|
||||
|
||||
### Search by Topic
|
||||
I can search through all documentation files to find information about specific topics.
|
||||
|
||||
### Navigate by Structure
|
||||
I understand the documentation hierarchy and can guide you to the right files.
|
||||
|
||||
### Explain Concepts
|
||||
I can read and explain complex documentation sections in simpler terms.
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. ✅ **Check README first**: Start with README.md for project overview
|
||||
2. ✅ **Use search**: Ask me to search docs instead of browsing manually
|
||||
3. ✅ **Verify versions**: Documentation may be version-specific
|
||||
4. ⚠️ **Read-only**: This skill cannot modify documentation
|
||||
```
|
||||
|
||||
## Validation and Testing
|
||||
|
||||
### Post-Creation Validation
|
||||
|
||||
**Run these checks after creation**:
|
||||
|
||||
```bash
|
||||
# 1. File exists in correct location
|
||||
ls "$skill_dir/SKILL.md"
|
||||
|
||||
# 2. YAML frontmatter is valid
|
||||
head -10 "$skill_dir/SKILL.md"
|
||||
|
||||
# Should see:
|
||||
# ---
|
||||
# name: your-skill-name
|
||||
# description: ...
|
||||
# ---
|
||||
|
||||
# 3. No syntax errors
|
||||
node -e "
|
||||
const fs = require('fs');
|
||||
const yaml = require('js-yaml');
|
||||
const content = fs.readFileSync('$skill_dir/SKILL.md', 'utf-8');
|
||||
const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);
|
||||
if (!match) {
|
||||
console.error('❌ No YAML frontmatter found');
|
||||
process.exit(1);
|
||||
}
|
||||
try {
|
||||
const data = yaml.load(match[1]);
|
||||
console.log('✅ Valid YAML:', JSON.stringify(data, null, 2));
|
||||
} catch (e) {
|
||||
console.error('❌ YAML parsing error:', e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
"
|
||||
```
|
||||
|
||||
### Testing Activation
|
||||
|
||||
**Steps**:
|
||||
1. Create skill
|
||||
2. Restart Claude Code
|
||||
3. Ask a question with trigger keywords
|
||||
4. Verify skill activates (should see skill content in context)
|
||||
|
||||
**Test questions based on examples**:
|
||||
- Python Data Science: "How do I use pandas to read a CSV file?"
|
||||
- Documentation Helper: "Where is the API documentation?"
|
||||
- Kubernetes Expert: "How do I list all pods in a namespace?"
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Skill Doesn't Activate
|
||||
|
||||
**Possible causes**:
|
||||
|
||||
1. **Claude Code not restarted**: Skills only load on startup
|
||||
- **Fix**: Restart Claude Code
|
||||
|
||||
2. **Missing trigger keywords**: Description doesn't match user's question
|
||||
- **Fix**: Add more keyword variations to description
|
||||
|
||||
3. **YAML syntax errors**: Frontmatter is invalid
|
||||
- **Fix**: Validate YAML format (use checker above)
|
||||
|
||||
4. **Wrong file location**: SKILL.md not in subdirectory
|
||||
- **Fix**: Move to `skills/skill-name/SKILL.md`
|
||||
|
||||
5. **Name mismatch**: YAML name doesn't match directory name
|
||||
- **Fix**: Ensure consistency (can be different, but confusing)
|
||||
|
||||
### YAML Parsing Errors
|
||||
|
||||
**Common mistakes**:
|
||||
|
||||
```yaml
|
||||
# ❌ WRONG: Missing closing ---
|
||||
---
|
||||
name: my-skill
|
||||
description: My skill description
|
||||
|
||||
# ✅ CORRECT: Closing --- present
|
||||
---
|
||||
name: my-skill
|
||||
description: My skill description
|
||||
---
|
||||
|
||||
# ❌ WRONG: Invalid characters in name
|
||||
---
|
||||
name: My Skill Name
|
||||
---
|
||||
|
||||
# ✅ CORRECT: Lowercase with hyphens
|
||||
---
|
||||
name: my-skill-name
|
||||
---
|
||||
|
||||
# ❌ WRONG: Description too long (>1024 chars)
|
||||
---
|
||||
name: skill
|
||||
description: [2000 character description]
|
||||
---
|
||||
|
||||
# ✅ CORRECT: Concise description (<1024 chars)
|
||||
---
|
||||
name: skill
|
||||
description: Focused description with key triggers
|
||||
---
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
1. **Be specific**: `react-hooks` not `react`
|
||||
2. **Use domain language**: `kubernetes-expert` not `k8s-helper`
|
||||
3. **Avoid redundancy**: `python-data-science` not `python-data-science-skill`
|
||||
4. **Max 3 words**: Keep names concise
|
||||
|
||||
### Description Writing
|
||||
|
||||
1. **Front-load purpose**: Start with what the skill does
|
||||
2. **List all variations**: Include abbreviations (k8s, kubernetes)
|
||||
3. **Use action words**: "Explains", "Helps with", "Provides guidance"
|
||||
4. **Include examples**: "React hooks (useState, useEffect, useContext)"
|
||||
|
||||
### Content Structure
|
||||
|
||||
1. **Start simple**: Basic examples before advanced patterns
|
||||
2. **Use headings**: Clear section organization
|
||||
3. **Include code**: Concrete examples over abstract explanations
|
||||
4. **Anti-patterns**: Show what NOT to do (⚠️ warnings)
|
||||
|
||||
### Tool Restrictions
|
||||
|
||||
1. **Read-only by default**: Start restrictive, expand if needed
|
||||
2. **Justify access**: Only grant Write/Edit if skill creates files
|
||||
3. **Document reasons**: Explain why tools are needed
|
||||
|
||||
## Summary
|
||||
|
||||
**Key steps**:
|
||||
1. ✅ Validate skill name (lowercase, hyphens, max 64 chars)
|
||||
2. ✅ Create description with triggers (max 1024 chars)
|
||||
3. ✅ Choose skill location (personal vs project)
|
||||
4. ✅ Add tool restrictions if read-only
|
||||
5. ✅ Generate SKILL.md with YAML frontmatter
|
||||
6. ✅ Validate structure (frontmatter, fields, format)
|
||||
7. ✅ Restart Claude Code
|
||||
8. ✅ Test with trigger question
|
||||
|
||||
**Remember**: Restart Claude Code after creating or modifying skills!
|
||||
751
commands/specweave-tooling-skill-package.md
Normal file
751
commands/specweave-tooling-skill-package.md
Normal file
@@ -0,0 +1,751 @@
|
||||
---
|
||||
name: specweave-tooling:skill-package
|
||||
description: Package Claude Code skill for distribution via npm, GitHub, or direct sharing. Creates distributable archives with installation instructions and validation.
|
||||
---
|
||||
|
||||
# Package Skill for Distribution
|
||||
|
||||
**Distribution-Ready Packaging**: Create shareable skill packages with installation scripts and documentation.
|
||||
|
||||
You are helping the user package a Claude Code skill for distribution to others.
|
||||
|
||||
## Distribution Methods
|
||||
|
||||
### 1. NPM Package
|
||||
- Professional distribution
|
||||
- Versioning and updates
|
||||
- `npm install` workflow
|
||||
- Best for public skills
|
||||
|
||||
### 2. GitHub Repository
|
||||
- Source control integration
|
||||
- Easy cloning and updates
|
||||
- Issue tracking
|
||||
- Best for collaborative skills
|
||||
|
||||
### 3. Direct Archive (.tar.gz)
|
||||
- Self-contained package
|
||||
- No dependencies
|
||||
- Manual installation
|
||||
- Best for private/internal sharing
|
||||
|
||||
### 4. Plugin Bundle
|
||||
- Multiple skills in one package
|
||||
- Shared dependencies
|
||||
- Professional presentation
|
||||
- Best for skill collections
|
||||
|
||||
## Steps
|
||||
|
||||
### Step 1: Validate Skill
|
||||
|
||||
**Before packaging, ensure skill is valid**:
|
||||
|
||||
```bash
|
||||
validate_before_package() {
|
||||
local skill_path="$1"
|
||||
|
||||
echo "Validating skill before packaging..."
|
||||
|
||||
# Run validation (from skill-validate command)
|
||||
if ! validate_skill "$skill_path"; then
|
||||
echo "❌ Skill validation failed"
|
||||
echo " Fix errors before packaging"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "✅ Skill validation passed"
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Gather Package Metadata
|
||||
|
||||
**Collect information for package**:
|
||||
|
||||
1. **Package Name**: npm-compatible name (e.g., `claude-skill-python-data-science`)
|
||||
2. **Version**: Semantic versioning (e.g., `1.0.0`)
|
||||
3. **Description**: Brief summary for package managers
|
||||
4. **Author**: Name and email
|
||||
5. **License**: MIT, Apache-2.0, etc.
|
||||
6. **Repository**: GitHub URL (optional)
|
||||
7. **Keywords**: For discoverability
|
||||
|
||||
**Example**:
|
||||
```json
|
||||
{
|
||||
"name": "claude-skill-python-data-science",
|
||||
"version": "1.0.0",
|
||||
"description": "Python data science expert skill for Claude Code",
|
||||
"author": "Your Name <email@example.com>",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/username/claude-skill-python-data-science",
|
||||
"keywords": ["claude", "skill", "python", "data-science", "pandas", "numpy"]
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Create Package Structure
|
||||
|
||||
**Standard package structure**:
|
||||
|
||||
```
|
||||
package-name/
|
||||
├── README.md # Installation and usage
|
||||
├── LICENSE # License file
|
||||
├── package.json # NPM metadata (if NPM)
|
||||
├── install.sh # Installation script
|
||||
├── uninstall.sh # Uninstall script
|
||||
├── skill/ # Skill files
|
||||
│ └── SKILL.md # The actual skill
|
||||
└── examples/ # Usage examples (optional)
|
||||
└── example-conversation.md
|
||||
```
|
||||
|
||||
**Create structure**:
|
||||
|
||||
```bash
|
||||
create_package_structure() {
|
||||
local skill_path="$1"
|
||||
local package_name="$2"
|
||||
local package_dir="$3"
|
||||
|
||||
# Create directories
|
||||
mkdir -p "$package_dir/skill"
|
||||
mkdir -p "$package_dir/examples"
|
||||
|
||||
# Copy skill
|
||||
cp "$skill_path" "$package_dir/skill/SKILL.md"
|
||||
|
||||
echo "✅ Package structure created"
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: Generate README.md
|
||||
|
||||
**Comprehensive README template**:
|
||||
|
||||
```markdown
|
||||
# [Skill Name]
|
||||
|
||||
[Brief description of what the skill does]
|
||||
|
||||
## Installation
|
||||
|
||||
### Personal Skills (Recommended)
|
||||
|
||||
```bash
|
||||
# Clone or download this repository
|
||||
git clone [repository-url]
|
||||
|
||||
# Run installation script
|
||||
cd [package-name]
|
||||
bash install.sh
|
||||
```
|
||||
|
||||
Or manually:
|
||||
|
||||
```bash
|
||||
# Copy skill to personal skills directory
|
||||
mkdir -p ~/.claude/skills/[skill-name]
|
||||
cp skill/SKILL.md ~/.claude/skills/[skill-name]/SKILL.md
|
||||
```
|
||||
|
||||
### Project Skills
|
||||
|
||||
```bash
|
||||
# Copy skill to project skills directory
|
||||
mkdir -p .claude/skills/[skill-name]
|
||||
cp skill/SKILL.md .claude/skills/[skill-name]/SKILL.md
|
||||
```
|
||||
|
||||
### NPM (if published)
|
||||
|
||||
```bash
|
||||
npm install -g [package-name]
|
||||
```
|
||||
|
||||
## Activation
|
||||
|
||||
This skill activates automatically when you mention:
|
||||
- [Trigger keyword 1]
|
||||
- [Trigger keyword 2]
|
||||
- [Trigger phrase 1]
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: [Use Case]
|
||||
|
||||
**You ask:**
|
||||
> [Example question]
|
||||
|
||||
**Skill provides:**
|
||||
[Description of response]
|
||||
|
||||
### Example 2: [Use Case]
|
||||
|
||||
**You ask:**
|
||||
> [Example question]
|
||||
|
||||
**Skill provides:**
|
||||
[Description of response]
|
||||
|
||||
## Features
|
||||
|
||||
- ✅ [Feature 1]
|
||||
- ✅ [Feature 2]
|
||||
- ✅ [Feature 3]
|
||||
|
||||
## What This Skill Knows
|
||||
|
||||
[Bullet list of expertise areas]
|
||||
|
||||
## Uninstallation
|
||||
|
||||
```bash
|
||||
bash uninstall.sh
|
||||
```
|
||||
|
||||
Or manually:
|
||||
|
||||
```bash
|
||||
rm -rf ~/.claude/skills/[skill-name]
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[License name] - See LICENSE file for details
|
||||
|
||||
## Author
|
||||
|
||||
[Author name and contact]
|
||||
|
||||
## Contributing
|
||||
|
||||
[Contribution guidelines if applicable]
|
||||
|
||||
## Version History
|
||||
|
||||
### 1.0.0 (YYYY-MM-DD)
|
||||
- Initial release
|
||||
- [Feature 1]
|
||||
- [Feature 2]
|
||||
```
|
||||
|
||||
**Generate README**:
|
||||
|
||||
```bash
|
||||
generate_readme() {
|
||||
local package_dir="$1"
|
||||
local skill_name="$2"
|
||||
local description="$3"
|
||||
local author="$4"
|
||||
local license="$5"
|
||||
|
||||
cat > "$package_dir/README.md" <<EOF
|
||||
# $skill_name
|
||||
|
||||
$description
|
||||
|
||||
## Installation
|
||||
|
||||
### Personal Skills (Recommended)
|
||||
|
||||
\`\`\`bash
|
||||
# Clone or download this repository
|
||||
git clone [repository-url]
|
||||
|
||||
# Run installation script
|
||||
cd [package-name]
|
||||
bash install.sh
|
||||
\`\`\`
|
||||
|
||||
Or manually:
|
||||
|
||||
\`\`\`bash
|
||||
# Copy skill to personal skills directory
|
||||
mkdir -p ~/.claude/skills/$skill_name
|
||||
cp skill/SKILL.md ~/.claude/skills/$skill_name/SKILL.md
|
||||
\`\`\`
|
||||
|
||||
## Activation
|
||||
|
||||
This skill activates automatically when needed.
|
||||
|
||||
## License
|
||||
|
||||
$license
|
||||
|
||||
## Author
|
||||
|
||||
$author
|
||||
EOF
|
||||
|
||||
echo "✅ README.md generated"
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5: Create Installation Script
|
||||
|
||||
**Universal installation script** (`install.sh`):
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Skill configuration
|
||||
SKILL_NAME="[skill-name]"
|
||||
SKILL_DISPLAY_NAME="[Skill Display Name]"
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "INSTALLING: $SKILL_DISPLAY_NAME"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# Check if skill already installed
|
||||
if [ -d "$HOME/.claude/skills/$SKILL_NAME" ]; then
|
||||
echo -e "${YELLOW}⚠️ Skill already installed at: ~/.claude/skills/$SKILL_NAME${NC}"
|
||||
echo ""
|
||||
read -p "Overwrite existing installation? (y/N) " -n 1 -r
|
||||
echo ""
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "Installation cancelled."
|
||||
exit 0
|
||||
fi
|
||||
rm -rf "$HOME/.claude/skills/$SKILL_NAME"
|
||||
fi
|
||||
|
||||
# Create skills directory if needed
|
||||
mkdir -p "$HOME/.claude/skills"
|
||||
|
||||
# Copy skill
|
||||
echo "📦 Installing skill..."
|
||||
mkdir -p "$HOME/.claude/skills/$SKILL_NAME"
|
||||
cp skill/SKILL.md "$HOME/.claude/skills/$SKILL_NAME/SKILL.md"
|
||||
|
||||
# Validate installation
|
||||
if [ -f "$HOME/.claude/skills/$SKILL_NAME/SKILL.md" ]; then
|
||||
echo -e "${GREEN}✅ Installation successful!${NC}"
|
||||
echo ""
|
||||
echo "📁 Installed to: ~/.claude/skills/$SKILL_NAME/"
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "NEXT STEPS"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "1. 🔄 Restart Claude Code to load the skill"
|
||||
echo "2. 🧪 Test the skill by asking a relevant question"
|
||||
echo "3. 📚 See README.md for usage examples"
|
||||
echo ""
|
||||
echo "To uninstall: bash uninstall.sh"
|
||||
echo ""
|
||||
else
|
||||
echo -e "${RED}❌ Installation failed${NC}"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
**Generate install.sh**:
|
||||
|
||||
```bash
|
||||
generate_install_script() {
|
||||
local package_dir="$1"
|
||||
local skill_name="$2"
|
||||
local skill_display_name="$3"
|
||||
|
||||
cat > "$package_dir/install.sh" <<'INSTALL_SCRIPT'
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# [Installation script content from above]
|
||||
INSTALL_SCRIPT
|
||||
|
||||
# Make executable
|
||||
chmod +x "$package_dir/install.sh"
|
||||
|
||||
echo "✅ install.sh generated"
|
||||
}
|
||||
```
|
||||
|
||||
### Step 6: Create Uninstallation Script
|
||||
|
||||
**Uninstallation script** (`uninstall.sh`):
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Skill configuration
|
||||
SKILL_NAME="[skill-name]"
|
||||
SKILL_DISPLAY_NAME="[Skill Display Name]"
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "UNINSTALLING: $SKILL_DISPLAY_NAME"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# Check if skill is installed
|
||||
if [ ! -d "$HOME/.claude/skills/$SKILL_NAME" ]; then
|
||||
echo -e "${YELLOW}⚠️ Skill not found at: ~/.claude/skills/$SKILL_NAME${NC}"
|
||||
echo ""
|
||||
echo "Nothing to uninstall."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Confirm uninstallation
|
||||
echo "This will remove: ~/.claude/skills/$SKILL_NAME/"
|
||||
echo ""
|
||||
read -p "Continue with uninstallation? (y/N) " -n 1 -r
|
||||
echo ""
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "Uninstallation cancelled."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Remove skill
|
||||
rm -rf "$HOME/.claude/skills/$SKILL_NAME"
|
||||
|
||||
# Verify removal
|
||||
if [ ! -d "$HOME/.claude/skills/$SKILL_NAME" ]; then
|
||||
echo -e "${GREEN}✅ Uninstallation successful!${NC}"
|
||||
echo ""
|
||||
echo "Skill removed from: ~/.claude/skills/$SKILL_NAME/"
|
||||
echo ""
|
||||
echo "🔄 Restart Claude Code to complete uninstallation"
|
||||
else
|
||||
echo -e "${RED}❌ Uninstallation failed${NC}"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### Step 7: Add License File
|
||||
|
||||
**Common licenses**:
|
||||
|
||||
**MIT License** (most permissive):
|
||||
```
|
||||
MIT License
|
||||
|
||||
Copyright (c) [year] [author]
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
|
||||
### Step 8: Create package.json (NPM Only)
|
||||
|
||||
**NPM package.json**:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "claude-skill-[skill-name]",
|
||||
"version": "1.0.0",
|
||||
"description": "[Skill description]",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"postinstall": "bash install.sh",
|
||||
"preuninstall": "bash uninstall.sh"
|
||||
},
|
||||
"keywords": [
|
||||
"claude",
|
||||
"claude-code",
|
||||
"skill",
|
||||
"[domain]"
|
||||
],
|
||||
"author": "[Author Name] <[email]>",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/[username]/[repo].git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/[username]/[repo]/issues"
|
||||
},
|
||||
"homepage": "https://github.com/[username]/[repo]#readme",
|
||||
"files": [
|
||||
"skill/",
|
||||
"install.sh",
|
||||
"uninstall.sh",
|
||||
"README.md",
|
||||
"LICENSE"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 9: Create Archive
|
||||
|
||||
**For direct distribution**:
|
||||
|
||||
```bash
|
||||
create_archive() {
|
||||
local package_dir="$1"
|
||||
local package_name="$2"
|
||||
local version="$3"
|
||||
|
||||
# Archive filename
|
||||
archive_name="${package_name}-${version}.tar.gz"
|
||||
|
||||
# Create archive
|
||||
tar -czf "$archive_name" -C "$(dirname "$package_dir")" "$(basename "$package_dir")"
|
||||
|
||||
# Verify archive
|
||||
if [ -f "$archive_name" ]; then
|
||||
echo "✅ Archive created: $archive_name"
|
||||
echo ""
|
||||
echo "Archive contents:"
|
||||
tar -tzf "$archive_name" | head -20
|
||||
echo ""
|
||||
echo "Distribution ready!"
|
||||
else
|
||||
echo "❌ Failed to create archive"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
### Step 10: Generate Distribution Instructions
|
||||
|
||||
**Include installation guide**:
|
||||
|
||||
```markdown
|
||||
# Distribution Instructions
|
||||
|
||||
## For NPM
|
||||
|
||||
1. Publish to npm:
|
||||
```bash
|
||||
npm publish
|
||||
```
|
||||
|
||||
2. Users install with:
|
||||
```bash
|
||||
npm install -g [package-name]
|
||||
```
|
||||
|
||||
## For GitHub
|
||||
|
||||
1. Push to GitHub:
|
||||
```bash
|
||||
git init
|
||||
git add .
|
||||
git commit -m "Initial commit"
|
||||
git remote add origin [repository-url]
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
2. Create release:
|
||||
- Go to GitHub → Releases → New Release
|
||||
- Tag: v1.0.0
|
||||
- Upload .tar.gz archive
|
||||
- Add release notes
|
||||
|
||||
3. Users install with:
|
||||
```bash
|
||||
git clone [repository-url]
|
||||
cd [package-name]
|
||||
bash install.sh
|
||||
```
|
||||
|
||||
## For Direct Sharing
|
||||
|
||||
1. Share the .tar.gz archive
|
||||
|
||||
2. Users install with:
|
||||
```bash
|
||||
tar -xzf [package-name]-1.0.0.tar.gz
|
||||
cd [package-name]
|
||||
bash install.sh
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
After installation, users should:
|
||||
1. Restart Claude Code
|
||||
2. Test skill activation
|
||||
3. Report issues
|
||||
```
|
||||
|
||||
## Packaging Examples
|
||||
|
||||
### Example 1: NPM Package
|
||||
|
||||
**Input**:
|
||||
- Skill: `python-data-science`
|
||||
- Distribution: NPM
|
||||
- Version: 1.0.0
|
||||
- License: MIT
|
||||
|
||||
**Output structure**:
|
||||
```
|
||||
claude-skill-python-data-science/
|
||||
├── README.md
|
||||
├── LICENSE
|
||||
├── package.json
|
||||
├── install.sh
|
||||
├── uninstall.sh
|
||||
├── skill/
|
||||
│ └── SKILL.md
|
||||
└── examples/
|
||||
└── example-conversation.md
|
||||
```
|
||||
|
||||
**package.json**:
|
||||
```json
|
||||
{
|
||||
"name": "claude-skill-python-data-science",
|
||||
"version": "1.0.0",
|
||||
"description": "Python data science expert skill for Claude Code",
|
||||
"author": "Your Name <email@example.com>",
|
||||
"license": "MIT",
|
||||
"keywords": ["claude", "skill", "python", "data-science"]
|
||||
}
|
||||
```
|
||||
|
||||
**Publishing**:
|
||||
```bash
|
||||
npm publish
|
||||
```
|
||||
|
||||
### Example 2: GitHub Repository
|
||||
|
||||
**Input**:
|
||||
- Skill: `kubernetes-expert`
|
||||
- Distribution: GitHub
|
||||
- Repository: `github.com/username/claude-skill-k8s`
|
||||
|
||||
**Setup**:
|
||||
```bash
|
||||
# Initialize repo
|
||||
git init
|
||||
git add .
|
||||
git commit -m "Initial commit: Kubernetes expert skill"
|
||||
|
||||
# Push to GitHub
|
||||
git remote add origin https://github.com/username/claude-skill-k8s.git
|
||||
git push -u origin main
|
||||
|
||||
# Create release
|
||||
gh release create v1.0.0 --title "v1.0.0" --notes "Initial release"
|
||||
```
|
||||
|
||||
**Users install**:
|
||||
```bash
|
||||
git clone https://github.com/username/claude-skill-k8s.git
|
||||
cd claude-skill-k8s
|
||||
bash install.sh
|
||||
```
|
||||
|
||||
### Example 3: Direct Archive
|
||||
|
||||
**Input**:
|
||||
- Skill: `project-docs-helper`
|
||||
- Distribution: Internal sharing
|
||||
- Archive: `project-docs-helper-1.0.0.tar.gz`
|
||||
|
||||
**Create archive**:
|
||||
```bash
|
||||
# Package structure already created
|
||||
tar -czf project-docs-helper-1.0.0.tar.gz project-docs-helper/
|
||||
|
||||
# Share archive via email, shared drive, etc.
|
||||
```
|
||||
|
||||
**Users install**:
|
||||
```bash
|
||||
tar -xzf project-docs-helper-1.0.0.tar.gz
|
||||
cd project-docs-helper
|
||||
bash install.sh
|
||||
```
|
||||
|
||||
## Quality Checklist
|
||||
|
||||
**Before distributing, verify**:
|
||||
|
||||
- [ ] ✅ Skill validated successfully
|
||||
- [ ] ✅ README.md includes installation instructions
|
||||
- [ ] ✅ LICENSE file present
|
||||
- [ ] ✅ install.sh script works correctly
|
||||
- [ ] ✅ uninstall.sh script works correctly
|
||||
- [ ] ✅ Examples included
|
||||
- [ ] ✅ Version number set
|
||||
- [ ] ✅ Author information complete
|
||||
- [ ] ✅ Repository URL (if applicable)
|
||||
- [ ] ✅ Keywords for discoverability
|
||||
- [ ] ✅ Archive created (if direct distribution)
|
||||
- [ ] ✅ Tested installation on clean system
|
||||
|
||||
## Publishing to NPM
|
||||
|
||||
**Step-by-step**:
|
||||
|
||||
```bash
|
||||
# 1. Login to npm
|
||||
npm login
|
||||
|
||||
# 2. Validate package.json
|
||||
npm pack --dry-run
|
||||
|
||||
# 3. Publish
|
||||
npm publish
|
||||
|
||||
# 4. Verify
|
||||
npm view [package-name]
|
||||
```
|
||||
|
||||
**Scope packages (recommended)**:
|
||||
```json
|
||||
{
|
||||
"name": "@your-username/claude-skill-python-data-science",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
**Package includes**:
|
||||
1. ✅ Skill file (SKILL.md)
|
||||
2. ✅ README with installation instructions
|
||||
3. ✅ LICENSE file
|
||||
4. ✅ install.sh script
|
||||
5. ✅ uninstall.sh script
|
||||
6. ✅ package.json (NPM only)
|
||||
7. ✅ Examples (optional)
|
||||
8. ✅ Archive file (direct distribution)
|
||||
|
||||
**Distribution methods**:
|
||||
1. ✅ NPM (`npm install -g`)
|
||||
2. ✅ GitHub (clone + install.sh)
|
||||
3. ✅ Direct archive (.tar.gz)
|
||||
|
||||
**Remember**: Test installation on clean system before distributing!
|
||||
858
commands/specweave-tooling-skill-validate.md
Normal file
858
commands/specweave-tooling-skill-validate.md
Normal file
@@ -0,0 +1,858 @@
|
||||
---
|
||||
name: specweave-tooling:skill-validate
|
||||
description: Validate Claude Code skill structure, YAML frontmatter, and activation triggers. Comprehensive validation with detailed error reporting and auto-fix suggestions.
|
||||
---
|
||||
|
||||
# Validate Skill Structure
|
||||
|
||||
**Comprehensive Validation**: Detect and fix skill structure issues, YAML errors, and activation problems.
|
||||
|
||||
You are helping the user validate an existing Claude Code skill to ensure it follows best practices and will activate correctly.
|
||||
|
||||
## What Gets Validated
|
||||
|
||||
### 1. Directory Structure
|
||||
- ✅ SKILL.md exists in subdirectory (not root)
|
||||
- ✅ File named exactly `SKILL.md` (case-sensitive)
|
||||
- ✅ Only one SKILL.md per directory
|
||||
|
||||
### 2. YAML Frontmatter
|
||||
- ✅ Starts with `---` on line 1
|
||||
- ✅ Contains required fields (`name`, `description`)
|
||||
- ✅ Has closing `---` before content
|
||||
- ✅ Valid YAML syntax
|
||||
- ✅ Field value constraints (length, format)
|
||||
|
||||
### 3. Content Quality
|
||||
- ✅ Description includes trigger keywords
|
||||
- ✅ Content has clear structure
|
||||
- ✅ Examples are present
|
||||
- ✅ Best practices documented
|
||||
|
||||
### 4. Activation Patterns
|
||||
- ✅ Description has sufficient triggers
|
||||
- ✅ Keyword variations included
|
||||
- ✅ Domain-specific terms present
|
||||
|
||||
## Steps
|
||||
|
||||
### Step 1: Locate Skill
|
||||
|
||||
**Ask user for skill path or name**:
|
||||
|
||||
```bash
|
||||
# Option 1: Full path
|
||||
skill_path="/path/to/skill/SKILL.md"
|
||||
|
||||
# Option 2: Skill name (search common locations)
|
||||
skill_name="python-data-science"
|
||||
|
||||
# Search order:
|
||||
# 1. ~/.claude/skills/$skill_name/SKILL.md
|
||||
# 2. .claude/skills/$skill_name/SKILL.md (project skills)
|
||||
```
|
||||
|
||||
**Auto-detection**:
|
||||
|
||||
```bash
|
||||
# Find skill by name
|
||||
find_skill() {
|
||||
local skill_name="$1"
|
||||
|
||||
# Check personal skills
|
||||
if [ -f "$HOME/.claude/skills/$skill_name/SKILL.md" ]; then
|
||||
echo "$HOME/.claude/skills/$skill_name/SKILL.md"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check project skills
|
||||
if [ -f ".claude/skills/$skill_name/SKILL.md" ]; then
|
||||
echo ".claude/skills/$skill_name/SKILL.md"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "❌ Skill not found: $skill_name" >&2
|
||||
return 1
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Validate Directory Structure
|
||||
|
||||
**Checks**:
|
||||
|
||||
```bash
|
||||
validate_directory_structure() {
|
||||
local skill_path="$1"
|
||||
local errors=0
|
||||
|
||||
# 1. Check file exists
|
||||
if [ ! -f "$skill_path" ]; then
|
||||
echo "❌ ERROR: File not found: $skill_path"
|
||||
((errors++))
|
||||
return $errors
|
||||
fi
|
||||
|
||||
# 2. Check file is named SKILL.md (case-sensitive)
|
||||
filename=$(basename "$skill_path")
|
||||
if [ "$filename" != "SKILL.md" ]; then
|
||||
echo "❌ ERROR: File must be named 'SKILL.md' (case-sensitive)"
|
||||
echo " Found: $filename"
|
||||
echo " Fix: mv '$skill_path' '$(dirname "$skill_path")/SKILL.md'"
|
||||
((errors++))
|
||||
fi
|
||||
|
||||
# 3. Check file is in subdirectory (not root of skills/)
|
||||
skill_dir=$(dirname "$skill_path")
|
||||
parent_dir=$(dirname "$skill_dir")
|
||||
parent_name=$(basename "$parent_dir")
|
||||
|
||||
if [[ "$parent_name" != "skills" ]]; then
|
||||
echo "⚠️ WARNING: Expected parent directory 'skills/'"
|
||||
echo " Found: $parent_name"
|
||||
fi
|
||||
|
||||
# 4. Check directory name format (lowercase, hyphens)
|
||||
dir_name=$(basename "$skill_dir")
|
||||
if [[ ! "$dir_name" =~ ^[a-z0-9-]+$ ]]; then
|
||||
echo "⚠️ WARNING: Directory name should be lowercase with hyphens"
|
||||
echo " Found: $dir_name"
|
||||
echo " Suggested: $(echo "$dir_name" | tr '[:upper:]' '[:lower:]' | tr '_' '-')"
|
||||
fi
|
||||
|
||||
# 5. Check for multiple SKILL.md files (only one allowed)
|
||||
skill_count=$(find "$skill_dir" -name "SKILL.md" | wc -l)
|
||||
if [ "$skill_count" -gt 1 ]; then
|
||||
echo "❌ ERROR: Multiple SKILL.md files found in directory"
|
||||
echo " Only one SKILL.md allowed per directory"
|
||||
((errors++))
|
||||
fi
|
||||
|
||||
if [ $errors -eq 0 ]; then
|
||||
echo "✅ Directory structure: PASSED"
|
||||
else
|
||||
echo "❌ Directory structure: FAILED ($errors errors)"
|
||||
fi
|
||||
|
||||
return $errors
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Validate YAML Frontmatter
|
||||
|
||||
**Checks**:
|
||||
|
||||
```bash
|
||||
validate_yaml_frontmatter() {
|
||||
local skill_path="$1"
|
||||
local errors=0
|
||||
|
||||
# 1. Check starts with ---
|
||||
first_line=$(head -1 "$skill_path")
|
||||
if [ "$first_line" != "---" ]; then
|
||||
echo "❌ ERROR: File must start with '---' (YAML frontmatter)"
|
||||
echo " Found: $first_line"
|
||||
echo " Fix: Add '---' as first line"
|
||||
((errors++))
|
||||
return $errors
|
||||
fi
|
||||
|
||||
# 2. Extract YAML frontmatter
|
||||
yaml_content=$(sed -n '2,/^---$/p' "$skill_path" | sed '$d')
|
||||
|
||||
if [ -z "$yaml_content" ]; then
|
||||
echo "❌ ERROR: Empty YAML frontmatter"
|
||||
echo " Fix: Add 'name:' and 'description:' fields"
|
||||
((errors++))
|
||||
return $errors
|
||||
fi
|
||||
|
||||
# 3. Check closing ---
|
||||
closing_line=$(sed -n '2,20p' "$skill_path" | grep -n '^---$' | head -1 | cut -d: -f1)
|
||||
if [ -z "$closing_line" ]; then
|
||||
echo "❌ ERROR: Missing closing '---' in YAML frontmatter"
|
||||
echo " Fix: Add '---' after YAML fields"
|
||||
((errors++))
|
||||
fi
|
||||
|
||||
# 4. Validate YAML syntax (using Node.js)
|
||||
yaml_check=$(node -e "
|
||||
const fs = require('fs');
|
||||
const yaml = require('js-yaml');
|
||||
const content = fs.readFileSync('$skill_path', 'utf-8');
|
||||
const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);
|
||||
if (!match) {
|
||||
console.log('ERROR: No YAML frontmatter found');
|
||||
process.exit(1);
|
||||
}
|
||||
try {
|
||||
const data = yaml.load(match[1]);
|
||||
console.log(JSON.stringify(data));
|
||||
process.exit(0);
|
||||
} catch (e) {
|
||||
console.log('ERROR: ' + e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
" 2>&1)
|
||||
|
||||
if [[ "$yaml_check" =~ ^ERROR: ]]; then
|
||||
echo "❌ ERROR: YAML syntax error"
|
||||
echo " $yaml_check"
|
||||
((errors++))
|
||||
return $errors
|
||||
fi
|
||||
|
||||
if [ $errors -eq 0 ]; then
|
||||
echo "✅ YAML frontmatter structure: PASSED"
|
||||
else
|
||||
echo "❌ YAML frontmatter structure: FAILED ($errors errors)"
|
||||
fi
|
||||
|
||||
return $errors
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: Validate Required Fields
|
||||
|
||||
**Checks**:
|
||||
|
||||
```bash
|
||||
validate_required_fields() {
|
||||
local skill_path="$1"
|
||||
local errors=0
|
||||
|
||||
# Parse YAML frontmatter
|
||||
yaml_data=$(node -e "
|
||||
const fs = require('fs');
|
||||
const yaml = require('js-yaml');
|
||||
const content = fs.readFileSync('$skill_path', 'utf-8');
|
||||
const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);
|
||||
if (match) {
|
||||
const data = yaml.load(match[1]);
|
||||
console.log(JSON.stringify(data));
|
||||
}
|
||||
")
|
||||
|
||||
# 1. Check 'name' field
|
||||
name=$(echo "$yaml_data" | node -e "
|
||||
const data = JSON.parse(require('fs').readFileSync(0, 'utf-8'));
|
||||
console.log(data.name || '');
|
||||
")
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo "❌ ERROR: Missing required field 'name'"
|
||||
echo " Fix: Add 'name: your-skill-name' to YAML frontmatter"
|
||||
((errors++))
|
||||
else
|
||||
# Validate name format
|
||||
if [[ ! "$name" =~ ^[a-z0-9-]+$ ]]; then
|
||||
echo "❌ ERROR: Invalid 'name' format: $name"
|
||||
echo " Must be lowercase with hyphens only"
|
||||
echo " Fix: name: $(echo "$name" | tr '[:upper:]' '[:lower:]' | tr '_' '-')"
|
||||
((errors++))
|
||||
fi
|
||||
|
||||
# Validate name length
|
||||
if [ ${#name} -gt 64 ]; then
|
||||
echo "❌ ERROR: 'name' too long: ${#name} characters (max 64)"
|
||||
echo " Fix: Shorten name to 64 characters or less"
|
||||
((errors++))
|
||||
fi
|
||||
|
||||
# Check no consecutive hyphens
|
||||
if [[ "$name" =~ -- ]]; then
|
||||
echo "⚠️ WARNING: 'name' has consecutive hyphens: $name"
|
||||
fi
|
||||
|
||||
# Check doesn't start/end with hyphen
|
||||
if [[ "$name" =~ ^- ]] || [[ "$name" =~ -$ ]]; then
|
||||
echo "❌ ERROR: 'name' cannot start or end with hyphen: $name"
|
||||
((errors++))
|
||||
fi
|
||||
fi
|
||||
|
||||
# 2. Check 'description' field
|
||||
description=$(echo "$yaml_data" | node -e "
|
||||
const data = JSON.parse(require('fs').readFileSync(0, 'utf-8'));
|
||||
console.log(data.description || '');
|
||||
")
|
||||
|
||||
if [ -z "$description" ]; then
|
||||
echo "❌ ERROR: Missing required field 'description'"
|
||||
echo " Fix: Add 'description: [what skill does]' to YAML frontmatter"
|
||||
((errors++))
|
||||
else
|
||||
# Validate description length
|
||||
desc_length=${#description}
|
||||
if [ $desc_length -gt 1024 ]; then
|
||||
echo "❌ ERROR: 'description' too long: $desc_length characters (max 1024)"
|
||||
echo " Fix: Shorten description to 1024 characters or less"
|
||||
((errors++))
|
||||
fi
|
||||
|
||||
# Check description has trigger keywords
|
||||
if [[ ! "$description" =~ [Aa]ctivates|[Tt]riggers|[Kk]eywords ]]; then
|
||||
echo "⚠️ WARNING: 'description' should include activation triggers"
|
||||
echo " Recommended: Add 'Activates for: keyword1, keyword2, ...'"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 3. Check optional 'allowed-tools' field
|
||||
allowed_tools=$(echo "$yaml_data" | node -e "
|
||||
const data = JSON.parse(require('fs').readFileSync(0, 'utf-8'));
|
||||
console.log(data['allowed-tools'] || '');
|
||||
")
|
||||
|
||||
if [ -n "$allowed_tools" ]; then
|
||||
# Validate tool names
|
||||
valid_tools="Read Write Edit Grep Glob Bash WebSearch WebFetch TodoWrite AskUserQuestion"
|
||||
|
||||
# Split and validate each tool
|
||||
echo "$allowed_tools" | tr ',' '\n' | while read -r tool; do
|
||||
tool=$(echo "$tool" | xargs) # trim whitespace
|
||||
if [[ ! " $valid_tools " =~ " $tool " ]]; then
|
||||
echo "⚠️ WARNING: Unknown tool in allowed-tools: $tool"
|
||||
echo " Valid tools: $valid_tools"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ $errors -eq 0 ]; then
|
||||
echo "✅ Required fields: PASSED"
|
||||
echo " name: $name"
|
||||
echo " description: ${description:0:80}..."
|
||||
[ -n "$allowed_tools" ] && echo " allowed-tools: $allowed_tools"
|
||||
else
|
||||
echo "❌ Required fields: FAILED ($errors errors)"
|
||||
fi
|
||||
|
||||
return $errors
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5: Validate Content Quality
|
||||
|
||||
**Checks**:
|
||||
|
||||
```bash
|
||||
validate_content_quality() {
|
||||
local skill_path="$1"
|
||||
local warnings=0
|
||||
|
||||
# Extract content (everything after closing ---)
|
||||
content=$(sed -n '/^---$/,/^---$/p' "$skill_path" | sed '1,2d')
|
||||
content_after=$(sed -n '/^---$/,/^---$/p' "$skill_path" | tail -n +3)
|
||||
|
||||
# 1. Check content exists
|
||||
if [ -z "$content_after" ]; then
|
||||
echo "⚠️ WARNING: No content after YAML frontmatter"
|
||||
echo " Add skill documentation, examples, and best practices"
|
||||
((warnings++))
|
||||
fi
|
||||
|
||||
# 2. Check for main heading
|
||||
if ! echo "$content_after" | grep -q '^# '; then
|
||||
echo "⚠️ WARNING: No main heading (# Title) found"
|
||||
echo " Add a descriptive title after YAML frontmatter"
|
||||
((warnings++))
|
||||
fi
|
||||
|
||||
# 3. Check for sections
|
||||
section_count=$(echo "$content_after" | grep -c '^## ')
|
||||
if [ $section_count -eq 0 ]; then
|
||||
echo "⚠️ WARNING: No sections (## Heading) found"
|
||||
echo " Recommended sections: What I Know, When to Use, Examples, Best Practices"
|
||||
((warnings++))
|
||||
elif [ $section_count -lt 3 ]; then
|
||||
echo "⚠️ WARNING: Only $section_count sections found"
|
||||
echo " Consider adding more structure for clarity"
|
||||
((warnings++))
|
||||
fi
|
||||
|
||||
# 4. Check for code examples
|
||||
if ! echo "$content_after" | grep -q '```'; then
|
||||
echo "⚠️ WARNING: No code examples found"
|
||||
echo " Add concrete examples to illustrate concepts"
|
||||
((warnings++))
|
||||
fi
|
||||
|
||||
# 5. Check for lists
|
||||
list_count=$(echo "$content_after" | grep -c '^- \|^[0-9]\. ')
|
||||
if [ $list_count -eq 0 ]; then
|
||||
echo "⚠️ WARNING: No lists found"
|
||||
echo " Use bullet points and numbered lists for clarity"
|
||||
((warnings++))
|
||||
fi
|
||||
|
||||
# 6. Check content length
|
||||
content_length=$(echo "$content_after" | wc -c)
|
||||
if [ $content_length -lt 500 ]; then
|
||||
echo "⚠️ WARNING: Content is very short ($content_length characters)"
|
||||
echo " Consider adding more detail, examples, and best practices"
|
||||
((warnings++))
|
||||
fi
|
||||
|
||||
# 7. Check for recommended sections
|
||||
recommended_sections=(
|
||||
"What I Know"
|
||||
"When to Use"
|
||||
"Examples"
|
||||
"Best Practices"
|
||||
"Common Patterns"
|
||||
)
|
||||
|
||||
missing_sections=()
|
||||
for section in "${recommended_sections[@]}"; do
|
||||
if ! echo "$content_after" | grep -iq "## $section"; then
|
||||
missing_sections+=("$section")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${#missing_sections[@]} -gt 0 ]; then
|
||||
echo "⚠️ WARNING: Missing recommended sections:"
|
||||
for section in "${missing_sections[@]}"; do
|
||||
echo " - ## $section"
|
||||
done
|
||||
((warnings++))
|
||||
fi
|
||||
|
||||
if [ $warnings -eq 0 ]; then
|
||||
echo "✅ Content quality: PASSED"
|
||||
echo " Sections: $section_count"
|
||||
echo " Content length: $content_length characters"
|
||||
else
|
||||
echo "⚠️ Content quality: $warnings warnings"
|
||||
fi
|
||||
|
||||
return 0 # Warnings don't cause failure
|
||||
}
|
||||
```
|
||||
|
||||
### Step 6: Validate Activation Patterns
|
||||
|
||||
**Checks**:
|
||||
|
||||
```bash
|
||||
validate_activation_patterns() {
|
||||
local skill_path="$1"
|
||||
local warnings=0
|
||||
|
||||
# Parse description
|
||||
description=$(node -e "
|
||||
const fs = require('fs');
|
||||
const yaml = require('js-yaml');
|
||||
const content = fs.readFileSync('$skill_path', 'utf-8');
|
||||
const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);
|
||||
if (match) {
|
||||
const data = yaml.load(match[1]);
|
||||
console.log(data.description || '');
|
||||
}
|
||||
")
|
||||
|
||||
if [ -z "$description" ]; then
|
||||
echo "⚠️ WARNING: No description to validate"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 1. Check for trigger section
|
||||
if [[ ! "$description" =~ [Aa]ctivates\ for:|[Tt]riggers:|[Kk]eywords: ]]; then
|
||||
echo "⚠️ WARNING: No explicit activation triggers in description"
|
||||
echo " Recommended: Add 'Activates for: keyword1, keyword2, ...'"
|
||||
((warnings++))
|
||||
fi
|
||||
|
||||
# 2. Count keywords (approximate)
|
||||
keyword_count=$(echo "$description" | tr ',' '\n' | grep -v '^[[:space:]]*$' | wc -l)
|
||||
if [ $keyword_count -lt 5 ]; then
|
||||
echo "⚠️ WARNING: Only $keyword_count potential triggers found"
|
||||
echo " Recommended: Include 5-10 keywords for better activation"
|
||||
((warnings++))
|
||||
fi
|
||||
|
||||
# 3. Check for keyword variations
|
||||
# Common patterns: abbreviations, full names, plurals
|
||||
if [[ "$description" =~ k8s ]] && [[ ! "$description" =~ kubernetes ]]; then
|
||||
echo "⚠️ WARNING: Include both abbreviation and full name"
|
||||
echo " Found: k8s"
|
||||
echo " Missing: kubernetes"
|
||||
((warnings++))
|
||||
fi
|
||||
|
||||
# 4. Check description clarity
|
||||
if [ ${#description} -lt 50 ]; then
|
||||
echo "⚠️ WARNING: Description is very short (${#description} chars)"
|
||||
echo " Add more context about what skill does and when to use it"
|
||||
((warnings++))
|
||||
fi
|
||||
|
||||
# 5. Check for action words
|
||||
action_words="explains|helps|provides|guides|assists|demonstrates|shows"
|
||||
if [[ ! "$description" =~ $action_words ]]; then
|
||||
echo "⚠️ WARNING: Description lacks action words"
|
||||
echo " Recommended: Use verbs like 'Explains', 'Helps with', 'Provides'"
|
||||
((warnings++))
|
||||
fi
|
||||
|
||||
if [ $warnings -eq 0 ]; then
|
||||
echo "✅ Activation patterns: PASSED"
|
||||
echo " Trigger count: ~$keyword_count"
|
||||
else
|
||||
echo "⚠️ Activation patterns: $warnings warnings"
|
||||
fi
|
||||
|
||||
return 0 # Warnings don't cause failure
|
||||
}
|
||||
```
|
||||
|
||||
### Step 7: Generate Validation Report
|
||||
|
||||
**Report format**:
|
||||
|
||||
```bash
|
||||
generate_validation_report() {
|
||||
local skill_path="$1"
|
||||
local total_errors=0
|
||||
local total_warnings=0
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "SKILL VALIDATION REPORT"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "📁 File: $skill_path"
|
||||
echo "📅 Validated: $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "VALIDATION RESULTS"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# Run all validations
|
||||
echo "1️⃣ Directory Structure"
|
||||
validate_directory_structure "$skill_path"
|
||||
total_errors=$((total_errors + $?))
|
||||
echo ""
|
||||
|
||||
echo "2️⃣ YAML Frontmatter"
|
||||
validate_yaml_frontmatter "$skill_path"
|
||||
total_errors=$((total_errors + $?))
|
||||
echo ""
|
||||
|
||||
echo "3️⃣ Required Fields"
|
||||
validate_required_fields "$skill_path"
|
||||
total_errors=$((total_errors + $?))
|
||||
echo ""
|
||||
|
||||
echo "4️⃣ Content Quality"
|
||||
validate_content_quality "$skill_path"
|
||||
# Warnings only, don't count as errors
|
||||
echo ""
|
||||
|
||||
echo "5️⃣ Activation Patterns"
|
||||
validate_activation_patterns "$skill_path"
|
||||
# Warnings only, don't count as errors
|
||||
echo ""
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "SUMMARY"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
if [ $total_errors -eq 0 ]; then
|
||||
echo "✅ VALIDATION PASSED!"
|
||||
echo ""
|
||||
echo "Your skill is properly structured and ready to use."
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " 1. Restart Claude Code to load the skill"
|
||||
echo " 2. Test with a trigger question"
|
||||
echo " 3. Verify skill activates correctly"
|
||||
else
|
||||
echo "❌ VALIDATION FAILED!"
|
||||
echo ""
|
||||
echo "Total errors: $total_errors"
|
||||
echo ""
|
||||
echo "Please fix the errors above and re-run validation."
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
|
||||
return $total_errors
|
||||
}
|
||||
```
|
||||
|
||||
### Step 8: Provide Auto-Fix Suggestions
|
||||
|
||||
**For common issues**:
|
||||
|
||||
```bash
|
||||
provide_autofix_suggestions() {
|
||||
local skill_path="$1"
|
||||
local errors="$2"
|
||||
|
||||
if [ "$errors" -eq 0 ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "AUTO-FIX SUGGESTIONS"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# Missing YAML frontmatter
|
||||
if ! head -1 "$skill_path" | grep -q '^---$'; then
|
||||
echo "🔧 FIX: Add YAML frontmatter"
|
||||
echo ""
|
||||
echo "Run this command:"
|
||||
echo ""
|
||||
echo "cat > '$skill_path' <<'EOF'"
|
||||
echo "---"
|
||||
echo "name: $(basename $(dirname "$skill_path"))"
|
||||
echo "description: [Add description with activation triggers]"
|
||||
echo "---"
|
||||
echo ""
|
||||
echo "$(cat "$skill_path")"
|
||||
echo "EOF"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Invalid name format
|
||||
name=$(grep '^name:' "$skill_path" | sed 's/^name: *//')
|
||||
if [ -n "$name" ] && [[ ! "$name" =~ ^[a-z0-9-]+$ ]]; then
|
||||
fixed_name=$(echo "$name" | tr '[:upper:]' '[:lower:]' | tr '_' '-')
|
||||
echo "🔧 FIX: Update name format"
|
||||
echo ""
|
||||
echo "Run this command:"
|
||||
echo ""
|
||||
echo "sed -i '' 's/^name: .*/name: $fixed_name/' '$skill_path'"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Missing description triggers
|
||||
description=$(grep '^description:' "$skill_path" | sed 's/^description: *//')
|
||||
if [ -n "$description" ] && [[ ! "$description" =~ [Aa]ctivates ]]; then
|
||||
echo "🔧 FIX: Add activation triggers to description"
|
||||
echo ""
|
||||
echo "Edit the description to include:"
|
||||
echo ""
|
||||
echo "description: $description Activates for: [keyword1], [keyword2], [keyword3]."
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# File in wrong location
|
||||
if [ "$(basename "$skill_path")" != "SKILL.md" ]; then
|
||||
echo "🔧 FIX: Rename file to SKILL.md"
|
||||
echo ""
|
||||
echo "Run this command:"
|
||||
echo ""
|
||||
echo "mv '$skill_path' '$(dirname "$skill_path")/SKILL.md'"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
}
|
||||
```
|
||||
|
||||
## Validation Examples
|
||||
|
||||
### Example 1: Valid Skill
|
||||
|
||||
**Input**: `~/.claude/skills/python-data-science/SKILL.md`
|
||||
|
||||
**Output**:
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
SKILL VALIDATION REPORT
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
📁 File: ~/.claude/skills/python-data-science/SKILL.md
|
||||
📅 Validated: 2025-01-15 14:30:00
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
VALIDATION RESULTS
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
1️⃣ Directory Structure
|
||||
✅ Directory structure: PASSED
|
||||
|
||||
2️⃣ YAML Frontmatter
|
||||
✅ YAML frontmatter structure: PASSED
|
||||
|
||||
3️⃣ Required Fields
|
||||
✅ Required fields: PASSED
|
||||
name: python-data-science
|
||||
description: Python best practices for data science projects. Explains pandas DataFrame...
|
||||
|
||||
4️⃣ Content Quality
|
||||
✅ Content quality: PASSED
|
||||
Sections: 6
|
||||
Content length: 3245 characters
|
||||
|
||||
5️⃣ Activation Patterns
|
||||
✅ Activation patterns: PASSED
|
||||
Trigger count: ~12
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
SUMMARY
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
✅ VALIDATION PASSED!
|
||||
|
||||
Your skill is properly structured and ready to use.
|
||||
|
||||
Next steps:
|
||||
1. Restart Claude Code to load the skill
|
||||
2. Test with a trigger question
|
||||
3. Verify skill activates correctly
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
```
|
||||
|
||||
### Example 2: Invalid Skill (Multiple Errors)
|
||||
|
||||
**Input**: `~/.claude/skills/MySkill/skill.md`
|
||||
|
||||
**Output**:
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
SKILL VALIDATION REPORT
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
📁 File: ~/.claude/skills/MySkill/skill.md
|
||||
📅 Validated: 2025-01-15 14:30:00
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
VALIDATION RESULTS
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
1️⃣ Directory Structure
|
||||
❌ ERROR: File must be named 'SKILL.md' (case-sensitive)
|
||||
Found: skill.md
|
||||
Fix: mv '~/.claude/skills/MySkill/skill.md' '~/.claude/skills/MySkill/SKILL.md'
|
||||
⚠️ WARNING: Directory name should be lowercase with hyphens
|
||||
Found: MySkill
|
||||
Suggested: myskill
|
||||
❌ Directory structure: FAILED (1 errors)
|
||||
|
||||
2️⃣ YAML Frontmatter
|
||||
❌ ERROR: File must start with '---' (YAML frontmatter)
|
||||
Found: # My Skill
|
||||
Fix: Add '---' as first line
|
||||
❌ YAML frontmatter structure: FAILED (1 errors)
|
||||
|
||||
3️⃣ Required Fields
|
||||
❌ ERROR: Missing required field 'name'
|
||||
Fix: Add 'name: your-skill-name' to YAML frontmatter
|
||||
❌ ERROR: Missing required field 'description'
|
||||
Fix: Add 'description: [what skill does]' to YAML frontmatter
|
||||
❌ Required fields: FAILED (2 errors)
|
||||
|
||||
4️⃣ Content Quality
|
||||
⚠️ WARNING: No content after YAML frontmatter
|
||||
Add skill documentation, examples, and best practices
|
||||
|
||||
5️⃣ Activation Patterns
|
||||
⚠️ WARNING: No description to validate
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
SUMMARY
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
❌ VALIDATION FAILED!
|
||||
|
||||
Total errors: 4
|
||||
|
||||
Please fix the errors above and re-run validation.
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
AUTO-FIX SUGGESTIONS
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
🔧 FIX: Add YAML frontmatter
|
||||
|
||||
Run this command:
|
||||
|
||||
cat > '~/.claude/skills/MySkill/skill.md' <<'EOF'
|
||||
---
|
||||
name: myskill
|
||||
description: [Add description with activation triggers]
|
||||
---
|
||||
|
||||
# My Skill
|
||||
EOF
|
||||
|
||||
🔧 FIX: Rename file to SKILL.md
|
||||
|
||||
Run this command:
|
||||
|
||||
mv '~/.claude/skills/MySkill/skill.md' '~/.claude/skills/MySkill/SKILL.md'
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
```
|
||||
|
||||
## Batch Validation
|
||||
|
||||
**Validate all skills in a directory**:
|
||||
|
||||
```bash
|
||||
validate_all_skills() {
|
||||
local skills_dir="$1"
|
||||
local total_skills=0
|
||||
local passed_skills=0
|
||||
local failed_skills=0
|
||||
|
||||
echo "Scanning for skills in: $skills_dir"
|
||||
echo ""
|
||||
|
||||
# Find all SKILL.md files
|
||||
while IFS= read -r skill_file; do
|
||||
((total_skills++))
|
||||
|
||||
echo "Validating: $skill_file"
|
||||
|
||||
if generate_validation_report "$skill_file"; then
|
||||
((passed_skills++))
|
||||
else
|
||||
((failed_skills++))
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
done < <(find "$skills_dir" -name "SKILL.md" -type f)
|
||||
|
||||
echo "BATCH VALIDATION SUMMARY"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "Total skills: $total_skills"
|
||||
echo "✅ Passed: $passed_skills"
|
||||
echo "❌ Failed: $failed_skills"
|
||||
echo ""
|
||||
|
||||
if [ $failed_skills -eq 0 ]; then
|
||||
echo "✅ All skills validated successfully!"
|
||||
else
|
||||
echo "⚠️ $failed_skills skill(s) need attention"
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
**Validation covers**:
|
||||
1. ✅ Directory structure (subdirectory, filename)
|
||||
2. ✅ YAML frontmatter (format, syntax)
|
||||
3. ✅ Required fields (name, description)
|
||||
4. ✅ Field constraints (length, format)
|
||||
5. ✅ Content quality (structure, examples)
|
||||
6. ✅ Activation patterns (triggers, keywords)
|
||||
|
||||
**Report includes**:
|
||||
- ✅ Pass/fail status for each check
|
||||
- ✅ Error messages with line numbers
|
||||
- ✅ Auto-fix suggestions for common issues
|
||||
- ✅ Overall summary and next steps
|
||||
|
||||
**Remember**: Fix all errors before using the skill. Restart Claude Code after fixes!
|
||||
Reference in New Issue
Block a user