
Skill Authoring
- 13 installs
- 1 repo stars
- Updated March 1, 2026
- cachemoney/agent-toolkit
Author and publish new skills
About
Comprehensive skill authoring environment. Supports creation, testing, validation, and publishing of Claude Code skills.
- Skill authoring
- Publishing
- Version management
Skill Authoring by the numbers
- 13 all-time installs (skills.sh)
- Ranked #535 of 826 Skill Development skills by installs in the Skillselion catalog
- Data as of Jul 28, 2026 (Skillselion catalog sync)
npx skills add https://github.com/cachemoney/agent-toolkit --skill skill-authoringAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 13 |
|---|---|
| repo stars | ★ 1 |
| Last updated | March 1, 2026 |
| Repository | cachemoney/agent-toolkit ↗ |
What it does
Author and publish new skills
Files
Writing Skills
What Is a Skill?
A skill is a way to teach an agent something it doesn't already know.
LLM agents are already smart. They can write code, analyze documents, reason through problems. But they don't know your codebase, your workflows, your domain's quirks. Skills bridge that gap — they're onboarding documents that transform a general-purpose agent into a specialized one equipped with knowledge no model ships with.
Think of skills as institutional memory made accessible to AI. The same way a senior engineer onboards a new hire by explaining "here's how we do X, here's why we avoid Y, here's the tool for Z" — a skill does that for an agent.
How Agents Find Skills
Understanding discovery is essential to writing skills that work.
When a conversation starts, the agent sees only metadata — the name and description from every available skill's frontmatter. That's it. Not the body. Not the instructions. Just names and descriptions, loaded into context alongside everything else.
When you ask the agent something, it pattern-matches your request against those descriptions. If your request seems to match a skill's description, the agent loads that skill. Only then does it read the full SKILL.md body.
This has profound implications:
1. A skill with a perfect body but a vague description will never trigger. The agent can't use what it can't find.
2. The description must contain the words users actually say. If users say "help me with PDFs" but your description says "document processing," the skill won't activate.
3. Descriptions that summarize workflow are dangerous. Testing revealed that when a description says "does X then Y then Z," agents sometimes follow that summary instead of reading the full skill. Keep descriptions to when to use, not what it does step-by-step.
The Anatomy of a Skill
skill-name/
├── SKILL.md # Required. The entry point.
├── references/ # Optional. Detailed docs loaded on demand.
├── scripts/ # Optional. Code executed, not read into context.
└── assets/ # Optional. Templates, images for output.Every skill has a SKILL.md with two parts:
Frontmatter (YAML) — The metadata the agent uses for discovery:
---
name: my-skill
description: Use when [triggering conditions]. Covers [capabilities].
---Body (Markdown) — The instructions the agent follows after the skill triggers. Only loaded when needed.
This split is intentional. Frontmatter is always in context (~100 tokens per skill). Bodies are loaded on demand. This is why you keep SKILL.md lean and push detailed reference material to separate files.
Writing Descriptions That Work
The description is the most important thing you'll write. It determines whether your skill ever gets used.
Formula: Describe when to use it, not how it works.
# ✅ Good — triggering conditions only
description: Use when working with PDF files — extracts text, fills forms, merges documents.
# ❌ Bad — summarizes workflow (agent may follow this instead of reading body)
description: Processes PDFs by first extracting text, then analyzing structure, then outputting results.
# ❌ Bad — too vague
description: Helps with documents.Include:
- Trigger words users actually say ("extract", "merge", "analyze")
- File types and extensions (.pdf, .xlsx, .docx)
- Error messages or symptoms ("skill won't trigger", "agent ignores")
- Synonyms for common terms
Exclude:
- Step-by-step workflow
- Implementation details
- First-person language ("I can help you...")
Writing Bodies That Teach
Once your skill triggers, the agent reads the body. This is where you teach.
The best skills follow a pattern:
1. Orient — What is this? What problem does it solve? (1-2 sentences) 2. Instruct — What should the agent do? (Imperative mood, clear steps) 3. Show — Concrete examples with real input/output 4. Warn — Common mistakes and how to avoid them
Don't over-explain. The agent is smart. Only add context it doesn't already have. Every paragraph should justify its token cost.
Progressive Disclosure
Skills share the context window with everything else — system prompt, conversation history, other skills' metadata, the user's actual request. Context is a public good. Don't waste it.
Structure your skill in layers:
| Layer | What | When Loaded | Size Target |
|---|---|---|---|
| 1 | name + description | Always | ~50 tokens |
| 2 | SKILL.md body | When skill triggers | <500 lines |
| 3 | references/, scripts/ | When agent needs them | Unlimited |
Split when:
- SKILL.md approaches 500 lines
- Content is domain-specific (load only for that domain)
- Reference material exceeds 100 lines
Keep references one level deep. Don't link from references to other references — the agent may not follow the chain.
The Cardinal Rules
| Rule | Why It Matters |
|---|---|
| Description has trigger keywords | Without them, skill never activates |
| Description in third person | It's injected into system prompt |
| Name matches directory | Required for skill loading |
| Critical instructions in first 100 lines | Content can be truncated |
| SKILL.md under 500 lines | Context is precious |
| One excellent example > many mediocre | Quality over quantity |
| Test activation before deployment | A skill that works but never triggers = zero value |
| Use agent-agnostic language | Skills work with any LLM, not just one |
When You're Ready to Build
This document taught you how skills work. Now you need the practical tools.
Scripts — Automate the boring parts:
python scripts/init.py my-skill # Scaffold a new skill
./scripts/validate.sh path/to/skill # Check for common errorsOr use the official skills-ref library:
pip install skills-ref
skills-ref validate path/to/skillWorkflows — Things you do:
| Task | Resource |
|---|---|
| Create a new skill from scratch | workflows/create.md |
| Test activation and behavior | workflows/test.md |
| Debug a skill that isn't working | workflows/debug.md |
| Refine a skill from session learnings | workflows/refine.md |
References — Things you look up:
| Topic | Resource |
|---|---|
| Official Agent Skills specification | spec/specification.md |
| Patterns: templates, routers, conditionals | references/patterns.md |
| Good and bad examples with analysis | references/examples.md |
| Granular rules organized by impact | references/rules.md |
Spec — Authoritative documentation from agentskills.io:
| Document | Description |
|---|---|
| spec/what-are-skills.md | Conceptual overview |
| spec/specification.md | Format specification |
| spec/skills-ref/ | Official validation library (vendored) |
Source Material
The sources/ directory contains complete skill-authoring approaches from different authors, preserved for deeper study:
| Source | Approach |
|---|---|
sources/anthropic/ | Official Anthropic skill-creator with init/package scripts |
sources/obra/ | TDD-based methodology with pressure testing |
sources/everyinc/ | Router patterns and workflow templates |
sources/pproenca/ | 46 granular rules organized by impact level |
sources/pytorch/ | Simple single-file approach |
The Bottom Line
A skill is a teaching document. Its job is to make an agent smarter about something specific.
Write the description for discovery — use the words users say. Write the body for understanding — orient, instruct, show, warn. Structure for efficiency — keep the main file lean, push details to references. Test for activation — a skill that never triggers provides zero value.
The best skills don't just tell the agent what to do. They give it enough understanding to adapt when the situation doesn't match the template exactly.
Skill Examples
Concrete good/bad examples showing what works and why.
Good Skill: PDF Handler
---
name: pdf-handler
description: Use when working with PDF files, extracting text from PDFs, filling PDF forms, or merging PDF documents. Use for .pdf file operations.
---# PDF Handler
## Quick Start
Extract text: `pdf-extract input.pdf > output.txt`
## Instructions
1. Identify the PDF operation needed
2. Run the appropriate script from `scripts/`
3. Return results to user
## Common Mistakes
- Scanned PDFs need OCR first → Run `scripts/ocr.py` before extractionWhy it works:
- Description has trigger words ("PDF", "extracting", "filling", "merging", ".pdf")
- Quick Start gives immediate value
- Instructions are imperative
- Common Mistakes prevent real failures
Bad Skill: Document Helper
---
name: document-helper
description: Helps users work with their documents by analyzing the content, extracting key information, and providing summaries.
---Why it fails:
- Description summarizes workflow (Claude follows this instead of reading body)
- No trigger keywords (what file types? what operations?)
- "Helps users" is vague — what specifically?
Bad Skill: TDD Helper
---
name: tdd-helper
description: Use for TDD — write test first, watch it fail, write minimal code, refactor
---Why it fails:
- Description summarizes the workflow step-by-step
- Claude may follow description instead of reading the full skill body
- Should describe when to use, not how it works
Fixed:
description: Use when implementing any feature or bugfix, before writing implementation codeSkill Patterns
Template Pattern
Provide output templates when consistent format matters.
Strict Template
Use when format must be exact:
## Report Structure
ALWAYS use this exact structure:
# [Analysis Title]
## Executive Summary
[One-paragraph overview]
## Key Findings
- Finding 1 with data
- Finding 2 with data
## Recommendations
1. Specific action
2. Specific actionFlexible Template
Use when adaptation is appropriate:
## Report Structure
Sensible default, adapt as needed:
# [Analysis Title]
## Executive Summary
[Overview - length varies by complexity]
## Findings
[Adapt sections to what you discover]
## Recommendations
[Tailor to context]Examples Pattern
Show input/output pairs when quality depends on demonstration:
## Commit Message Format
**Example 1:**
Input: Added user authentication with JWT tokens
Output:feat(auth): implement JWT-based authentication
Add login endpoint and token validation middleware
**Example 2:**
Input: Fixed date display bug in reports
Output:fix(reports): correct date formatting in timezone conversion
Use UTC timestamps consistently across report generation
Follow: type(scope): summary, then detailed explanation.When to use examples:
- Format has nuances text can't capture
- Pattern recognition easier than rule following
- Edge cases need demonstration
Sequential Workflow Pattern
For multi-step processes:
## PDF Form Filling
1. **Analyze form** - `python scripts/analyze.py input.pdf`
2. **Create mapping** - Edit `fields.json` with values
3. **Validate** - `python scripts/validate.py fields.json`
4. **Fill form** - `python scripts/fill.py input.pdf fields.json output.pdf`
5. **Verify** - `python scripts/verify.py output.pdf`Conditional Workflow Pattern
For branching logic:
## Document Processing
**Creating new content?** → Follow "Creation Workflow" below
**Editing existing?** → Follow "Editing Workflow" below
### Creation Workflow
1. Determine structure
2. Generate content
3. Format and save
### Editing Workflow
1. Load existing document
2. Identify changes
3. Apply modifications
4. Preserve formattingChecklist Pattern
For complex multi-step tasks:
## Migration Checklist
Copy and track progress:
- [ ] Step 1: Backup database
- [ ] Step 2: Run migration script
- [ ] Step 3: Validate output
- [ ] Step 4: Update configuration
- [ ] Step 5: Verify in staging
### Step 1: Backup Database
Run: `./scripts/backup.sh`
Expected output: `backup-YYYY-MM-DD.sql` created
### Step 2: Run Migration
...Default + Escape Hatch Pattern
Provide one default, one alternative:
## Text Extraction
Use pdfplumber for text extraction:
import pdfplumber with pdfplumber.open("file.pdf") as pdf: text = pdf.pages[0].extract_text()
**For scanned PDFs requiring OCR**, use pdf2image + pytesseract instead.Don't list 5 alternatives and say "choose based on needs" — causes decision paralysis.
Router Pattern
For complex skills with multiple workflows:
---
name: project-management
description: Manages project tasks, planning, and reviews. Use when planning features, tracking progress, or reviewing work.
---
# Project Management
## Core Principles
[Principles that ALWAYS apply, inline here]
## What Would You Like To Do?
1. **Plan a feature** - Break down requirements
2. **Track progress** - Update task status
3. **Review work** - Code review checklist
## Routing
| Choice | Workflow |
|--------|----------|
| 1, "plan", "feature" | [workflows/planning.md](workflows/planning.md) |
| 2, "track", "progress" | [workflows/tracking.md](workflows/tracking.md) |
| 3, "review" | [workflows/review.md](workflows/review.md) |
## Reference Index
- [references/templates.md](references/templates.md) - Document templates
- [references/standards.md](references/standards.md) - Quality standardsRouter Directory Structure
project-management/
├── SKILL.md # Router + core principles
├── workflows/
│ ├── planning.md
│ ├── tracking.md
│ └── review.md
└── references/
├── templates.md
└── standards.mdWorkflow File Structure
# Workflow: Feature Planning
## Required Reading
Load these first:
- [references/templates.md](../references/templates.md)
## Process
1. Gather requirements
2. Break into tasks
3. Estimate effort
4. Create timeline
## Success Criteria
- [ ] Requirements documented
- [ ] Tasks created with estimates
- [ ] Timeline approvedValidation Pattern
For skills with validation steps:
## Validation
After changes, validate immediately:
python scripts/validate.py output/
**Fix errors before continuing.** Common errors:
| Error | Meaning | Fix |
|-------|---------|-----|
| Field not found | Wrong field name | Check available fields in schema |
| Type mismatch | Wrong data type | Convert to expected type |
| Missing required | Required field empty | Provide value |
Only proceed when validation passes with zero errors.Degrees of Freedom
Match specificity to task fragility:
| Freedom | Format | When |
|---|---|---|
| High | Text instructions | Multiple valid approaches |
| Medium | Pseudocode with params | Preferred pattern, some variation OK |
| Low | Exact scripts | Fragile operations, consistency critical |
High freedom example:
Create a summary that captures the key points and recommendations.Low freedom example:
Run exactly: `python scripts/process.py --input data.json --output result.json --validate`Rules by Impact
Rules organized by impact level. Use rule IDs (e.g., desc-trigger-keywords) to reference specific rules.
CRITICAL Impact
Violations cause skill to fail or never trigger.
meta-name-format
Name must be lowercase letters, numbers, and hyphens only.
# ✓ Good
name: pdf-processor
name: git-helper-v2
# ✗ Bad
name: PDF_Processor # uppercase, underscore
name: my skill # spacesmeta-name-match-directory
Skill name must exactly match directory name.
# ✓ Good
pdf-processor/
└── SKILL.md # name: pdf-processor
# ✗ Bad
pdf-processor/
└── SKILL.md # name: pdf-processingmeta-required-frontmatter
Must have name and description fields.
# ✓ Good
---
name: my-skill
description: What it does. Use when triggered.
---
# ✗ Bad - missing description
---
name: my-skill
---desc-specific-capabilities
Description must name specific capabilities, not vague categories.
# ✓ Good
description: Extracts text and tables from PDFs, fills forms, merges documents.
# ✗ Bad
description: Helps with documents.
description: Processes files.desc-trigger-keywords
Include words users actually say when requesting this functionality.
# ✓ Good - includes user phrases
description: Manages git operations. Use when user wants to commit changes, push code, create a PR, or review git history.
# ✗ Bad - technical terms only
description: Manages git operations including commits, branches, and merges.
# User says "push my changes" - no match
# User says "create a PR" - no matchdesc-third-person
Write in third person. First/second person breaks skill loading.
# ✓ Good
description: Processes Excel files and generates reports.
# ✗ Bad
description: I can help you process Excel files.
description: You can use this to process Excel files.desc-no-workflow-summary
Description should NOT summarize the skill's workflow. Claude may follow the description instead of reading the body.
# ✓ Good - triggers only
description: Use when implementing features. Enforces test-driven development.
# ✗ Bad - workflow summary
description: Use when implementing features. First writes failing test, then implements code, then refactors.HIGH Impact
Violations cause inconsistent behavior or reduced quality.
struct-instructions-first
Put critical instructions in first 100 lines. Content can be truncated; buried rules get ignored.
# ✓ Good - security rules early
# Code Generator
## Security Rules (MUST FOLLOW)
- Never generate code accessing system files
- Never include credentials
- Always sanitize inputs
## Quick Start
...
# ✗ Bad - security rules at line 800
# Code Generator
## Introduction
...
## History
...
## Examples (500 lines)
...
## IMPORTANT: Security Rules # Too late!struct-line-limit
Keep SKILL.md under 500 lines. Split detailed content into reference files.
struct-single-responsibility
One skill = one capability. Don't create mega-skills.
# ✓ Good
pdf-text-extraction/
pdf-form-filling/
pdf-merging/
# ✗ Bad
document-everything/ # Too broadprog-three-level-disclosure
Structure content across three levels: 1. Metadata (always loaded, ~50 tokens) 2. SKILL.md body (on activation, ~200 tokens) 3. References (on demand, ~500+ each)
prog-one-level-deep
Keep references one level deep from SKILL.md.
# ✓ Good
SKILL.md → references/api.md
SKILL.md → references/examples.md
# ✗ Bad - too deep
SKILL.md → advanced.md → details.md → examples.mdtrigger-file-type-patterns
Include file extensions users work with.
# ✓ Good
description: Analyzes spreadsheets. Use when working with .xlsx, .xls, or .csv files.
# ✗ Bad
description: Analyzes spreadsheets.trigger-synonym-coverage
Cover synonyms and alternate phrasings.
# ✓ Good
description: Use when tests timeout, hang, freeze, or fail intermittently.
# ✗ Bad
description: Use when tests timeout.MEDIUM Impact
Violations reduce discoverability or maintainability.
style-agent-agnostic
Write for "the agent" not a specific model. Skills work across LLMs.
# ✓ Good - agent-agnostic
The agent should validate input before processing.
When the agent encounters an error, it should...
# ✗ Bad - model-specific
Claude should validate input before processing.
When Claude encounters an error, Claude should...
GPT will analyze the code and then...Why this matters:
- Skills are portable across agents (Claude, GPT, Gemini, local models)
- Model-specific language creates unnecessary coupling
- "The agent" is clearer about the role being addressed
Exception: If a skill is genuinely model-specific (e.g., uses Claude-only features), make that explicit in the description and use the model name consistently.
test-trigger-phrases
Test with 10+ real user phrases before deployment.
## Test Plan
Should trigger:
1. "generate API docs" ✓
2. "create swagger spec" ✗ → Added "Swagger"
3. "write OpenAPI" ✗ → Added "OpenAPI"
Should NOT trigger:
1. "what does this API do?" ✓ (correctly ignored)test-negative-scenarios
Test that skill does NOT trigger on unrelated requests.
trigger-error-patterns
For debugging skills, include error messages users see.
description: Debug async tests. Use when seeing "Hook timed out", "ENOTEMPTY", or tests pass/fail inconsistently.struct-imperative-instructions
Write instructions in imperative mood.
# ✓ Good
Run the validation script.
Create the output directory.
# ✗ Bad
You should run the validation script.
The output directory should be created.struct-code-blocks-with-language
Specify language in code blocks.
````markdown
✓ Good
import pdfplumber✗ Bad
import pdfplumber````
LOW Impact
Best practices for polish and maintainability.
maint-consistent-terminology
Choose one term and use it throughout.
# ✓ Good - consistent
Extract data from API endpoints using field mappings.
1. Identify the API endpoint
2. Map response fields
# ✗ Bad - inconsistent
Pull data from API routes using element mappings.
1. Identify the URL
2. Map response boxesmaint-forward-slashes
Always use forward slashes for paths.
# ✓ Good
See scripts/validate.py
# ✗ Bad
See scripts\validate.pymaint-no-time-sensitive
Avoid time-sensitive information that will become stale.
# ✓ Good
Use the current stable API version.
# ✗ Bad
Use API v2.3.1 released in January 2024.#!/usr/bin/env python3
"""
Initialize a new skill with template structure.
Usage:
python init.py <skill-name> [--path <directory>] [--router]
Examples:
python init.py pdf-processor
python init.py pdf-processor --path ~/.claude/skills
python init.py project-manager --router
"""
import sys
import argparse
from pathlib import Path
SIMPLE_TEMPLATE = '''---
name: {name}
description: [What it does]. Use when [trigger conditions].
---
# {title}
## Quick Start
[Immediate actionable example - what to do first]
## Instructions
1. [First step]
2. [Second step]
3. [Third step]
## Examples
**Example 1:**
Input: [description]
Output:
```
[result]
```
## Common Mistakes
| Mistake | Fix |
|---------|-----|
| [Common error] | [How to fix] |
'''
ROUTER_TEMPLATE = '''---
name: {name}
description: [What it does]. Use when [trigger conditions].
---
# {title}
## Core Principles
[Principles that ALWAYS apply, regardless of workflow]
1. **[First principle]** - [Explanation]
2. **[Second principle]** - [Explanation]
## What Would You Like To Do?
1. **[First option]** - [Brief description]
2. **[Second option]** - [Brief description]
3. **[Third option]** - [Brief description]
## Routing
| Choice | Workflow |
|--------|----------|
| 1, "[keywords]" | [workflows/first.md](workflows/first.md) |
| 2, "[keywords]" | [workflows/second.md](workflows/second.md) |
| 3, "[keywords]" | [workflows/third.md](workflows/third.md) |
## References
| When | Load |
|------|------|
| [Condition] | [references/topic.md](references/topic.md) |
'''
WORKFLOW_TEMPLATE = '''# Workflow: {title}
## Process
1. **[First step]**
[Instructions]
2. **[Second step]**
[Instructions]
3. **[Third step]**
[Instructions]
## Success Criteria
- [ ] [First criterion]
- [ ] [Second criterion]
- [ ] [Third criterion]
'''
REFERENCE_TEMPLATE = '''# {title}
## Overview
[What this reference covers]
## [Section 1]
[Content]
## [Section 2]
[Content]
'''
def title_case(name: str) -> str:
"""Convert hyphenated name to Title Case."""
return ' '.join(word.capitalize() for word in name.split('-'))
def init_skill(name: str, path: Path, router: bool = False) -> Path:
"""
Initialize a new skill directory.
Returns:
Path to created skill directory
"""
skill_dir = path / name
if skill_dir.exists():
raise ValueError(f"Directory already exists: {skill_dir}")
# Create directory structure
skill_dir.mkdir(parents=True)
if router:
(skill_dir / "workflows").mkdir()
(skill_dir / "references").mkdir()
# Write SKILL.md
template = ROUTER_TEMPLATE if router else SIMPLE_TEMPLATE
content = template.format(name=name, title=title_case(name))
(skill_dir / "SKILL.md").write_text(content)
if router:
# Write example workflow
workflow_content = WORKFLOW_TEMPLATE.format(title="First Workflow")
(skill_dir / "workflows" / "first.md").write_text(workflow_content)
# Write example reference
reference_content = REFERENCE_TEMPLATE.format(title="Topic Reference")
(skill_dir / "references" / "topic.md").write_text(reference_content)
return skill_dir
def main():
parser = argparse.ArgumentParser(
description="Initialize a new skill with template structure."
)
parser.add_argument(
"name",
help="Skill name (lowercase-with-hyphens)"
)
parser.add_argument(
"--path",
type=Path,
default=Path.home() / ".claude" / "skills",
help="Directory to create skill in (default: ~/.claude/skills)"
)
parser.add_argument(
"--router",
action="store_true",
help="Create router skill with workflows/ and references/"
)
args = parser.parse_args()
# Validate name
import re
if not re.match(r'^[a-z0-9-]+$', args.name):
print(f"Error: name must be lowercase letters, numbers, and hyphens only")
sys.exit(1)
if args.name.startswith('-') or args.name.endswith('-') or '--' in args.name:
print(f"Error: name cannot start/end with hyphen or contain consecutive hyphens")
sys.exit(1)
try:
skill_dir = init_skill(args.name, args.path, args.router)
print(f"✓ Created skill: {skill_dir}")
print()
print("Files created:")
for f in sorted(skill_dir.rglob("*")):
if f.is_file():
rel = f.relative_to(skill_dir)
print(f" {rel}")
print()
print("Next steps:")
print(" 1. Edit SKILL.md - fill in description and instructions")
print(" 2. Run validate.py to check structure")
print(" 3. Test activation with real user phrases")
except ValueError as e:
print(f"Error: {e}")
sys.exit(1)
if __name__ == "__main__":
main()
#!/usr/bin/env bash
#
# Update source skills from upstream repositories.
#
# Downloads the latest version of each source skill and replaces
# the corresponding directory in sources/.
#
# Usage:
# ./scripts/update-sources.sh # Update all sources
# ./scripts/update-sources.sh anthropic # Update specific source
#
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SKILL_DIR="$(dirname "$SCRIPT_DIR")"
SOURCES_DIR="$SKILL_DIR/sources"
# Format: name|repo_url|branch|path_within_repo
SOURCES=(
"anthropic|https://github.com/anthropics/skills|main|skills/skill-creator"
"everyinc|https://github.com/EveryInc/compound-engineering-plugin|main|plugins/compound-engineering/skills/create-agent-skills"
"obra|https://github.com/obra/superpowers|main|skills/writing-skills"
"pproenca|https://github.com/pproenca/dot-skills|master|skills/.curated/skill-authoring"
"pytorch|https://github.com/pytorch/pytorch|main|.claude/skills/skill-writer"
)
# Spec docs from agentskills.io - fetched directly with Accept: text/markdown
SPEC_BASE_URL="https://agentskills.io"
SPEC_PAGES=(
"what-are-skills"
"specification"
"integrate-skills"
)
# skills-ref library from GitHub
SKILLS_REF_REPO="https://github.com/agentskills/agentskills"
SKILLS_REF_BRANCH="main"
SKILLS_REF_PATH="skills-ref"
update_spec() {
local spec_dir="$SKILL_DIR/spec"
echo "Updating spec from agentskills.io..."
# Clear and recreate spec directory (but preserve skills-ref for separate update)
rm -rf "${spec_dir:?}"/*.md "${spec_dir:?}"/.source 2>/dev/null || true
mkdir -p "$spec_dir"
# Fetch each page with Accept: text/markdown
for page in "${SPEC_PAGES[@]}"; do
echo " Fetching: $page"
if curl -sfH "Accept: text/markdown" "$SPEC_BASE_URL/$page" > "$spec_dir/$page.md"; then
echo " OK"
else
echo " WARNING: Failed to fetch $page"
fi
done
# Fetch skills-ref library from GitHub
echo " Fetching: skills-ref library"
local tmp_dir
tmp_dir="$(mktemp -d)"
local commit
git clone --depth 1 --branch "$SKILLS_REF_BRANCH" --filter=blob:none --sparse "$SKILLS_REF_REPO" "$tmp_dir/repo" 2>/dev/null
pushd "$tmp_dir/repo" > /dev/null
git sparse-checkout set "$SKILLS_REF_PATH" 2>/dev/null
commit="$(git rev-parse HEAD)"
popd > /dev/null
rm -rf "$spec_dir/skills-ref"
cp -r "$tmp_dir/repo/$SKILLS_REF_PATH" "$spec_dir/skills-ref"
rm -rf "$tmp_dir"
echo " OK (commit: ${commit:0:8})"
# Record provenance
cat > "$spec_dir/.source" << EOF
source: $SPEC_BASE_URL
skills-ref: $SKILLS_REF_REPO ($SKILLS_REF_BRANCH @ $commit)
updated: $(date -Iseconds)
pages:
$(printf ' - %s\n' "${SPEC_PAGES[@]}")
EOF
echo " Done."
}
update_source() {
local name="$1"
local repo="$2"
local branch="$3"
local path="$4"
local tmp_dir
tmp_dir="$(mktemp -d)"
trap "rm -rf '$tmp_dir'" RETURN
echo "Updating $name..."
echo " Repo: $repo"
echo " Branch: $branch"
echo " Path: $path"
# Shallow clone with sparse checkout for efficiency
git clone --depth 1 --branch "$branch" --filter=blob:none --sparse "$repo" "$tmp_dir/repo" 2>/dev/null
pushd "$tmp_dir/repo" > /dev/null
git sparse-checkout set "$path" 2>/dev/null
popd > /dev/null
# Verify the path exists
if [[ ! -d "$tmp_dir/repo/$path" ]]; then
echo " ERROR: Path '$path' not found in repository"
return 1
fi
# Replace the source directory
rm -rf "${SOURCES_DIR:?}/$name"
mkdir -p "$SOURCES_DIR"
cp -r "$tmp_dir/repo/$path" "$SOURCES_DIR/$name"
# Rename SKILL.md to SKILL.reference.md to prevent Pi from discovering it
# (Pi recursively discovers all SKILL.md files as active skills)
if [[ -f "$SOURCES_DIR/$name/SKILL.md" ]]; then
mv "$SOURCES_DIR/$name/SKILL.md" "$SOURCES_DIR/$name/SKILL.reference.md"
echo " Renamed SKILL.md → SKILL.reference.md (prevents Pi discovery)"
fi
# Record provenance
local commit
commit="$(git -C "$tmp_dir/repo" rev-parse HEAD)"
cat > "$SOURCES_DIR/$name/.source" << EOF
repo: $repo
branch: $branch
path: $path
commit: $commit
updated: $(date -Iseconds)
EOF
echo " Done. Commit: ${commit:0:8}"
}
main() {
local filter="${1:-}"
local updated=0
# Update spec if no filter or filter is "spec"
if [[ -z "$filter" || "$filter" == "spec" ]]; then
update_spec
((updated++)) || true
echo
fi
# Skip sources if only updating spec
if [[ "$filter" == "spec" ]]; then
echo "Updated $updated target(s)."
return 0
fi
# Update sources
for source in "${SOURCES[@]}"; do
IFS='|' read -r name repo branch path <<< "$source"
# Skip if filter specified and doesn't match
if [[ -n "$filter" && "$name" != "$filter" ]]; then
continue
fi
if update_source "$name" "$repo" "$branch" "$path"; then
((updated++)) || true
fi
echo
done
if [[ $updated -eq 0 ]]; then
echo "Unknown target: $filter"
echo "Available: spec, anthropic, everyinc, obra, pproenca, pytorch"
exit 1
fi
echo "Updated $updated target(s)."
}
main "$@"
#!/usr/bin/env bash
#
# Validate a skill using skills-ref.
#
# Usage:
# ./scripts/validate.sh <skill_directory>
#
# Requires: uv (https://docs.astral.sh/uv/)
#
# This script uses uvx to run the official skills-ref validator
# from the vendored copy in spec/skills-ref/.
#
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SKILL_DIR="$(dirname "$SCRIPT_DIR")"
SKILLS_REF_DIR="$SKILL_DIR/spec/skills-ref"
if [[ $# -lt 1 ]]; then
echo "Usage: $0 <skill_directory>"
echo ""
echo "Example:"
echo " $0 path/to/my-skill"
exit 1
fi
# Resolve to absolute path
TARGET_SKILL="$(cd "$1" 2>/dev/null && pwd || echo "$1")"
# Check if uv is available
if ! command -v uv &> /dev/null; then
echo "Error: uv is required but not installed."
echo "Install it from: https://docs.astral.sh/uv/"
exit 1
fi
# Check if skills-ref is vendored
if [[ ! -d "$SKILLS_REF_DIR" ]]; then
echo "Error: skills-ref not found at $SKILLS_REF_DIR"
echo "Run ./scripts/update-sources.sh spec to download it."
exit 1
fi
# Run skills-ref validate using uv
exec uv run --directory "$SKILLS_REF_DIR" skills-ref validate "$TARGET_SKILL"
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.Output Patterns
Use these patterns when skills need to produce consistent, high-quality output.
Template Pattern
Provide templates for output format. Match the level of strictness to your needs.
For strict requirements (like API responses or data formats):
## Report structure
ALWAYS use this exact template structure:
# [Analysis Title]
## Executive summary
[One-paragraph overview of key findings]
## Key findings
- Finding 1 with supporting data
- Finding 2 with supporting data
- Finding 3 with supporting data
## Recommendations
1. Specific actionable recommendation
2. Specific actionable recommendationFor flexible guidance (when adaptation is useful):
## Report structure
Here is a sensible default format, but use your best judgment:
# [Analysis Title]
## Executive summary
[Overview]
## Key findings
[Adapt sections based on what you discover]
## Recommendations
[Tailor to the specific context]
Adjust sections as needed for the specific analysis type.Examples Pattern
For skills where output quality depends on seeing examples, provide input/output pairs:
## Commit message format
Generate commit messages following these examples:
**Example 1:**
Input: Added user authentication with JWT tokens
Output:feat(auth): implement JWT-based authentication
Add login endpoint and token validation middleware
**Example 2:**
Input: Fixed bug where dates displayed incorrectly in reports
Output:fix(reports): correct date formatting in timezone conversion
Use UTC timestamps consistently across report generation
Follow this style: type(scope): brief description, then detailed explanation.Examples help Claude understand the desired style and level of detail more clearly than descriptions alone.
Workflow Patterns
Sequential Workflows
For complex tasks, break operations into clear, sequential steps. It is often helpful to give Claude an overview of the process towards the beginning of SKILL.md:
Filling a PDF form involves these steps:
1. Analyze the form (run analyze_form.py)
2. Create field mapping (edit fields.json)
3. Validate mapping (run validate_fields.py)
4. Fill the form (run fill_form.py)
5. Verify output (run verify_output.py)Conditional Workflows
For tasks with branching logic, guide Claude through decision points:
1. Determine the modification type:
**Creating new content?** → Follow "Creation workflow" below
**Editing existing content?** → Follow "Editing workflow" below
2. Creation workflow: [steps]
3. Editing workflow: [steps]#!/usr/bin/env python3
"""
Skill Initializer - Creates a new skill from template
Usage:
init_skill.py <skill-name> --path <path>
Examples:
init_skill.py my-new-skill --path skills/public
init_skill.py my-api-helper --path skills/private
init_skill.py custom-skill --path /custom/location
"""
import sys
from pathlib import Path
SKILL_TEMPLATE = """---
name: {skill_name}
description: [TODO: Complete and informative explanation of what the skill does and when to use it. Include WHEN to use this skill - specific scenarios, file types, or tasks that trigger it.]
---
# {skill_title}
## Overview
[TODO: 1-2 sentences explaining what this skill enables]
## Structuring This Skill
[TODO: Choose the structure that best fits this skill's purpose. Common patterns:
**1. Workflow-Based** (best for sequential processes)
- Works well when there are clear step-by-step procedures
- Example: DOCX skill with "Workflow Decision Tree" → "Reading" → "Creating" → "Editing"
- Structure: ## Overview → ## Workflow Decision Tree → ## Step 1 → ## Step 2...
**2. Task-Based** (best for tool collections)
- Works well when the skill offers different operations/capabilities
- Example: PDF skill with "Quick Start" → "Merge PDFs" → "Split PDFs" → "Extract Text"
- Structure: ## Overview → ## Quick Start → ## Task Category 1 → ## Task Category 2...
**3. Reference/Guidelines** (best for standards or specifications)
- Works well for brand guidelines, coding standards, or requirements
- Example: Brand styling with "Brand Guidelines" → "Colors" → "Typography" → "Features"
- Structure: ## Overview → ## Guidelines → ## Specifications → ## Usage...
**4. Capabilities-Based** (best for integrated systems)
- Works well when the skill provides multiple interrelated features
- Example: Product Management with "Core Capabilities" → numbered capability list
- Structure: ## Overview → ## Core Capabilities → ### 1. Feature → ### 2. Feature...
Patterns can be mixed and matched as needed. Most skills combine patterns (e.g., start with task-based, add workflow for complex operations).
Delete this entire "Structuring This Skill" section when done - it's just guidance.]
## [TODO: Replace with the first main section based on chosen structure]
[TODO: Add content here. See examples in existing skills:
- Code samples for technical skills
- Decision trees for complex workflows
- Concrete examples with realistic user requests
- References to scripts/templates/references as needed]
## Resources
This skill includes example resource directories that demonstrate how to organize different types of bundled resources:
### scripts/
Executable code (Python/Bash/etc.) that can be run directly to perform specific operations.
**Examples from other skills:**
- PDF skill: `fill_fillable_fields.py`, `extract_form_field_info.py` - utilities for PDF manipulation
- DOCX skill: `document.py`, `utilities.py` - Python modules for document processing
**Appropriate for:** Python scripts, shell scripts, or any executable code that performs automation, data processing, or specific operations.
**Note:** Scripts may be executed without loading into context, but can still be read by Claude for patching or environment adjustments.
### references/
Documentation and reference material intended to be loaded into context to inform Claude's process and thinking.
**Examples from other skills:**
- Product management: `communication.md`, `context_building.md` - detailed workflow guides
- BigQuery: API reference documentation and query examples
- Finance: Schema documentation, company policies
**Appropriate for:** In-depth documentation, API references, database schemas, comprehensive guides, or any detailed information that Claude should reference while working.
### assets/
Files not intended to be loaded into context, but rather used within the output Claude produces.
**Examples from other skills:**
- Brand styling: PowerPoint template files (.pptx), logo files
- Frontend builder: HTML/React boilerplate project directories
- Typography: Font files (.ttf, .woff2)
**Appropriate for:** Templates, boilerplate code, document templates, images, icons, fonts, or any files meant to be copied or used in the final output.
---
**Any unneeded directories can be deleted.** Not every skill requires all three types of resources.
"""
EXAMPLE_SCRIPT = '''#!/usr/bin/env python3
"""
Example helper script for {skill_name}
This is a placeholder script that can be executed directly.
Replace with actual implementation or delete if not needed.
Example real scripts from other skills:
- pdf/scripts/fill_fillable_fields.py - Fills PDF form fields
- pdf/scripts/convert_pdf_to_images.py - Converts PDF pages to images
"""
def main():
print("This is an example script for {skill_name}")
# TODO: Add actual script logic here
# This could be data processing, file conversion, API calls, etc.
if __name__ == "__main__":
main()
'''
EXAMPLE_REFERENCE = """# Reference Documentation for {skill_title}
This is a placeholder for detailed reference documentation.
Replace with actual reference content or delete if not needed.
Example real reference docs from other skills:
- product-management/references/communication.md - Comprehensive guide for status updates
- product-management/references/context_building.md - Deep-dive on gathering context
- bigquery/references/ - API references and query examples
## When Reference Docs Are Useful
Reference docs are ideal for:
- Comprehensive API documentation
- Detailed workflow guides
- Complex multi-step processes
- Information too lengthy for main SKILL.md
- Content that's only needed for specific use cases
## Structure Suggestions
### API Reference Example
- Overview
- Authentication
- Endpoints with examples
- Error codes
- Rate limits
### Workflow Guide Example
- Prerequisites
- Step-by-step instructions
- Common patterns
- Troubleshooting
- Best practices
"""
EXAMPLE_ASSET = """# Example Asset File
This placeholder represents where asset files would be stored.
Replace with actual asset files (templates, images, fonts, etc.) or delete if not needed.
Asset files are NOT intended to be loaded into context, but rather used within
the output Claude produces.
Example asset files from other skills:
- Brand guidelines: logo.png, slides_template.pptx
- Frontend builder: hello-world/ directory with HTML/React boilerplate
- Typography: custom-font.ttf, font-family.woff2
- Data: sample_data.csv, test_dataset.json
## Common Asset Types
- Templates: .pptx, .docx, boilerplate directories
- Images: .png, .jpg, .svg, .gif
- Fonts: .ttf, .otf, .woff, .woff2
- Boilerplate code: Project directories, starter files
- Icons: .ico, .svg
- Data files: .csv, .json, .xml, .yaml
Note: This is a text placeholder. Actual assets can be any file type.
"""
def title_case_skill_name(skill_name):
"""Convert hyphenated skill name to Title Case for display."""
return ' '.join(word.capitalize() for word in skill_name.split('-'))
def init_skill(skill_name, path):
"""
Initialize a new skill directory with template SKILL.md.
Args:
skill_name: Name of the skill
path: Path where the skill directory should be created
Returns:
Path to created skill directory, or None if error
"""
# Determine skill directory path
skill_dir = Path(path).resolve() / skill_name
# Check if directory already exists
if skill_dir.exists():
print(f"❌ Error: Skill directory already exists: {skill_dir}")
return None
# Create skill directory
try:
skill_dir.mkdir(parents=True, exist_ok=False)
print(f"✅ Created skill directory: {skill_dir}")
except Exception as e:
print(f"❌ Error creating directory: {e}")
return None
# Create SKILL.md from template
skill_title = title_case_skill_name(skill_name)
skill_content = SKILL_TEMPLATE.format(
skill_name=skill_name,
skill_title=skill_title
)
skill_md_path = skill_dir / 'SKILL.md'
try:
skill_md_path.write_text(skill_content)
print("✅ Created SKILL.md")
except Exception as e:
print(f"❌ Error creating SKILL.md: {e}")
return None
# Create resource directories with example files
try:
# Create scripts/ directory with example script
scripts_dir = skill_dir / 'scripts'
scripts_dir.mkdir(exist_ok=True)
example_script = scripts_dir / 'example.py'
example_script.write_text(EXAMPLE_SCRIPT.format(skill_name=skill_name))
example_script.chmod(0o755)
print("✅ Created scripts/example.py")
# Create references/ directory with example reference doc
references_dir = skill_dir / 'references'
references_dir.mkdir(exist_ok=True)
example_reference = references_dir / 'api_reference.md'
example_reference.write_text(EXAMPLE_REFERENCE.format(skill_title=skill_title))
print("✅ Created references/api_reference.md")
# Create assets/ directory with example asset placeholder
assets_dir = skill_dir / 'assets'
assets_dir.mkdir(exist_ok=True)
example_asset = assets_dir / 'example_asset.txt'
example_asset.write_text(EXAMPLE_ASSET)
print("✅ Created assets/example_asset.txt")
except Exception as e:
print(f"❌ Error creating resource directories: {e}")
return None
# Print next steps
print(f"\n✅ Skill '{skill_name}' initialized successfully at {skill_dir}")
print("\nNext steps:")
print("1. Edit SKILL.md to complete the TODO items and update the description")
print("2. Customize or delete the example files in scripts/, references/, and assets/")
print("3. Run the validator when ready to check the skill structure")
return skill_dir
def main():
if len(sys.argv) < 4 or sys.argv[2] != '--path':
print("Usage: init_skill.py <skill-name> --path <path>")
print("\nSkill name requirements:")
print(" - Hyphen-case identifier (e.g., 'data-analyzer')")
print(" - Lowercase letters, digits, and hyphens only")
print(" - Max 40 characters")
print(" - Must match directory name exactly")
print("\nExamples:")
print(" init_skill.py my-new-skill --path skills/public")
print(" init_skill.py my-api-helper --path skills/private")
print(" init_skill.py custom-skill --path /custom/location")
sys.exit(1)
skill_name = sys.argv[1]
path = sys.argv[3]
print(f"🚀 Initializing skill: {skill_name}")
print(f" Location: {path}")
print()
result = init_skill(skill_name, path)
if result:
sys.exit(0)
else:
sys.exit(1)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Skill Packager - Creates a distributable .skill file of a skill folder
Usage:
python utils/package_skill.py <path/to/skill-folder> [output-directory]
Example:
python utils/package_skill.py skills/public/my-skill
python utils/package_skill.py skills/public/my-skill ./dist
"""
import sys
import zipfile
from pathlib import Path
from quick_validate import validate_skill
def package_skill(skill_path, output_dir=None):
"""
Package a skill folder into a .skill file.
Args:
skill_path: Path to the skill folder
output_dir: Optional output directory for the .skill file (defaults to current directory)
Returns:
Path to the created .skill file, or None if error
"""
skill_path = Path(skill_path).resolve()
# Validate skill folder exists
if not skill_path.exists():
print(f"❌ Error: Skill folder not found: {skill_path}")
return None
if not skill_path.is_dir():
print(f"❌ Error: Path is not a directory: {skill_path}")
return None
# Validate SKILL.md exists
skill_md = skill_path / "SKILL.md"
if not skill_md.exists():
print(f"❌ Error: SKILL.md not found in {skill_path}")
return None
# Run validation before packaging
print("🔍 Validating skill...")
valid, message = validate_skill(skill_path)
if not valid:
print(f"❌ Validation failed: {message}")
print(" Please fix the validation errors before packaging.")
return None
print(f"✅ {message}\n")
# Determine output location
skill_name = skill_path.name
if output_dir:
output_path = Path(output_dir).resolve()
output_path.mkdir(parents=True, exist_ok=True)
else:
output_path = Path.cwd()
skill_filename = output_path / f"{skill_name}.skill"
# Create the .skill file (zip format)
try:
with zipfile.ZipFile(skill_filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
# Walk through the skill directory
for file_path in skill_path.rglob('*'):
if file_path.is_file():
# Calculate the relative path within the zip
arcname = file_path.relative_to(skill_path.parent)
zipf.write(file_path, arcname)
print(f" Added: {arcname}")
print(f"\n✅ Successfully packaged skill to: {skill_filename}")
return skill_filename
except Exception as e:
print(f"❌ Error creating .skill file: {e}")
return None
def main():
if len(sys.argv) < 2:
print("Usage: python utils/package_skill.py <path/to/skill-folder> [output-directory]")
print("\nExample:")
print(" python utils/package_skill.py skills/public/my-skill")
print(" python utils/package_skill.py skills/public/my-skill ./dist")
sys.exit(1)
skill_path = sys.argv[1]
output_dir = sys.argv[2] if len(sys.argv) > 2 else None
print(f"📦 Packaging skill: {skill_path}")
if output_dir:
print(f" Output directory: {output_dir}")
print()
result = package_skill(skill_path, output_dir)
if result:
sys.exit(0)
else:
sys.exit(1)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Quick validation script for skills - minimal version
"""
import sys
import os
import re
import yaml
from pathlib import Path
def validate_skill(skill_path):
"""Basic validation of a skill"""
skill_path = Path(skill_path)
# Check SKILL.md exists
skill_md = skill_path / 'SKILL.md'
if not skill_md.exists():
return False, "SKILL.md not found"
# Read and validate frontmatter
content = skill_md.read_text()
if not content.startswith('---'):
return False, "No YAML frontmatter found"
# Extract frontmatter
match = re.match(r'^---\n(.*?)\n---', content, re.DOTALL)
if not match:
return False, "Invalid frontmatter format"
frontmatter_text = match.group(1)
# Parse YAML frontmatter
try:
frontmatter = yaml.safe_load(frontmatter_text)
if not isinstance(frontmatter, dict):
return False, "Frontmatter must be a YAML dictionary"
except yaml.YAMLError as e:
return False, f"Invalid YAML in frontmatter: {e}"
# Define allowed properties
ALLOWED_PROPERTIES = {'name', 'description', 'license', 'allowed-tools', 'metadata'}
# Check for unexpected properties (excluding nested keys under metadata)
unexpected_keys = set(frontmatter.keys()) - ALLOWED_PROPERTIES
if unexpected_keys:
return False, (
f"Unexpected key(s) in SKILL.md frontmatter: {', '.join(sorted(unexpected_keys))}. "
f"Allowed properties are: {', '.join(sorted(ALLOWED_PROPERTIES))}"
)
# Check required fields
if 'name' not in frontmatter:
return False, "Missing 'name' in frontmatter"
if 'description' not in frontmatter:
return False, "Missing 'description' in frontmatter"
# Extract name for validation
name = frontmatter.get('name', '')
if not isinstance(name, str):
return False, f"Name must be a string, got {type(name).__name__}"
name = name.strip()
if name:
# Check naming convention (hyphen-case: lowercase with hyphens)
if not re.match(r'^[a-z0-9-]+$', name):
return False, f"Name '{name}' should be hyphen-case (lowercase letters, digits, and hyphens only)"
if name.startswith('-') or name.endswith('-') or '--' in name:
return False, f"Name '{name}' cannot start/end with hyphen or contain consecutive hyphens"
# Check name length (max 64 characters per spec)
if len(name) > 64:
return False, f"Name is too long ({len(name)} characters). Maximum is 64 characters."
# Extract and validate description
description = frontmatter.get('description', '')
if not isinstance(description, str):
return False, f"Description must be a string, got {type(description).__name__}"
description = description.strip()
if description:
# Check for angle brackets
if '<' in description or '>' in description:
return False, "Description cannot contain angle brackets (< or >)"
# Check description length (max 1024 characters per spec)
if len(description) > 1024:
return False, f"Description is too long ({len(description)} characters). Maximum is 1024 characters."
return True, "Skill is valid!"
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python quick_validate.py <skill_directory>")
sys.exit(1)
valid, message = validate_skill(sys.argv[1])
print(message)
sys.exit(0 if valid else 1)Skill Creator
This skill provides guidance for creating effective skills.
About Skills
Skills are modular, self-contained packages that extend Claude's capabilities by providing specialized knowledge, workflows, and tools. Think of them as "onboarding guides" for specific domains or tasks—they transform Claude from a general-purpose agent into a specialized agent equipped with procedural knowledge that no model can fully possess.
What Skills Provide
1. Specialized workflows - Multi-step procedures for specific domains 2. Tool integrations - Instructions for working with specific file formats or APIs 3. Domain expertise - Company-specific knowledge, schemas, business logic 4. Bundled resources - Scripts, references, and assets for complex and repetitive tasks
Core Principles
Concise is Key
The context window is a public good. Skills share the context window with everything else Claude needs: system prompt, conversation history, other Skills' metadata, and the actual user request.
Default assumption: Claude is already very smart. Only add context Claude doesn't already have. Challenge each piece of information: "Does Claude really need this explanation?" and "Does this paragraph justify its token cost?"
Prefer concise examples over verbose explanations.
Set Appropriate Degrees of Freedom
Match the level of specificity to the task's fragility and variability:
High freedom (text-based instructions): Use when multiple approaches are valid, decisions depend on context, or heuristics guide the approach.
Medium freedom (pseudocode or scripts with parameters): Use when a preferred pattern exists, some variation is acceptable, or configuration affects behavior.
Low freedom (specific scripts, few parameters): Use when operations are fragile and error-prone, consistency is critical, or a specific sequence must be followed.
Think of Claude as exploring a path: a narrow bridge with cliffs needs specific guardrails (low freedom), while an open field allows many routes (high freedom).
Anatomy of a Skill
Every skill consists of a required SKILL.md file and optional bundled resources:
skill-name/
├── SKILL.md (required)
│ ├── YAML frontmatter metadata (required)
│ │ ├── name: (required)
│ │ └── description: (required)
│ └── Markdown instructions (required)
└── Bundled Resources (optional)
├── scripts/ - Executable code (Python/Bash/etc.)
├── references/ - Documentation intended to be loaded into context as needed
└── assets/ - Files used in output (templates, icons, fonts, etc.)SKILL.md (required)
Every SKILL.md consists of:
- Frontmatter (YAML): Contains
nameanddescriptionfields. These are the only fields that Claude reads to determine when the skill gets used, thus it is very important to be clear and comprehensive in describing what the skill is, and when it should be used. - Body (Markdown): Instructions and guidance for using the skill. Only loaded AFTER the skill triggers (if at all).
Bundled Resources (optional)
Scripts (scripts/)
Executable code (Python/Bash/etc.) for tasks that require deterministic reliability or are repeatedly rewritten.
- When to include: When the same code is being rewritten repeatedly or deterministic reliability is needed
- Example:
scripts/rotate_pdf.pyfor PDF rotation tasks - Benefits: Token efficient, deterministic, may be executed without loading into context
- Note: Scripts may still need to be read by Claude for patching or environment-specific adjustments
References (references/)
Documentation and reference material intended to be loaded as needed into context to inform Claude's process and thinking.
- When to include: For documentation that Claude should reference while working
- Examples:
references/finance.mdfor financial schemas,references/mnda.mdfor company NDA template,references/policies.mdfor company policies,references/api_docs.mdfor API specifications - Use cases: Database schemas, API documentation, domain knowledge, company policies, detailed workflow guides
- Benefits: Keeps SKILL.md lean, loaded only when Claude determines it's needed
- Best practice: If files are large (>10k words), include grep search patterns in SKILL.md
- Avoid duplication: Information should live in either SKILL.md or references files, not both. Prefer references files for detailed information unless it's truly core to the skill—this keeps SKILL.md lean while making information discoverable without hogging the context window. Keep only essential procedural instructions and workflow guidance in SKILL.md; move detailed reference material, schemas, and examples to references files.
Assets (assets/)
Files not intended to be loaded into context, but rather used within the output Claude produces.
- When to include: When the skill needs files that will be used in the final output
- Examples:
assets/logo.pngfor brand assets,assets/slides.pptxfor PowerPoint templates,assets/frontend-template/for HTML/React boilerplate,assets/font.ttffor typography - Use cases: Templates, images, icons, boilerplate code, fonts, sample documents that get copied or modified
- Benefits: Separates output resources from documentation, enables Claude to use files without loading them into context
What to Not Include in a Skill
A skill should only contain essential files that directly support its functionality. Do NOT create extraneous documentation or auxiliary files, including:
- README.md
- INSTALLATION_GUIDE.md
- QUICK_REFERENCE.md
- CHANGELOG.md
- etc.
The skill should only contain the information needed for an AI agent to do the job at hand. It should not contain auxilary context about the process that went into creating it, setup and testing procedures, user-facing documentation, etc. Creating additional documentation files just adds clutter and confusion.
Progressive Disclosure Design Principle
Skills use a three-level loading system to manage context efficiently:
1. Metadata (name + description) - Always in context (~100 words) 2. SKILL.md body - When skill triggers (<5k words) 3. Bundled resources - As needed by Claude (Unlimited because scripts can be executed without reading into context window)
Progressive Disclosure Patterns
Keep SKILL.md body to the essentials and under 500 lines to minimize context bloat. Split content into separate files when approaching this limit. When splitting out content into other files, it is very important to reference them from SKILL.md and describe clearly when to read them, to ensure the reader of the skill knows they exist and when to use them.
Key principle: When a skill supports multiple variations, frameworks, or options, keep only the core workflow and selection guidance in SKILL.md. Move variant-specific details (patterns, examples, configuration) into separate reference files.
Pattern 1: High-level guide with references
# PDF Processing
## Quick start
Extract text with pdfplumber:
[code example]
## Advanced features
- **Form filling**: See [FORMS.md](FORMS.md) for complete guide
- **API reference**: See [REFERENCE.md](REFERENCE.md) for all methods
- **Examples**: See [EXAMPLES.md](EXAMPLES.md) for common patternsClaude loads FORMS.md, REFERENCE.md, or EXAMPLES.md only when needed.
Pattern 2: Domain-specific organization
For Skills with multiple domains, organize content by domain to avoid loading irrelevant context:
bigquery-skill/
├── SKILL.md (overview and navigation)
└── reference/
├── finance.md (revenue, billing metrics)
├── sales.md (opportunities, pipeline)
├── product.md (API usage, features)
└── marketing.md (campaigns, attribution)When a user asks about sales metrics, Claude only reads sales.md.
Similarly, for skills supporting multiple frameworks or variants, organize by variant:
cloud-deploy/
├── SKILL.md (workflow + provider selection)
└── references/
├── aws.md (AWS deployment patterns)
├── gcp.md (GCP deployment patterns)
└── azure.md (Azure deployment patterns)When the user chooses AWS, Claude only reads aws.md.
Pattern 3: Conditional details
Show basic content, link to advanced content:
# DOCX Processing
## Creating documents
Use docx-js for new documents. See [DOCX-JS.md](DOCX-JS.md).
## Editing documents
For simple edits, modify the XML directly.
**For tracked changes**: See [REDLINING.md](REDLINING.md)
**For OOXML details**: See [OOXML.md](OOXML.md)Claude reads REDLINING.md or OOXML.md only when the user needs those features.
Important guidelines:
- Avoid deeply nested references - Keep references one level deep from SKILL.md. All reference files should link directly from SKILL.md.
- Structure longer reference files - For files longer than 100 lines, include a table of contents at the top so Claude can see the full scope when previewing.
Skill Creation Process
Skill creation involves these steps:
1. Understand the skill with concrete examples 2. Plan reusable skill contents (scripts, references, assets) 3. Initialize the skill (run init_skill.py) 4. Edit the skill (implement resources and write SKILL.md) 5. Package the skill (run package_skill.py) 6. Iterate based on real usage
Follow these steps in order, skipping only if there is a clear reason why they are not applicable.
Step 1: Understanding the Skill with Concrete Examples
Skip this step only when the skill's usage patterns are already clearly understood. It remains valuable even when working with an existing skill.
To create an effective skill, clearly understand concrete examples of how the skill will be used. This understanding can come from either direct user examples or generated examples that are validated with user feedback.
For example, when building an image-editor skill, relevant questions include:
- "What functionality should the image-editor skill support? Editing, rotating, anything else?"
- "Can you give some examples of how this skill would be used?"
- "I can imagine users asking for things like 'Remove the red-eye from this image' or 'Rotate this image'. Are there other ways you imagine this skill being used?"
- "What would a user say that should trigger this skill?"
To avoid overwhelming users, avoid asking too many questions in a single message. Start with the most important questions and follow up as needed for better effectiveness.
Conclude this step when there is a clear sense of the functionality the skill should support.
Step 2: Planning the Reusable Skill Contents
To turn concrete examples into an effective skill, analyze each example by:
1. Considering how to execute on the example from scratch 2. Identifying what scripts, references, and assets would be helpful when executing these workflows repeatedly
Example: When building a pdf-editor skill to handle queries like "Help me rotate this PDF," the analysis shows:
1. Rotating a PDF requires re-writing the same code each time 2. A scripts/rotate_pdf.py script would be helpful to store in the skill
Example: When designing a frontend-webapp-builder skill for queries like "Build me a todo app" or "Build me a dashboard to track my steps," the analysis shows:
1. Writing a frontend webapp requires the same boilerplate HTML/React each time 2. An assets/hello-world/ template containing the boilerplate HTML/React project files would be helpful to store in the skill
Example: When building a big-query skill to handle queries like "How many users have logged in today?" the analysis shows:
1. Querying BigQuery requires re-discovering the table schemas and relationships each time 2. A references/schema.md file documenting the table schemas would be helpful to store in the skill
To establish the skill's contents, analyze each concrete example to create a list of the reusable resources to include: scripts, references, and assets.
Step 3: Initializing the Skill
At this point, it is time to actually create the skill.
Skip this step only if the skill being developed already exists, and iteration or packaging is needed. In this case, continue to the next step.
When creating a new skill from scratch, always run the init_skill.py script. The script conveniently generates a new template skill directory that automatically includes everything a skill requires, making the skill creation process much more efficient and reliable.
Usage:
scripts/init_skill.py <skill-name> --path <output-directory>The script:
- Creates the skill directory at the specified path
- Generates a SKILL.md template with proper frontmatter and TODO placeholders
- Creates example resource directories:
scripts/,references/, andassets/ - Adds example files in each directory that can be customized or deleted
After initialization, customize or remove the generated SKILL.md and example files as needed.
Step 4: Edit the Skill
When editing the (newly-generated or existing) skill, remember that the skill is being created for another instance of Claude to use. Include information that would be beneficial and non-obvious to Claude. Consider what procedural knowledge, domain-specific details, or reusable assets would help another Claude instance execute these tasks more effectively.
Learn Proven Design Patterns
Consult these helpful guides based on your skill's needs:
- Multi-step processes: See references/workflows.md for sequential workflows and conditional logic
- Specific output formats or quality standards: See references/output-patterns.md for template and example patterns
These files contain established best practices for effective skill design.
Start with Reusable Skill Contents
To begin implementation, start with the reusable resources identified above: scripts/, references/, and assets/ files. Note that this step may require user input. For example, when implementing a brand-guidelines skill, the user may need to provide brand assets or templates to store in assets/, or documentation to store in references/.
Added scripts must be tested by actually running them to ensure there are no bugs and that the output matches what is expected. If there are many similar scripts, only a representative sample needs to be tested to ensure confidence that they all work while balancing time to completion.
Any example files and directories not needed for the skill should be deleted. The initialization script creates example files in scripts/, references/, and assets/ to demonstrate structure, but most skills won't need all of them.
Update SKILL.md
Writing Guidelines: Always use imperative/infinitive form.
Frontmatter
Write the YAML frontmatter with name and description:
name: The skill namedescription: This is the primary triggering mechanism for your skill, and helps Claude understand when to use the skill.- Include both what the Skill does and specific triggers/contexts for when to use it.
- Include all "when to use" information here - Not in the body. The body is only loaded after triggering, so "When to Use This Skill" sections in the body are not helpful to Claude.
- Example description for a
docxskill: "Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. Use when Claude needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks"
Do not include any other fields in YAML frontmatter.
Body
Write instructions for using the skill and its bundled resources.
Step 5: Packaging a Skill
Once development of the skill is complete, it must be packaged into a distributable .skill file that gets shared with the user. The packaging process automatically validates the skill first to ensure it meets all requirements:
scripts/package_skill.py <path/to/skill-folder>Optional output directory specification:
scripts/package_skill.py <path/to/skill-folder> ./distThe packaging script will:
1. Validate the skill automatically, checking:
- YAML frontmatter format and required fields
- Skill naming conventions and directory structure
- Description completeness and quality
- File organization and resource references
2. Package the skill if validation passes, creating a .skill file named after the skill (e.g., my-skill.skill) that includes all files and maintains the proper directory structure for distribution. The .skill file is a zip file with a .skill extension.
If validation fails, the script will report the errors and exit without creating a package. Fix any validation errors and run the packaging command again.
Step 6: Iterate
After testing the skill, users may request improvements. Often this happens right after using the skill, with fresh context of how the skill performed.
Iteration workflow:
1. Use the skill on real tasks 2. Notice struggles or inefficiencies 3. Identify how SKILL.md or bundled resources should be updated 4. Implement changes and test again
MIT License
Copyright (c) 2025 Every
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.
<overview> When building skills that make API calls requiring credentials (API keys, tokens, secrets), follow this protocol to prevent credentials from appearing in chat. </overview>
<the_problem> Raw curl commands with environment variables expose credentials:
# ❌ BAD - API key visible in chat
curl -H "Authorization: Bearer $API_KEY" https://api.example.com/dataWhen Claude executes this, the full command with expanded $API_KEY appears in the conversation. </the_problem>
<the_solution> Use ~/.claude/scripts/secure-api.sh - a wrapper that loads credentials internally.
<for_supported_services>
# ✅ GOOD - No credentials visible
~/.claude/scripts/secure-api.sh <service> <operation> [args]
# Examples:
~/.claude/scripts/secure-api.sh facebook list-campaigns
~/.claude/scripts/secure-api.sh ghl search-contact "email@example.com"</for_supported_services>
<adding_new_services> When building a new skill that requires API calls:
1. Add operations to the wrapper (~/.claude/scripts/secure-api.sh):
case "$SERVICE" in
yourservice)
case "$OPERATION" in
list-items)
curl -s -G \
-H "Authorization: Bearer $YOUR_API_KEY" \
"https://api.yourservice.com/items"
;;
get-item)
ITEM_ID=$1
curl -s -G \
-H "Authorization: Bearer $YOUR_API_KEY" \
"https://api.yourservice.com/items/$ITEM_ID"
;;
*)
echo "Unknown operation: $OPERATION" >&2
exit 1
;;
esac
;;
esac2. Add profile support to the wrapper (if service needs multiple accounts):
# In secure-api.sh, add to profile remapping section:
yourservice)
SERVICE_UPPER="YOURSERVICE"
YOURSERVICE_API_KEY=$(eval echo \$${SERVICE_UPPER}_${PROFILE_UPPER}_API_KEY)
YOURSERVICE_ACCOUNT_ID=$(eval echo \$${SERVICE_UPPER}_${PROFILE_UPPER}_ACCOUNT_ID)
;;3. Add credential placeholders to `~/.claude/.env` using profile naming:
# Check if entries already exist
grep -q "YOURSERVICE_MAIN_API_KEY=" ~/.claude/.env 2>/dev/null || \
echo -e "\n# Your Service - Main profile\nYOURSERVICE_MAIN_API_KEY=\nYOURSERVICE_MAIN_ACCOUNT_ID=" >> ~/.claude/.env
echo "Added credential placeholders to ~/.claude/.env - user needs to fill them in"4. Document profile workflow in your SKILL.md:
## Profile Selection Workflow
**CRITICAL:** Always use profile selection to prevent using wrong account credentials.
### When user requests YourService operation:
1. **Check for saved profile:**~/.claude/scripts/profile-state get yourservice
2. **If no profile saved, discover available profiles:**~/.claude/scripts/list-profiles yourservice
3. **If only ONE profile:** Use it automatically and announce:"Using YourService profile 'main' to list items..."
4. **If MULTIPLE profiles:** Ask user which one:"Which YourService profile: main, clienta, or clientb?"
5. **Save user's selection:**~/.claude/scripts/profile-state set yourservice <selected_profile>
6. **Always announce which profile before calling API:**"Using YourService profile 'main' to list items..."
7. **Make API call with profile:**~/.claude/scripts/secure-api.sh yourservice:<profile> list-items
## Secure API Calls
All API calls use profile syntax:
~/.claude/scripts/secure-api.sh yourservice:<profile> <operation> [args]
Examples:
~/.claude/scripts/secure-api.sh yourservice:main list-items ~/.claude/scripts/secure-api.sh yourservice:main get-item <ITEM_ID>
**Profile persists for session:** Once selected, use same profile for subsequent operations unless user explicitly changes it.</adding_new_services> </the_solution>
<pattern_guidelines> <simple_get_requests>
curl -s -G \
-H "Authorization: Bearer $API_KEY" \
"https://api.example.com/endpoint"</simple_get_requests>
<post_with_json_body>
ITEM_ID=$1
curl -s -X POST \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d @- \
"https://api.example.com/items/$ITEM_ID"Usage:
echo '{"name":"value"}' | ~/.claude/scripts/secure-api.sh service create-item</post_with_json_body>
<post_with_form_data>
curl -s -X POST \
-F "field1=value1" \
-F "field2=value2" \
-F "access_token=$API_TOKEN" \
"https://api.example.com/endpoint"</post_with_form_data> </pattern_guidelines>
<credential_storage> Location: ~/.claude/.env (global for all skills, accessible from any directory)
Format:
# Service credentials
SERVICE_API_KEY=your-key-here
SERVICE_ACCOUNT_ID=account-id-here
# Another service
OTHER_API_TOKEN=token-here
OTHER_BASE_URL=https://api.other.comLoading in script:
set -a
source ~/.claude/.env 2>/dev/null || { echo "Error: ~/.claude/.env not found" >&2; exit 1; }
set +a</credential_storage>
<best_practices> 1. Never use raw curl with `$VARIABLE` in skill examples - always use the wrapper 2. Add all operations to the wrapper - don't make users figure out curl syntax 3. Auto-create credential placeholders - add empty fields to ~/.claude/.env immediately when creating the skill 4. Keep credentials in `~/.claude/.env` - one central location, works everywhere 5. Document each operation - show examples in SKILL.md 6. Handle errors gracefully - check for missing env vars, show helpful error messages </best_practices>
<testing> Test the wrapper without exposing credentials:
# This command appears in chat
~/.claude/scripts/secure-api.sh facebook list-campaigns
# But API keys never appear - they're loaded inside the scriptVerify credentials are loaded:
# Check .env exists
ls -la ~/.claude/.env
# Check specific variables (without showing values)
grep -q "YOUR_API_KEY=" ~/.claude/.env && echo "API key configured" || echo "API key missing"</testing>
<golden_rule> Show your skill to someone with minimal context and ask them to follow the instructions. If they're confused, Claude will likely be too. </golden_rule>
<overview> Clarity and directness are fundamental to effective skill authoring. Clear instructions reduce errors, improve execution quality, and minimize token waste. </overview>
<guidelines> <contextual_information> Give Claude contextual information that frames the task:
- What the task results will be used for
- What audience the output is meant for
- What workflow the task is part of
- The end goal or what successful completion looks like
Context helps Claude make better decisions and produce more appropriate outputs.
<example>
<context>
This analysis will be presented to investors who value transparency and actionable insights. Focus on financial metrics and clear recommendations.
</context></example> </contextual_information>
<specificity> Be specific about what you want Claude to do. If you want code only and nothing else, say so.
Vague: "Help with the report" Specific: "Generate a markdown report with three sections: Executive Summary, Key Findings, Recommendations"
Vague: "Process the data" Specific: "Extract customer names and email addresses from the CSV file, removing duplicates, and save to JSON format"
Specificity eliminates ambiguity and reduces iteration cycles. </specificity>
<sequential_steps> Provide instructions as sequential steps. Use numbered lists or bullet points.
<workflow>
1. Extract data from source file
2. Transform to target format
3. Validate transformation
4. Save to output file
5. Verify output correctness
</workflow>Sequential steps create clear expectations and reduce the chance Claude skips important operations. </sequential_steps> </guidelines>
<example_comparison> <unclear_example>
<quick_start>
Please remove all personally identifiable information from these customer feedback messages: {{FEEDBACK_DATA}}
</quick_start>Problems:
- What counts as PII?
- What should replace PII?
- What format should the output be?
- What if no PII is found?
- Should product names be redacted?
</unclear_example>
<clear_example>
<objective>
Anonymize customer feedback for quarterly review presentation.
</objective>
<quick_start>
<instructions>
1. Replace all customer names with "CUSTOMER_[ID]" (e.g., "Jane Doe" → "CUSTOMER_001")
2. Replace email addresses with "EMAIL_[ID]@example.com"
3. Redact phone numbers as "PHONE_[ID]"
4. If a message mentions a specific product (e.g., "AcmeCloud"), leave it intact
5. If no PII is found, copy the message verbatim
6. Output only the processed messages, separated by "---"
</instructions>
Data to process: {{FEEDBACK_DATA}}
</quick_start>
<success_criteria>
- All customer names replaced with IDs
- All emails and phones redacted
- Product names preserved
- Output format matches specification
</success_criteria>Why this is better:
- States the purpose (quarterly review)
- Provides explicit step-by-step rules
- Defines output format clearly
- Specifies edge cases (product names, no PII found)
- Defines success criteria
</clear_example> </example_comparison>
<key_differences> The clear version:
- States the purpose (quarterly review)
- Provides explicit step-by-step rules
- Defines output format
- Specifies edge cases (product names, no PII found)
- Includes success criteria
The unclear version leaves all these decisions to Claude, increasing the chance of misalignment with expectations. </key_differences>
<show_dont_just_tell> <principle> When format matters, show an example rather than just describing it. </principle>
<telling_example>
<commit_messages>
Generate commit messages in conventional format with type, scope, and description.
</commit_messages></telling_example>
<showing_example>
<commit_message_format>
Generate commit messages following these examples:
<example number="1">
<input>Added user authentication with JWT tokens</input>
<output>feat(auth): implement JWT-based authentication
Add login endpoint and token validation middleware
</output>
</example>
<example number="2">
<input>Fixed bug where dates displayed incorrectly in reports</input>
<output>fix(reports): correct date formatting in timezone conversion
Use UTC timestamps consistently across report generation
</output>
</example>
Follow this style: type(scope): brief description, then detailed explanation.
</commit_message_format></showing_example>
<why_showing_works> Examples communicate nuances that text descriptions can't:
- Exact formatting (spacing, capitalization, punctuation)
- Tone and style
- Level of detail
- Pattern across multiple cases
Claude learns patterns from examples more reliably than from descriptions. </why_showing_works> </show_dont_just_tell>
<avoid_ambiguity> <principle> Eliminate words and phrases that create ambiguity or leave decisions open. </principle>
<ambiguous_phrases> ❌ "Try to..." - Implies optional ✅ "Always..." or "Never..." - Clear requirement
❌ "Should probably..." - Unclear obligation ✅ "Must..." or "May optionally..." - Clear obligation level
❌ "Generally..." - When are exceptions allowed? ✅ "Always... except when..." - Clear rule with explicit exceptions
❌ "Consider..." - Should Claude always do this or only sometimes? ✅ "If X, then Y" or "Always..." - Clear conditions </ambiguous_phrases>
<example> ❌ Ambiguous:
<validation>
You should probably validate the output and try to fix any errors.
</validation>✅ Clear:
<validation>
Always validate output before proceeding:
python scripts/validate.py output_dir/
If validation fails, fix errors and re-validate. Only proceed when validation passes with zero errors.
</validation></example> </avoid_ambiguity>
<define_edge_cases> <principle> Anticipate edge cases and define how to handle them. Don't leave Claude guessing. </principle>
<without_edge_cases>
<quick_start>
Extract email addresses from the text file and save to a JSON array.
</quick_start>Questions left unanswered:
- What if no emails are found?
- What if the same email appears multiple times?
- What if emails are malformed?
- What JSON format exactly?
</without_edge_cases>
<with_edge_cases>
<quick_start>
Extract email addresses from the text file and save to a JSON array.
<edge_cases>
- **No emails found**: Save empty array `[]`
- **Duplicate emails**: Keep only unique emails
- **Malformed emails**: Skip invalid formats, log to stderr
- **Output format**: Array of strings, one email per element
</edge_cases>
<example_output>[ "user1@example.com", "user2@example.com" ]
</example_output>
</quick_start></with_edge_cases> </define_edge_cases>
<output_format_specification> <principle> When output format matters, specify it precisely. Show examples. </principle>
<vague_format>
<output>
Generate a report with the analysis results.
</output></vague_format>
<specific_format>
<output_format>
Generate a markdown report with this exact structure:
Analysis Report: [Title]
Executive Summary
[1-2 paragraphs summarizing key findings]
Key Findings
- Finding 1 with supporting data
- Finding 2 with supporting data
- Finding 3 with supporting data
Recommendations
1. Specific actionable recommendation 2. Specific actionable recommendation
Appendix
[Raw data and detailed calculations]
**Requirements**:
- Use exactly these section headings
- Executive summary must be 1-2 paragraphs
- List 3-5 key findings
- Provide 2-4 recommendations
- Include appendix with source data
</output_format></specific_format> </output_format_specification>
<decision_criteria> <principle> When Claude must make decisions, provide clear criteria. </principle>
<no_criteria>
<workflow>
Analyze the data and decide which visualization to use.
</workflow>Problem: What factors should guide this decision? </no_criteria>
<with_criteria>
<workflow>
Analyze the data and select appropriate visualization:
<decision_criteria>
**Use bar chart when**:
- Comparing quantities across categories
- Fewer than 10 categories
- Exact values matter
**Use line chart when**:
- Showing trends over time
- Continuous data
- Pattern recognition matters more than exact values
**Use scatter plot when**:
- Showing relationship between two variables
- Looking for correlations
- Individual data points matter
</decision_criteria>
</workflow>Benefits: Claude has objective criteria for making the decision rather than guessing. </with_criteria> </decision_criteria>
<constraints_and_requirements> <principle> Clearly separate "must do" from "nice to have" from "must not do". </principle>
<unclear_requirements>
<requirements>
The report should include financial data, customer metrics, and market analysis. It would be good to have visualizations. Don't make it too long.
</requirements>Problems:
- Are all three content types required?
- Are visualizations optional or required?
- How long is "too long"?
</unclear_requirements>
<clear_requirements>
<requirements>
<must_have>
- Financial data (revenue, costs, profit margins)
- Customer metrics (acquisition, retention, lifetime value)
- Market analysis (competition, trends, opportunities)
- Maximum 5 pages
</must_have>
<nice_to_have>
- Charts and visualizations
- Industry benchmarks
- Future projections
</nice_to_have>
<must_not>
- Include confidential customer names
- Exceed 5 pages
- Use technical jargon without definitions
</must_not>
</requirements>Benefits: Clear priorities and constraints prevent misalignment. </clear_requirements> </constraints_and_requirements>
<success_criteria> <principle> Define what success looks like. How will Claude know it succeeded? </principle>
<without_success_criteria>
<objective>
Process the CSV file and generate a report.
</objective>Problem: When is this task complete? What defines success? </without_success_criteria>
<with_success_criteria>
<objective>
Process the CSV file and generate a summary report.
</objective>
<success_criteria>
- All rows in CSV successfully parsed
- No data validation errors
- Report generated with all required sections
- Report saved to output/report.md
- Output file is valid markdown
- Process completes without errors
</success_criteria>Benefits: Clear completion criteria eliminate ambiguity about when the task is done. </with_success_criteria> </success_criteria>
<testing_clarity> <principle> Test your instructions by asking: "Could I hand these instructions to a junior developer and expect correct results?" </principle>
<testing_process> 1. Read your skill instructions 2. Remove context only you have (project knowledge, unstated assumptions) 3. Identify ambiguous terms or vague requirements 4. Add specificity where needed 5. Test with someone who doesn't have your context 6. Iterate based on their questions and confusion
If a human with minimal context struggles, Claude will too. </testing_process> </testing_clarity>
<practical_examples> <example domain="data_processing"> ❌ Unclear:
<quick_start>
Clean the data and remove bad entries.
</quick_start>✅ Clear:
<quick_start>
<data_cleaning>
1. Remove rows where required fields (name, email, date) are empty
2. Standardize date format to YYYY-MM-DD
3. Remove duplicate entries based on email address
4. Validate email format (must contain @ and domain)
5. Save cleaned data to output/cleaned_data.csv
</data_cleaning>
<success_criteria>
- No empty required fields
- All dates in YYYY-MM-DD format
- No duplicate emails
- All emails valid format
- Output file created successfully
</success_criteria>
</quick_start></example>
<example domain="code_generation"> ❌ Unclear:
<quick_start>
Write a function to process user input.
</quick_start>✅ Clear:
<quick_start>
<function_specification>
Write a Python function with this signature:
def process_user_input(raw_input: str) -> dict: """ Validate and parse user input.
Args: raw_input: Raw string from user (format: "name:email:age")
Returns: dict with keys: name (str), email (str), age (int)
Raises: ValueError: If input format is invalid """
**Requirements**:
- Split input on colon delimiter
- Validate email contains @ and domain
- Convert age to integer, raise ValueError if not numeric
- Return dictionary with specified keys
- Include docstring and type hints
</function_specification>
<success_criteria>
- Function signature matches specification
- All validation checks implemented
- Proper error handling for invalid input
- Type hints included
- Docstring included
</success_criteria>
</quick_start></example> </practical_examples>
Skill Authoring Best Practices
Source: platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices
Core Principles
Concise is Key
The context window is a public good. Your Skill shares the context window with everything else Claude needs to know.
Default assumption: Claude is already very smart. Only add context Claude doesn't already have.
Challenge each piece of information:
- "Does Claude really need this explanation?"
- "Can I assume Claude knows this?"
- "Does this paragraph justify its token cost?"
Good example (concise, ~50 tokens):
## Extract PDF text
Use pdfplumber for text extraction:
import pdfplumber with pdfplumber.open("file.pdf") as pdf: text = pdf.pages[0].extract_text()
Bad example (too verbose, ~150 tokens):
## Extract PDF text
PDF (Portable Document Format) files are a common file format that contains
text, images, and other content. To extract text from a PDF, you'll need to
use a library. There are many libraries available...Set Appropriate Degrees of Freedom
Match specificity to task fragility and variability.
High freedom (multiple valid approaches):
## Code review process
1. Analyze the code structure and organization
2. Check for potential bugs or edge cases
3. Suggest improvements for readability
4. Verify adherence to project conventionsMedium freedom (preferred pattern with variation):
## Generate report
Use this template and customize as needed:
def generate_report(data, format="markdown"):
Process data
Generate output in specified format
Low freedom (fragile, exact sequence required):
## Database migration
Run exactly this script:
python scripts/migrate.py --verify --backup
Do not modify the command or add flags.Test With All Models
Skills act as additions to models. Test with Haiku, Sonnet, and Opus.
- Haiku: Does the Skill provide enough guidance?
- Sonnet: Is the Skill clear and efficient?
- Opus: Does the Skill avoid over-explaining?
Naming Conventions
Use gerund form (verb + -ing) for Skill names:
Good:
processing-pdfsanalyzing-spreadsheetsmanaging-databasestesting-codewriting-documentation
Acceptable alternatives:
- Noun phrases:
pdf-processing,spreadsheet-analysis - Action-oriented:
process-pdfs,analyze-spreadsheets
Avoid:
- Vague:
helper,utils,tools - Generic:
documents,data,files - Reserved:
anthropic-*,claude-*
Writing Effective Descriptions
Always write in third person. The description is injected into the system prompt.
Be specific and include key terms:
# PDF Processing skill
description: Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF files or when the user mentions PDFs, forms, or document extraction.
# Excel Analysis skill
description: Analyze Excel spreadsheets, create pivot tables, generate charts. Use when analyzing Excel files, spreadsheets, tabular data, or .xlsx files.
# Git Commit Helper skill
description: Generate descriptive commit messages by analyzing git diffs. Use when the user asks for help writing commit messages or reviewing staged changes.Avoid vague descriptions:
description: Helps with documents # Too vague!
description: Processes data # Too generic!
description: Does stuff with files # Useless!Progressive Disclosure Patterns
Pattern 1: High-level guide with references
---
name: pdf-processing
description: Extracts text and tables from PDF files, fills forms, merges documents.
---
# PDF Processing
## Quick start
import pdfplumber with pdfplumber.open("file.pdf") as pdf: text = pdf.pages[0].extract_text()
## Advanced features
**Form filling**: See [FORMS.md](FORMS.md)
**API reference**: See [REFERENCE.md](REFERENCE.md)
**Examples**: See [EXAMPLES.md](EXAMPLES.md)Pattern 2: Domain-specific organization
bigquery-skill/
├── SKILL.md (overview and navigation)
└── reference/
├── finance.md (revenue, billing)
├── sales.md (opportunities, pipeline)
├── product.md (API usage, features)
└── marketing.md (campaigns, attribution)Pattern 3: Conditional details
# DOCX Processing
## Creating documents
Use docx-js for new documents. See [DOCX-JS.md](DOCX-JS.md).
## Editing documents
For simple edits, modify the XML directly.
**For tracked changes**: See [REDLINING.md](REDLINING.md)
**For OOXML details**: See [OOXML.md](OOXML.md)Keep References One Level Deep
Claude may partially read files when they're referenced from other referenced files.
Bad (too deep):
# SKILL.md
See [advanced.md](advanced.md)...
# advanced.md
See [details.md](details.md)...
# details.md
Here's the actual information...Good (one level deep):
# SKILL.md
**Basic usage**: [in SKILL.md]
**Advanced features**: See [advanced.md](advanced.md)
**API reference**: See [reference.md](reference.md)
**Examples**: See [examples.md](examples.md)Workflows and Feedback Loops
Workflow with Checklist
## Research synthesis workflow
Copy this checklist:
- [ ] Step 1: Read all source documents
- [ ] Step 2: Identify key themes
- [ ] Step 3: Cross-reference claims
- [ ] Step 4: Create structured summary
- [ ] Step 5: Verify citations
**Step 1: Read all source documents**
Review each document in `sources/`. Note main arguments.
...Feedback Loop Pattern
## Document editing process
1. Make your edits to `word/document.xml`
2. **Validate immediately**: `python scripts/validate.py unpacked_dir/`
3. If validation fails:
- Review the error message
- Fix the issues
- Run validation again
4. **Only proceed when validation passes**
5. Rebuild: `python scripts/pack.py unpacked_dir/ output.docx`Common Patterns
Template Pattern
## Report structure
Use this template:
[Analysis Title]
Executive summary
[One-paragraph overview]
Key findings
- Finding 1 with supporting data
- Finding 2 with supporting data
Recommendations
1. Specific actionable recommendation 2. Specific actionable recommendation
Examples Pattern
## Commit message format
**Example 1:**
Input: Added user authentication with JWT tokens
Output:feat(auth): implement JWT-based authentication
Add login endpoint and token validation middleware
**Example 2:**
Input: Fixed bug where dates displayed incorrectly
Output:fix(reports): correct date formatting in timezone conversion
Conditional Workflow Pattern
## Document modification
1. Determine the modification type:
**Creating new content?** → Follow "Creation workflow"
**Editing existing?** → Follow "Editing workflow"
2. Creation workflow:
- Use docx-js library
- Build document from scratch
3. Editing workflow:
- Unpack existing document
- Modify XML directly
- Validate after each changeContent Guidelines
Avoid Time-Sensitive Information
Bad:
If you're doing this before August 2025, use the old API.Good:
## Current method
Use the v2 API endpoint: `api.example.com/v2/messages`
## Old patterns
<details>
<summary>Legacy v1 API (deprecated 2025-08)</summary>
The v1 API used: `api.example.com/v1/messages`
</details>Use Consistent Terminology
Good - Consistent:
- Always "API endpoint"
- Always "field"
- Always "extract"
Bad - Inconsistent:
- Mix "API endpoint", "URL", "API route", "path"
- Mix "field", "box", "element", "control"
Anti-Patterns to Avoid
Windows-Style Paths
- Good:
scripts/helper.py,reference/guide.md - Avoid:
scripts\helper.py,reference\guide.md
Too Many Options
Bad:
You can use pypdf, or pdfplumber, or PyMuPDF, or pdf2image, or...Good:
Use pdfplumber for text extraction:import pdfplumber
For scanned PDFs requiring OCR, use pdf2image with pytesseract instead.Checklist for Effective Skills
Core Quality
- [ ] Description is specific and includes key terms
- [ ] Description includes both what and when
- [ ] SKILL.md body under 500 lines
- [ ] Additional details in separate files
- [ ] No time-sensitive information
- [ ] Consistent terminology
- [ ] Examples are concrete
- [ ] References one level deep
- [ ] Progressive disclosure used appropriately
- [ ] Workflows have clear steps
Code and Scripts
- [ ] Scripts handle errors explicitly
- [ ] No "voodoo constants" (all values justified)
- [ ] Required packages listed
- [ ] Scripts have clear documentation
- [ ] No Windows-style paths
- [ ] Validation steps for critical operations
- [ ] Feedback loops for quality-critical tasks
Testing
- [ ] At least three test scenarios
- [ ] Tested with Haiku, Sonnet, and Opus
- [ ] Tested with real usage scenarios
- [ ] Team feedback incorporated
<overview> This reference documents common patterns for skill authoring, including templates, examples, terminology consistency, and anti-patterns. All patterns use pure XML structure. </overview>
<template_pattern> <description> Provide templates for output format. Match the level of strictness to your needs. </description>
<strict_requirements> Use when output format must be exact and consistent:
<report_structure>
ALWAYS use this exact template structure:
[Analysis Title]
Executive summary
[One-paragraph overview of key findings]
Key findings
- Finding 1 with supporting data
- Finding 2 with supporting data
- Finding 3 with supporting data
Recommendations
1. Specific actionable recommendation 2. Specific actionable recommendation
</report_structure>When to use: Compliance reports, standardized formats, automated processing </strict_requirements>
<flexible_guidance> Use when Claude should adapt the format based on context:
<report_structure>
Here is a sensible default format, but use your best judgment:
[Analysis Title]
Executive summary
[Overview]
Key findings
[Adapt sections based on what you discover]
Recommendations
[Tailor to the specific context]
Adjust sections as needed for the specific analysis type.
</report_structure>When to use: Exploratory analysis, context-dependent formatting, creative tasks </flexible_guidance> </template_pattern>
<examples_pattern> <description> For skills where output quality depends on seeing examples, provide input/output pairs. </description>
<commit_messages_example>
<objective>
Generate commit messages following conventional commit format.
</objective>
<commit_message_format>
Generate commit messages following these examples:
<example number="1">
<input>Added user authentication with JWT tokens</input>
<output>feat(auth): implement JWT-based authentication
Add login endpoint and token validation middleware
</output>
</example>
<example number="2">
<input>Fixed bug where dates displayed incorrectly in reports</input>
<output>fix(reports): correct date formatting in timezone conversion
Use UTC timestamps consistently across report generation
</output>
</example>
Follow this style: type(scope): brief description, then detailed explanation.
</commit_message_format></commit_messages_example>
<when_to_use>
- Output format has nuances that text explanations can't capture
- Pattern recognition is easier than rule following
- Examples demonstrate edge cases
- Multi-shot learning improves quality
</when_to_use> </examples_pattern>
<consistent_terminology> <principle> Choose one term and use it throughout the skill. Inconsistent terminology confuses Claude and reduces execution quality. </principle>
<good_example> Consistent usage:
- Always "API endpoint" (not mixing with "URL", "API route", "path")
- Always "field" (not mixing with "box", "element", "control")
- Always "extract" (not mixing with "pull", "get", "retrieve")
<objective>
Extract data from API endpoints using field mappings.
</objective>
<quick_start>
1. Identify the API endpoint
2. Map response fields to your schema
3. Extract field values
</quick_start></good_example>
<bad_example> Inconsistent usage creates confusion:
<objective>
Pull data from API routes using element mappings.
</objective>
<quick_start>
1. Identify the URL
2. Map response boxes to your schema
3. Retrieve control values
</quick_start>Claude must now interpret: Are "API routes" and "URLs" the same? Are "fields", "boxes", "elements", and "controls" the same? </bad_example>
<implementation> 1. Choose terminology early in skill development 2. Document key terms in <objective> or <context> 3. Use find/replace to enforce consistency 4. Review reference files for consistent usage </implementation> </consistent_terminology>
<provide_default_with_escape_hatch> <principle> Provide a default approach with an escape hatch for special cases, not a list of alternatives. Too many options paralyze decision-making. </principle>
<good_example> Clear default with escape hatch:
<quick_start>
Use pdfplumber for text extraction:
import pdfplumber with pdfplumber.open("file.pdf") as pdf: text = pdf.pages[0].extract_text()
For scanned PDFs requiring OCR, use pdf2image with pytesseract instead.
</quick_start></good_example>
<bad_example> Too many options creates decision paralysis:
<quick_start>
You can use any of these libraries:
- **pypdf**: Good for basic extraction
- **pdfplumber**: Better for tables
- **PyMuPDF**: Faster but more complex
- **pdf2image**: For scanned documents
- **pdfminer**: Low-level control
- **tabula-py**: Table-focused
Choose based on your needs.
</quick_start>Claude must now research and compare all options before starting. This wastes tokens and time. </bad_example>
<implementation> 1. Recommend ONE default approach 2. Explain when to use the default (implied: most of the time) 3. Add ONE escape hatch for edge cases 4. Link to advanced reference if multiple alternatives truly needed </implementation> </provide_default_with_escape_hatch>
<anti_patterns> <description> Common mistakes to avoid when authoring skills. </description>
<pitfall name="markdown_headings_in_body"> ❌ BAD: Using markdown headings in skill body:
# PDF Processing
## Quick start
Extract text with pdfplumber...
## Advanced features
Form filling requires additional setup...✅ GOOD: Using pure XML structure:
<objective>
PDF processing with text extraction, form filling, and merging capabilities.
</objective>
<quick_start>
Extract text with pdfplumber...
</quick_start>
<advanced_features>
Form filling requires additional setup...
</advanced_features>Why it matters: XML provides semantic meaning, reliable parsing, and token efficiency. </pitfall>
<pitfall name="vague_descriptions"> ❌ BAD:
description: Helps with documents✅ GOOD:
description: Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF files or when the user mentions PDFs, forms, or document extraction.Why it matters: Vague descriptions prevent Claude from discovering and using the skill appropriately. </pitfall>
<pitfall name="inconsistent_pov"> ❌ BAD:
description: I can help you process Excel files and generate reports✅ GOOD:
description: Processes Excel files and generates reports. Use when analyzing spreadsheets or .xlsx files.Why it matters: Skills must use third person. First/second person breaks the skill metadata pattern. </pitfall>
<pitfall name="wrong_naming_convention"> ❌ BAD: Directory name doesn't match skill name or verb-noun convention:
- Directory:
facebook-ads, Name:facebook-ads-manager - Directory:
stripe-integration, Name:stripe - Directory:
helper-scripts, Name:helper
✅ GOOD: Consistent verb-noun convention:
- Directory:
manage-facebook-ads, Name:manage-facebook-ads - Directory:
setup-stripe-payments, Name:setup-stripe-payments - Directory:
process-pdfs, Name:process-pdfs
Why it matters: Consistency in naming makes skills discoverable and predictable. </pitfall>
<pitfall name="too_many_options"> ❌ BAD:
<quick_start>
You can use pypdf, or pdfplumber, or PyMuPDF, or pdf2image, or pdfminer, or tabula-py...
</quick_start>✅ GOOD:
<quick_start>
Use pdfplumber for text extraction:
import pdfplumber
For scanned PDFs requiring OCR, use pdf2image with pytesseract instead.
</quick_start>Why it matters: Decision paralysis. Provide one default approach with escape hatch for special cases. </pitfall>
<pitfall name="deeply_nested_references"> ❌ BAD: References nested multiple levels:
SKILL.md → advanced.md → details.md → examples.md✅ GOOD: References one level deep from SKILL.md:
SKILL.md → advanced.md
SKILL.md → details.md
SKILL.md → examples.mdWhy it matters: Claude may only partially read deeply nested files. Keep references one level deep from SKILL.md. </pitfall>
<pitfall name="windows_paths"> ❌ BAD:
<reference_guides>
See scripts\validate.py for validation
</reference_guides>✅ GOOD:
<reference_guides>
See scripts/validate.py for validation
</reference_guides>Why it matters: Always use forward slashes for cross-platform compatibility. </pitfall>
<pitfall name="dynamic_context_and_file_reference_execution"> Problem: When showing examples of dynamic context syntax (exclamation mark + backticks) or file references (@ prefix), the skill loader executes these during skill loading.
❌ BAD - These execute during skill load:
<examples>
Load current status with: !`git status`
Review dependencies in: @package.json
</examples>✅ GOOD - Add space to prevent execution:
<examples>
Load current status with: ! `git status` (remove space before backtick in actual usage)
Review dependencies in: @ package.json (remove space after @ in actual usage)
</examples>When this applies:
- Skills that teach users about dynamic context (slash commands, prompts)
- Any documentation showing the exclamation mark prefix syntax or @ file references
- Skills with example commands or file paths that shouldn't execute during loading
Why it matters: Without the space, these execute during skill load, causing errors or unwanted file reads. </pitfall>
<pitfall name="missing_required_tags"> ❌ BAD: Missing required tags:
<quick_start>
Use this tool for processing...
</quick_start>✅ GOOD: All required tags present:
<objective>
Process data files with validation and transformation.
</objective>
<quick_start>
Use this tool for processing...
</quick_start>
<success_criteria>
- Input file successfully processed
- Output file validates without errors
- Transformation applied correctly
</success_criteria>Why it matters: Every skill must have <objective>, <quick_start>, and <success_criteria> (or <when_successful>). </pitfall>
<pitfall name="hybrid_xml_markdown"> ❌ BAD: Mixing XML tags with markdown headings:
<objective>
PDF processing capabilities
</objective>
## Quick start
Extract text with pdfplumber...
## Advanced features
Form filling...✅ GOOD: Pure XML throughout:
<objective>
PDF processing capabilities
</objective>
<quick_start>
Extract text with pdfplumber...
</quick_start>
<advanced_features>
Form filling...
</advanced_features>Why it matters: Consistency in structure. Either use pure XML or pure markdown (prefer XML). </pitfall>
<pitfall name="unclosed_xml_tags"> ❌ BAD: Forgetting to close XML tags:
<objective>
Process PDF files
<quick_start>
Use pdfplumber...
</quick_start>✅ GOOD: Properly closed tags:
<objective>
Process PDF files
</objective>
<quick_start>
Use pdfplumber...
</quick_start>Why it matters: Unclosed tags break XML parsing and create ambiguous boundaries. </pitfall> </anti_patterns>
<progressive_disclosure_pattern> <description> Keep SKILL.md concise by linking to detailed reference files. Claude loads reference files only when needed. </description>
<implementation>
<objective>
Manage Facebook Ads campaigns, ad sets, and ads via the Marketing API.
</objective>
<quick_start>
<basic_operations>
See [basic-operations.md](basic-operations.md) for campaign creation and management.
</basic_operations>
</quick_start>
<advanced_features>
**Custom audiences**: See [audiences.md](audiences.md)
**Conversion tracking**: See [conversions.md](conversions.md)
**Budget optimization**: See [budgets.md](budgets.md)
**API reference**: See [api-reference.md](api-reference.md)
</advanced_features>Benefits:
- SKILL.md stays under 500 lines
- Claude only reads relevant reference files
- Token usage scales with task complexity
- Easier to maintain and update
</implementation> </progressive_disclosure_pattern>
<validation_pattern> <description> For skills with validation steps, make validation scripts verbose and specific. </description>
<implementation>
<validation>
After making changes, validate immediately:
python scripts/validate.py output_dir/
If validation fails, fix errors before continuing. Validation errors include:
- **Field not found**: "Field 'signature_date' not found. Available fields: customer_name, order_total, signature_date_signed"
- **Type mismatch**: "Field 'order_total' expects number, got string"
- **Missing required field**: "Required field 'customer_name' is missing"
Only proceed when validation passes with zero errors.
</validation>Why verbose errors help:
- Claude can fix issues without guessing
- Specific error messages reduce iteration cycles
- Available options shown in error messages
</implementation> </validation_pattern>
<checklist_pattern> <description> For complex multi-step workflows, provide a checklist Claude can copy and track progress. </description>
<implementation>
<workflow>
Copy this checklist and check off items as you complete them:
Task Progress:
- [ ] Step 1: Analyze the form (run analyze_form.py)
- [ ] Step 2: Create field mapping (edit fields.json)
- [ ] Step 3: Validate mapping (run validate_fields.py)
- [ ] Step 4: Fill the form (run fill_form.py)
- [ ] Step 5: Verify output (run verify_output.py)
<step_1>
**Analyze the form**
Run: `python scripts/analyze_form.py input.pdf`
This extracts form fields and their locations, saving to `fields.json`.
</step_1>
<step_2>
**Create field mapping**
Edit `fields.json` to add values for each field.
</step_2>
<step_3>
**Validate mapping**
Run: `python scripts/validate_fields.py fields.json`
Fix any validation errors before continuing.
</step_3>
<step_4>
**Fill the form**
Run: `python scripts/fill_form.py input.pdf fields.json output.pdf`
</step_4>
<step_5>
**Verify output**
Run: `python scripts/verify_output.py output.pdf`
If verification fails, return to Step 2.
</step_5>
</workflow>Benefits:
- Clear progress tracking
- Prevents skipping steps
- Easy to resume after interruption
</implementation> </checklist_pattern>
Using Scripts in Skills
<purpose> Scripts are executable code that Claude runs as-is rather than regenerating each time. They ensure reliable, error-free execution of repeated operations. </purpose>
<when_to_use> Use scripts when:
- The same code runs across multiple skill invocations
- Operations are error-prone when rewritten from scratch
- Complex shell commands or API interactions are involved
- Consistency matters more than flexibility
Common script types:
- Deployment - Deploy to Vercel, publish packages, push releases
- Setup - Initialize projects, install dependencies, configure environments
- API calls - Authenticated requests, webhook handlers, data fetches
- Data processing - Transform files, batch operations, migrations
- Build processes - Compile, bundle, test runners
</when_to_use>
<script_structure> Scripts live in scripts/ within the skill directory:
skill-name/
├── SKILL.md
├── workflows/
├── references/
├── templates/
└── scripts/
├── deploy.sh
├── setup.py
└── fetch-data.tsA well-structured script includes: 1. Clear purpose comment at top 2. Input validation 3. Error handling 4. Idempotent operations where possible 5. Clear output/feedback </script_structure>
<script_example>
#!/bin/bash
# deploy.sh - Deploy project to Vercel
# Usage: ./deploy.sh [environment]
# Environments: preview (default), production
set -euo pipefail
ENVIRONMENT="${1:-preview}"
# Validate environment
if [[ "$ENVIRONMENT" != "preview" && "$ENVIRONMENT" != "production" ]]; then
echo "Error: Environment must be 'preview' or 'production'"
exit 1
fi
echo "Deploying to $ENVIRONMENT..."
if [[ "$ENVIRONMENT" == "production" ]]; then
vercel --prod
else
vercel
fi
echo "Deployment complete."</script_example>
<workflow_integration> Workflows reference scripts like this:
<process>
## Step 5: Deploy
1. Ensure all tests pass
2. Run `scripts/deploy.sh production`
3. Verify deployment succeeded
4. Update user with deployment URL
</process>The workflow tells Claude WHEN to run the script. The script handles HOW the operation executes. </workflow_integration>
<best_practices> Do:
- Make scripts idempotent (safe to run multiple times)
- Include clear usage comments
- Validate inputs before executing
- Provide meaningful error messages
- Use
set -euo pipefailin bash scripts
Don't:
- Hardcode secrets or credentials (use environment variables)
- Create scripts for one-off operations
- Skip error handling
- Make scripts do too many unrelated things
- Forget to make scripts executable (
chmod +x)
</best_practices>
<security_considerations>
- Never embed API keys, tokens, or secrets in scripts
- Use environment variables for sensitive configuration
- Validate and sanitize any user-provided inputs
- Be cautious with scripts that delete or modify data
- Consider adding
--dry-runoptions for destructive operations
</security_considerations>