SKILL.md
name: Skill Builder description: > This skill should be used when the user asks to "create a skill", "update a skill", "review my skill", "improve skill quality", "publish a skill", "generalize skill", "check for hardcoded values", "review for specific references", "validate skill for publishing", or when modifying any skill in ~/.claude/skills/. Enforces generalization rules and quality standards for skills intended for public use. version: 1.1.0 triggers: keywords: - create a skill - update a skill - review my skill - improve skill quality - publish a skill - generalize skill - check for hardcoded - specific references - validate skill - skill for publishing paths: - ~/.claude/skills/** explicit: - /skill-builder - /validate-skill
Skill Builder
Build, update, and validate Claude Code skills following best practices for public distribution.
Core Principle: Generalization for Public Users
CRITICAL: Skills in ~/.claude/skills/ may be shared publicly. Never include:
| ❌ Never Include | ✅ Use Instead |
|---|---|
| Hardcoded project names | Environment variables |
| Specific UUIDs/IDs | process.env.VAR_NAME |
| Personal API endpoints | Configurable URLs |
| Company-specific logic | Generic patterns |
| Internal team references | Generic examples |
Example: Linear Skill Refactoring
Before (project-specific):
export const INITIATIVES = {
SKILLSMITH: '5e1cebfe-f4bb-42c1-988d-af792fc4253b'
}
export async function linkAllSkillsmithProjects() { ... }
After (generalized):
export const DEFAULT_INITIATIVE_ID = process.env.LINEAR_DEFAULT_INITIATIVE_ID || ''
export async function linkProjectsToInitiative(initiativeId: string, filter?) { ... }
Behavioral Classification (ADR-025)
Every skill must declare its behavioral type. This determines how the skill interacts with users.
1. Autonomous Execution
Directive: EXECUTE, DON'T ASK
Skills that follow a prescribed workflow automatically. No permission-seeking.
| Use For | Examples |
|---|---|
| Enforcement/compliance | governance, docker-enforce |
| Automated fixes | lint-fix, format |
| CI/CD integrations | deploy, release |
2. Guided Decision
Directive: ASK, THEN EXECUTE
Skills that ask structured questions upfront, then execute based on decisions.
| Use For | Examples |
|---|---|
| Planning/architecture | wave-planner, mcp-decision-helper |
| Configuration wizards | init, setup |
| Template generators | skill-builder |
3. Interactive Exploration
Directive: ASK THROUGHOUT
Skills with ongoing dialogue. The conversation IS the value.
| Use For | Examples |
|---|---|
| Research/exploration | researcher |
| Browser automation | dev-browser |
| Debugging sessions | debugger |
4. Configurable Enforcement
Directive: USER-CONFIGURED
Skills that adapt behavior based on project/user configuration.
| Use For | Examples |
|---|---|
| Security tools with severity levels | varlock, security-auditor |
| Linting with configurable strictness | eslint-wrapper |
| Environment-dependent workflows | ci-doctor |
Classification Decision Tree
Does the skill need user input to work?
│
├─ NO → Autonomous Execution
│
└─ YES → Is input needed throughout, or just upfront?
│
├─ UPFRONT → Guided Decision
│
└─ THROUGHOUT → Interactive Exploration
Exception: If behavior depends on config → Configurable Enforcement
Skill Creation Checklist
1. Structure Validation
skill-name/
├── SKILL.md # Required: Core instructions
├── references/ # Optional: Detailed docs
├── scripts/ # Optional: Utility scripts
├── hooks/ # Optional: Pre/post command hooks
└── examples/ # Optional: Working examples
2. SKILL.md Requirements
Frontmatter (required):
---
name: Skill Name
description: This skill should be used when the user asks to "phrase 1", "phrase 2", "phrase 3". Be specific with trigger phrases.
version: 1.0.0
---
Behavioral Classification (required in body):
Every skill MUST include a Behavioral Classification section immediately after the title.
## Behavioral Classification
**Type**: [Autonomous Execution | Guided Decision | Interactive Exploration | Configurable Enforcement]
**Directive**: [EXECUTE, DON'T ASK | ASK, THEN EXECUTE | ASK THROUGHOUT | USER-CONFIGURED]
[Brief description of how the skill interacts with users]
Body requirements:
- Use imperative form ("Configure the server", not "You should configure")
- Keep under 2,000 words (move details to references/)
- Reference all bundled resources
- No project-specific details
3. Generalization Checklist
Before publishing or committing any skill:
- Behavioral classification declared: Type and directive documented
- No hardcoded IDs: UUIDs, project IDs, initiative IDs → environment variables
- No specific names: Project names, company names → generic examples
- No personal URLs: API endpoints, webhooks → configurable via env vars
- No internal references: Team names, internal docs → generic documentation
- Environment variables documented: All required env vars listed
- Generic examples: Examples use placeholder values like
<your-uuid>
3.1 Documentation Generalization (MANDATORY)
CRITICAL: ALL documentation files (README.md, references/, examples/, lessons-learned.md) MUST be fully generalized. This is non-negotiable for public skills.
What to Generalize in Documentation
| ❌ Project-Specific | ✅ Generic Replacement |
|---|---|
| "Skillsmith" | "[Project Name]" or "your project" |
| "SMI-1234" (Linear issues) | "[ISSUE-ID]" or "[Tracking Issue]" |
| "Apache-2.0 to Elastic License 2.0" | "[Old License] to [New License]" |
| "ADR-013", "ADR-017" | "ADR-XXX", "ADR-YYY" |
| Specific file paths from a project | Generic paths like "docs/adr/*.md" |
| Company names (Smith Horn Group, etc.) | "[Your Company]" or omit entirely |
| Real dates tied to a project | "[Date]" or "[Month Year]" |
Case Studies and Examples
When including case studies or lessons learned:
# ❌ BAD - Project-specific case study
## Case Study: Skillsmith License Migration (January 2026)
After migrating Skillsmith from Apache-2.0 to Elastic License 2.0...
Created Linear issue SMI-1369...
# ✅ GOOD - Generalized case study
## Case Study: License Migration (Generic Example)
After migrating a project from an open-source license (e.g., Apache-2.0, MIT)
to a source-available license (e.g., Elastic License 2.0, BSL)...
Created tracking issue [ISSUE-ID]...
Templates Must Use Placeholders
All templates in a skill must use generic placeholders:
# ❌ BAD - Specific project in template
> **Linear Issue:** SMI-XXXX (to be created)
> See [ADR-013](../adr/013-open-core-licensing.md)
# ✅ GOOD - Generic placeholders
> **Tracking Issue:** [ISSUE-ID] (to be created)
> See [ADR-XXX](../adr/XXX.md)
Automatic Generalization Check
Before publishing ANY skill, run:
# Search for common project-specific patterns
grep -ri "skillsmith\|smi-[0-9]\|smith.horn" skill-name/
grep -ri "lin_api_\|api_key.*=" skill-name/ # Exposed secrets
If ANY matches are found, the skill is NOT ready for publishing.
4. Varlock for Secrets Management
CRITICAL: All skills handling secrets MUST use Varlock to prevent exposure.
Required Files
skill-name/
├── .env.schema # Variable definitions with @sensitive annotations (commit)
├── .env.example # Template with placeholders (commit)
└── .env # Actual secrets (NEVER commit)
.env.schema Format
# @type=string(startsWith=lin_api_) @required @sensitive
LINEAR_API_KEY=
# @type=string @optional
LINEAR_DEFAULT_INITIATIVE_ID=
Safe Commands (Always Use)
varlock load # Validate (masked output)
varlock run -- npx tsx scripts/my.ts # Run with secrets injected
Unsafe Commands (NEVER Use)
echo $API_KEY # ❌ Exposes to Claude's context
cat .env # ❌ Exposes all secrets
tool config show # ❌ Many tools print secrets!
Document in SKILL.md
## Environment Variables
| Variable | Required | Sensitive | Description |
|----------|----------|-----------|-------------|
| `LINEAR_API_KEY` | Yes | 🔐 Yes | Your Linear API key |
| `LINEAR_DEFAULT_INITIATIVE_ID` | No | No | Default initiative for linking |
Skill Update Workflow
When modifying an existing skill:
Step 1: Audit for Project-Specific Content
# Search for hardcoded values
grep -r "SKILLSMITH\|MyProject\|specific-id" skill-name/
grep -r "[0-9a-f]{8}-[0-9a-f]{4}" skill-name/ # UUIDs
Step 2: Extract to Environment Variables
// Before
const PROJECT_ID = '5e1cebfe-f4bb-42c1-988d-af792fc4253b'
// After
const PROJECT_ID = process.env.MY_SKILL_PROJECT_ID || ''
if (!PROJECT_ID) {
throw new Error('MY_SKILL_PROJECT_ID environment variable required')
}
Step 3: Rename Project-Specific Functions
// Before
export async function updateSkillsmithProject() { ... }
// After
export async function updateProject(projectId: string) { ... }
Step 4: Update Documentation
- Replace specific examples with generic placeholders
- Document all environment variables
- Add configuration section to SKILL.md
Step 5: Validate
Run the validation script:
npx tsx scripts/validate-skill.ts skill-name/
Common Mistakes
Mistake 1: Hardcoded Project References
❌ Bad:
const result = await createSkillsmithProject({...})
await linkToSkillsmithInitiative(projectId)
✅ Good:
const result = await createProject(teamId, {..., initiative: initiativeId})
await linkProjectToInitiative(projectId, initiativeId)
Mistake 2: Missing Environment Variable Validation
❌ Bad:
const apiKey = process.env.API_KEY // Silently undefined
✅ Good:
const apiKey = process.env.API_KEY
if (!apiKey) {
throw new Error('API_KEY environment variable is required')
}
Mistake 3: Project-Specific Examples
❌ Bad:
## Example
Link the Skillsmith Phase 5 project to the initiative.
✅ Good:
## Example
Link a project to an initiative:
\`\`\`bash
npx tsx lib/initiative.ts link <initiative-id> [project-filter]
\`\`\`
Lessons Learned from Linear Skill
The Linear skill update revealed common patterns to avoid:
1. Hardcoded Initiative IDs
- Problem:
INITIATIVES.SKILLSMITH = '5e1cebfe-...' - Solution:
DEFAULT_INITIATIVE_ID = process.env.LINEAR_DEFAULT_INITIATIVE_ID
2. Project-Specific Function Names
- Problem:
linkAllSkillsmithProjects(),verifyAllSkillsmithProjects() - Solution:
linkProjectsToInitiative(id, filter),verifyProjectsForInitiative(id, filter)
3. Missing Configuration Documentation
- Problem: Users didn't know what env vars to set
- Solution: Add environment variable table to SKILL.md
4. Non-Generic Examples
- Problem: Examples referenced "Skillsmith Phase X"
- Solution: Use "My Project Phase X" or
<your-project-name>
Quality Standards
Code Quality
- TypeScript with strict mode
- Proper error handling with descriptive messages
- Input validation for required parameters
- JSDoc comments for public functions
Documentation Quality
- Clear purpose statement
- Step-by-step workflows
- Working examples with placeholders
- Environment variable documentation
- Troubleshooting section
Maintainability
- No duplicated logic across files
- Shared utilities in
lib/orscripts/ - Consistent naming conventions
- Version number in frontmatter
Validation Script
Run before committing skill changes:
# Validate a skill
npx tsx scripts/validate-skill.ts path/to/skill
# Check for project-specific content
npx tsx scripts/check-generalization.ts path/to/skill
Subagent Pair Generation
When to Generate a Subagent
Generate a companion subagent when the skill:
- Produces verbose output (>500 tokens working context)
- Involves document processing (PDF, Excel, large files)
- Performs multi-file analysis or code review
- Runs test suites with detailed output
- Conducts research with iterative exploration
Token Savings: 37-97% reduction through context isolation.
Subagent Definition Structure
Every skill can have a companion subagent defined at ~/.claude/agents/[skill-name]-specialist.md:
---
name: [skill-name]-specialist
description: [Skill purpose]. Use when [trigger conditions].
skills: [skill-name]
tools: [minimal tool set]
model: sonnet
---
## Operating Protocol
1. Execute the [skill-name] skill for the delegated task
2. Process all intermediate results internally
3. Return ONLY a structured summary to the orchestrator
## Output Format
- **Task:** [what was requested]
- **Actions:** [what you did]
- **Results:** [key outcomes, max 3-5 bullet points]
- **Artifacts:** [file paths or outputs created]
Keep response under 500 tokens unless explicitly requested.
Tool Set Determination
| Skill Content Contains | Include Tools |
|---|---|
| Always | Read |
| write, create, edit | Write, Edit |
| bash, npm, command | Bash |
| search, find, grep | Grep, Glob |
| web, fetch, url | WebFetch |
CLI Commands for Subagent Generation
# Generate subagent for a skill
skillsmith author subagent [path] [options]
-o, --output <path> Output directory (default: ~/.claude/agents)
--tools <tools> Override tools (comma-separated)
--model <model> Model to use (default: sonnet)
--skip-claude-md Skip CLAUDE.md snippet generation
# Transform existing skill (non-destructive)
skillsmith author transform [path] [options]
--dry-run Preview without creating files
--force Overwrite existing subagent
--batch <paths> Process multiple skills
CLAUDE.md Delegation Snippet
After generating a subagent, add to your CLAUDE.md:
## Subagent Delegation
When tasks match [skill-name] triggers, delegate to the [skill-name]-specialist
subagent instead of executing directly. This provides context isolation and
token savings.
### Delegation Pattern
- Detect: User requests [trigger phrases]
- Delegate: Task tool with subagent_type="[skill-name]-specialist"
- Receive: Structured summary (under 500 tokens)
Template and Script References
templates/subagent-template.md- Base template for subagent generationscripts/generate-subagent.ts- Generation logic and tool detection
Enforcement Hooks Pattern (Optional)
Skills can include pre/post command hooks for policy enforcement. This pattern is optional and most useful for skills that enforce development policies.
When to Add Hooks
Add a hooks/ directory when your skill needs to:
- Intercept commands before execution (pre-command)
- Validate environment state
- Transform commands automatically
- Enforce project policies
Hooks Directory Structure
skill-name/
├── SKILL.md
├── hooks/
│ ├── pre-command.sh # Runs before commands
│ └── post-command.sh # Runs after commands (optional)
└── scripts/
Pre-Command Hook Template
#!/bin/bash
# Pre-command hook for [skill-name]
# Called automatically by Claude Code hooks system
set -euo pipefail
COMMAND="${1:-}"
CONFIG_FILE=".claude/[skill-name]-config.json"
# Load configuration
load_config() {
if [[ -f "$CONFIG_FILE" ]]; then
# Parse config
ENFORCEMENT=$(grep -o '"enforcement".*"[^"]*"' "$CONFIG_FILE" | cut -d'"' -f4 || echo "warn")
else
ENFORCEMENT="warn"
fi
}
# Check if command should be intercepted
should_intercept() {
# Add pattern matching logic
echo "$COMMAND" | grep -qE "^pattern"
}
# Main enforcement
main() {
load_config
if ! should_intercept; then
exit 0 # Allow command
fi
case "$ENFORCEMENT" in
block)
echo "ERROR: Policy violation" >&2
exit 1
;;
warn)
echo "WARNING: Consider alternative approach" >&2
exit 0
;;
transform)
# Transform and execute
exec transformed-command
;;
esac
}
main "$@"
Configuration Pattern
Skills with hooks should support a configuration file:
{
"enforcement": "block|warn|transform|disabled",
"allowedPatterns": ["pattern1", "pattern2"],
"options": {}
}
Example: docker-enforce
The docker-enforce skill demonstrates this pattern:
| Component | Purpose |
|---|---|
hooks/pre-command.sh |
Intercepts npm/node commands |
.claude/docker-config.json |
Per-project configuration |
| Enforcement modes | block, warn, transform, disabled |
Integration with Claude Code
To enable hooks in Claude Code, add to .claude/settings.json:
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "bash ~/.claude/skills/[skill-name]/hooks/pre-command.sh \"$COMMAND\""
}]
}]
}
}
Note: Hooks integration is optional and should only be added when the skill genuinely needs to enforce policies.
Additional Resources
Reference Files
references/generalization-patterns.md- Detailed patterns for generalizing skillsreferences/linear-retro.md- Full retrospective from Linear skill updatereferences/orchestrator-delegation.md- Delegation patterns for subagents
Scripts
scripts/validate-skill.ts- Validate skill structure and contentscripts/check-generalization.ts- Check for project-specific contentscripts/generate-subagent.ts- Generate companion subagent for a skill
Integration with Skill Updates
This skill should be automatically invoked when:
- Creating new skills
- Updating existing skills in
~/.claude/skills/ - Reviewing skills before publishing
- Committing changes to skill repositories
Automatic Triggering via Claude Code Hooks
Add to ~/.claude/settings.json to automatically trigger skill-builder validation when editing skills:
{
"hooks": {
"PostToolUse": [{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "bash -c 'if [[ \"$CLAUDE_TOOL_ARG_FILE_PATH\" == */.claude/skills/* ]]; then echo \"[skill-builder] Reminder: Run generalization check before committing\"; fi'"
}]
}]
}
}
This hook provides a reminder when editing skill files. For full validation, run:
# Check for project-specific content
grep -ri "skillsmith\|smi-[0-9]\|specific-uuid" ~/.claude/skills/<skill-name>/
# Or use the validation script
npx tsx scripts/check-generalization.ts ~/.claude/skills/<skill-name>/
CLAUDE.md Integration
To ensure this skill is used, add to your CLAUDE.md:
## Skill Development
When creating or updating skills in `~/.claude/skills/`, always:
1. **Invoke skill-builder** for validation: `/skill-builder` or "validate skill"
2. **Run generalization check** before committing
3. **Review for specific references** (project names, UUIDs, internal docs)
The skill-builder skill enforces generalization rules and quality standards.
Why This Matters
Lesson learned from SMI-1735: During the Skill Architecture Refactor, skills were edited without invoking skill-builder, resulting in project-specific references that required a second pass to generalize.
Root cause: The trigger phrases didn't include "review for specific references" or "generalize", and there was no automatic hook to remind about validation.
Fix applied: Added trigger phrases and documented hook pattern in v1.1.0.