From skill-builder
Validates, generalizes, and publishes existing Claude Code skills, enforcing quality standards and preventing hardcoded values for public distribution.
How this skill is triggered — by the user, by Claude, or both
Slash command
/skill-builder:skill-reviewerThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Review, validate, generalize, and publish existing Claude Code skills following best practices for public distribution. (To scaffold a brand-new skill, use the companion **skill-builder** skill.)
Review, validate, generalize, and publish existing Claude Code skills following best practices for public distribution. (To scaffold a brand-new skill, use the companion skill-builder skill.)
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 |
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?) { ... }
Every skill must declare its behavioral type. This determines how the skill interacts with users.
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 |
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 |
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 |
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 |
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-name/
├── SKILL.md # Required: Core instructions
├── README.md # Required: Human-readable docs and install instructions
├── CHANGELOG.md # Required: Version history in Keep a Changelog format
├── references/ # Optional: Detailed docs
├── scripts/ # Optional: Utility scripts
├── hooks/ # Optional: Pre/post command hooks
└── examples/ # Optional: Working examples
README.md must include: problem statement, install command (the Claude Code plugin marketplace flow — claude plugin marketplace add <author>/<repo> then claude plugin install <plugin>@<marketplace>; skillsmith install <author>/<name> is an alternative), usage examples, contents table, requirements.
CHANGELOG.md must include: ## [X.Y.Z] - YYYY-MM-DD entry for every version with Added/Changed/Fixed sections.
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:
Before publishing or committing any skill:
<your-uuid>CRITICAL: ALL documentation files (README.md, references/, examples/, lessons-learned.md) MUST be fully generalized. This is non-negotiable for public skills.
| ❌ 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]" |
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]...
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)
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.
CRITICAL: All skills handling secrets MUST use Varlock to prevent exposure.
skill-name/
├── .env.schema # Variable definitions with @sensitive annotations (commit)
├── .env.example # Template with placeholders (commit)
└── .env # Actual secrets (NEVER commit)
# @type=string(startsWith=lin_api_) @required @sensitive
LINEAR_API_KEY=
# @type=string @optional
LINEAR_DEFAULT_INITIATIVE_ID=
varlock load # Validate (masked output)
varlock run -- npx tsx scripts/my.ts # Run with secrets injected
echo $API_KEY # ❌ Exposes to Claude's context
cat .env # ❌ Exposes all secrets
tool config show # ❌ Many tools print secrets!
## 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 |
When modifying an existing skill:
# 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
// 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')
}
// Before
export async function updateSkillsmithProject() { ... }
// After
export async function updateProject(projectId: string) { ... }
Run the validation script:
npx tsx scripts/validate-skill.ts skill-name/
Every meaningful change to a skill requires a version bump and a CHANGELOG entry. Use semver rules:
| Change type | Bump | Example |
|---|---|---|
| Bug fix, copy correction, typo | PATCH | 1.0.0 → 1.0.1 |
| New section, new workflow step, new trigger phrase | MINOR | 1.0.1 → 1.1.0 |
| Renamed triggers, removed steps, behavioural change | MAJOR | 1.1.0 → 2.0.0 |
# 1. Update frontmatter
sed -i '' 's/^version: .*/version: "X.Y.Z"/' SKILL.md
# 2. Add CHANGELOG entry
# ## [X.Y.Z] - YYYY-MM-DD
# ### Added / Changed / Fixed
# - Description of change
Before starting any update, record the current version so the diff is clear:
grep "^version:" SKILL.md # Note this before editing
Every new skill and every version bump must complete all four steps before the work is considered done:
# 1. Confirm README.md exists and covers: problem, install, usage, contents, requirements
ls README.md || echo "MISSING README.md — create it before publishing"
# 2. Confirm CHANGELOG.md has an entry for this version
grep "## \[$(grep '^version:' SKILL.md | awk '{print $2}')\]" CHANGELOG.md \
|| echo "MISSING CHANGELOG entry for this version"
# 3. Commit everything
git add .
git commit -m "feat: <skill-name> v<X.Y.Z>"
# 4. Push to GitHub
git push
# 5. Create GitHub release with tag
VERSION=$(grep '^version:' SKILL.md | awk '{print $2}' | tr -d '"')
gh release create "v${VERSION}" \
--title "v${VERSION}" \
--notes "$(grep -A 50 "## \[${VERSION}\]" CHANGELOG.md | tail -n +2 | sed '/^## \[/q' | head -n -1)"
Required README.md sections:
claude plugin marketplace add <author>/<repo> then claude plugin install <plugin>@<marketplace>); skillsmith install <author>/<name> is an alternativeRequired CHANGELOG.md format:
## [X.Y.Z] - YYYY-MM-DD
### Added
- New features
### Changed
- Breaking or behavioural changes
### Fixed
- Bug fixes
Before releasing a skill pack (e.g. product-builder-starter), verify bundled versions
match their sources. Skills in a pack can silently fall behind — e.g. linear was
bundled at 2.0.0 while the source had reached 2.2.3 (a 14-release gap).
# List all bundled skill versions
for skill_md in skills/*/SKILL.md; do
skill=$(basename $(dirname "$skill_md"))
version=$(grep "^version:" "$skill_md" | head -1)
echo "$skill: $version"
done
# Cross-reference against installed sources
for skill_md in ~/.claude/skills/*/SKILL.md; do
skill=$(basename $(dirname "$skill_md"))
version=$(grep "^version:" "$skill_md" | head -1)
echo "[source] $skill: $version"
done
If a bundled version is behind: update the SKILL.md, add the missing CHANGELOG entries, and bump the version in the pack before tagging the release.
Run before tagging any release. Missing version: is a silent failure — the registry
cannot index the skill, skill_diff has no baseline, and release notes are incomplete.
# Check all SKILL.md files for required fields
for skill_md in skills/*/SKILL.md; do
skill=$(basename $(dirname "$skill_md"))
for field in name version description; do
grep -q "^${field}:" "$skill_md" || echo "MISSING $field in $skill/SKILL.md"
done
done
For skill packs with multiple skills, use the <skill-name>/v<version> tag format:
git tag governance/v1.4.0
git tag linear/v2.2.3
git tag varlock/v1.0.0
git push --tags
This enables per-skill version history in the same repository without tag collisions.
When renaming a term across a skill pack (e.g. a dependency renames like claude-flow → ruflo):
# Capture ALL capitalisation variants before writing sed patterns
grep -ri "old-term" skills/
Common variants to watch for — all require separate sed expressions:
| Variant | Appears in |
|---|---|
old-term | Body text, code blocks |
Old-Term | Section headings (### Old-Term MCP) |
OldTerm | CamelCase references |
OLD_TERM | Env var names |
sed for strings containing angle bracketsThe Edit tool HTML-encodes < and > as < and >, writing the entity as
literal text. Always use sed for replacements involving placeholder strings:
# ❌ Edit tool — writes <project>-dev-1 as literal text
# ✅ Use sed instead:
sed -i '' 's/old-container/<project>-dev-1/g' path/to/file.md
grep -ri "old-term" skills/ # Should return empty
❌ Bad:
const result = await createSkillsmithProject({...})
await linkToSkillsmithInitiative(projectId)
✅ Good:
const result = await createProject(teamId, {..., initiative: initiativeId})
await linkProjectToInitiative(projectId, initiativeId)
❌ 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')
}
❌ 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]
\`\`\`
The Linear skill update revealed common patterns to avoid:
INITIATIVES.SKILLSMITH = '5e1cebfe-...'DEFAULT_INITIATIVE_ID = process.env.LINEAR_DEFAULT_INITIATIVE_IDlinkAllSkillsmithProjects(), verifyAllSkillsmithProjects()linkProjectsToInitiative(id, filter), verifyProjectsForInitiative(id, filter)<your-project-name>lib/ or scripts/Run before committing skill changes:
# Validate a skill (structure, generalization, secret-exposure, env-var and
# plugin.json version-sync checks are all built into this one script)
npx tsx scripts/validate-skill.ts path/to/skill
Generate a companion subagent when the skill:
Token Savings: 37-97% reduction through context isolation.
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.
| 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 |
When a skill dispatches to a Task subagent that uses Write, Edit, or Bash tools, it must include an "Execution Context Requirements" section. Background subagents auto-deny unapproved tools, causing silent failures.
Include this section when the skill uses the thin dispatcher pattern (dispatches to agent-prompt.md via general-purpose subagent):
## Execution Context Requirements
This skill spawns a general-purpose subagent that performs file operations.
**Foreground execution required**: [Yes if Write/Edit/Bash used, No if read-only]
**Required tools**: [List tools the subagent needs, e.g., Read, Write, Edit, Bash, Grep, Glob]
**Fallback**: If tools are denied, the subagent returns recommendations as text
for the coordinator to apply.
Decision logic:
After generating a skill, validate it with skillsmith validate to check for missing execution context documentation.
# 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
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)
templates/subagent-template.md - Base template for subagent generationscripts/generate-subagent.ts - Generation logic and tool detectionSkills can include pre/post command hooks for policy enforcement. This pattern is optional and most useful for skills that enforce development policies.
Add a hooks/ directory when your skill needs to:
skill-name/
├── SKILL.md
├── hooks/
│ ├── pre-command.sh # Runs before commands
│ └── post-command.sh # Runs after commands (optional)
└── scripts/
#!/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 "$@"
Skills with hooks should support a configuration file:
{
"enforcement": "block|warn|transform|disabled",
"allowedPatterns": ["pattern1", "pattern2"],
"options": {}
}
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 |
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.
references/generalization-patterns.md - Detailed patterns for generalizing skillsreferences/orchestrator-delegation.md - Delegation patterns for subagentsscripts/validate-skill.ts - Validate skill structure, generalization (project-specific content), secret exposure, env-var documentation, and plugin.json version syncscripts/generate-subagent.ts - Generate companion subagent for a skillAnthropic's Claude Plugin Marketplace (anthropics/claude-plugins-official) requires a .claude-plugin/plugin.json metadata file in addition to SKILL.md. This section covers everything needed to prepare a skill for marketplace submission.
.claude-plugin/plugin.jsonAdd this file to the root of the skill's GitHub repository:
{
"name": "<slug>",
"description": "<description from SKILL.md, ≤150 chars>",
"version": "<version from SKILL.md frontmatter>",
"author": {
"name": "<Your Name>",
"url": "https://github.com/<your-github-username>"
},
"homepage": "https://skillsmith.app",
"repository": "https://github.com/<org>/<repo>",
"license": "MIT",
"keywords": ["claude-skill", "<category-keyword>"]
}
Required fields: name, description, author.name
Description rules:
Keywords convention:
"claude-skill" as the first keyword"docker", "devops", "containers")Before pushing, confirm the version in plugin.json matches the authoritative source:
| Priority | Source | Notes |
|---|---|---|
| 1st | SKILL.md frontmatter version: | Most authoritative |
| 2nd | package.json version | Sync to SKILL.md if different |
| 3rd | Latest git tag | Tag should match after publishing |
Fix common drift patterns:
# Check if versions are in sync
grep "version:" SKILL.md
node -p "require('./package.json').version"
git tag --sort=-v:refname | head -3
Before checking quality, confirm a README is present:
gh api repos/<org>/<repo>/contents/README.md --jq '.name' 2>/dev/null \
|| echo "❌ NO README — must create before submitting to Anthropic"
If missing: create a README with the sections in Step 3b before proceeding. Anthropic will reject submissions without a quality README.
Anthropic's security review checks for a quality README with at minimum:
skillsmith install <org>/<name>, or manual copy instructions)plugin.json via gh CLI# Create the file in the repo
CONTENT=$(cat .claude-plugin/plugin.json | base64)
gh api repos/<org>/<repo>/contents/.claude-plugin/plugin.json \
-X PUT \
-f message="feat: add Claude plugin marketplace metadata" \
-f content="$CONTENT"
# Verify it's live and valid
gh api repos/<org>/<repo>/contents/.claude-plugin/plugin.json \
--jq '.content' | python3 -c "import base64,sys; print(base64.b64decode(sys.stdin.read()).decode())" | python3 -m json.tool
After all changes are live on GitHub:
https://clau.de/plugin-directory-submission/plugin install <name>@claude-plugins-officialBefore submitting, verify all of the following:
.claude-plugin/plugin.json exists and is valid JSONversion in plugin.json matches SKILL.md frontmatterdescription is ≤150 chars, no surrounding quotesREADME.md has Features + Installation + Usage + RequirementsSKILL.md has version: in frontmatterlicense field is correct (MIT, Apache-2.0, or Elastic License 2.0)# Quick pre-submission check
python3 -c "
import json, sys
with open('.claude-plugin/plugin.json') as f:
d = json.load(f)
required = ['name', 'description', 'version', 'author']
missing = [k for k in required if k not in d]
if missing:
print('MISSING FIELDS:', missing); sys.exit(1)
if 'name' not in d.get('author', {}):
print('MISSING: author.name'); sys.exit(1)
if len(d['description']) > 150:
print(f'DESCRIPTION TOO LONG: {len(d["description"])} chars (max 150)'); sys.exit(1)
print('OK plugin.json valid', d['name'], 'v' + d['version'])
"
This skill should be automatically invoked when:
~/.claude/skills/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 (generalization check is built in)
npx tsx scripts/validate-skill.ts ~/.claude/skills/<skill-name>/
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.
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.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub wrsmith108/skill-builder-claude-skill --plugin skill-builder