
Claude Code Mastery
- 61 installs
- 451 repo stars
- Updated July 21, 2026
- borghei/claude-skills
claude-code-mastery is a skill that covers Claude Code CLI mastery, including CLAUDE.md optimization, skill authoring, subagent creation, hooks, and context engineering.
About
This skill covers Claude Code CLI mastery: optimizing CLAUDE.md, authoring skills, creating subagents, configuring hooks, and context engineering. It ships Python tools for scaffolding skill packages, optimizing CLAUDE.md files, and estimating a project's context-window usage. Developers use it to tune their Claude Code setup and build custom skills, subagents, and hooks.
- Optimizes CLAUDE.md and scaffolds new skill packages
- Creates subagents and configures hooks for lifecycle automation
- Analyzes context-window and token budget across a project
Claude Code Mastery by the numbers
- 61 all-time installs (skills.sh)
- Ranked #6,381 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
claude-code-mastery capabilities & compatibility
- Capabilities
- claudemd optimization · skill authoring · subagent creation · context analysis
- Use cases
- token optimization · documentation · orchestration
- Pricing
- Free
What claude-code-mastery says it does
Expert skill for Claude Code CLI -- CLAUDE.md optimization, skill authoring, subagent creation, hooks automation, and context engineering.
Scans a project to estimate context window consumption by file category.
Generates a skill directory with SKILL.md template, scripts/, references/, assets/ directories, and YAML frontmatter.
npx skills add https://github.com/borghei/claude-skills --skill claude-code-masteryAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 61 |
|---|---|
| repo stars | ★ 451 |
| Last updated | July 21, 2026 |
| Repository | borghei/claude-skills ↗ |
What it does
Optimize CLAUDE.md, scaffold skills, create subagents, and manage context budget in Claude Code.
Who is it for?
Developers optimizing their Claude Code setup, authoring skills, or building subagents and hooks.
Skip if: Non-Claude-Code agent frameworks.
When should I use this skill?
You want to optimize CLAUDE.md, create a skill, write a subagent, configure hooks, or manage the context window.
What you get
An optimized CLAUDE.md, scaffolded skills, subagents, and hooks tuned for context efficiency.
- optimized CLAUDE.md
- scaffolded skill package
- subagent definition
By the numbers
- 3 Python tools included
- CLAUDE.md optimizer default token limit 4000
Files
Claude Code Mastery
Expert skill for Claude Code CLI -- CLAUDE.md optimization, skill authoring, subagent creation, hooks automation, and context engineering.
Keywords
claude-code, claude-cli, CLAUDE.md, skill-authoring, subagents, hooks, context-window, token-budget, MCP-servers, worktrees, permission-modes, prompt-engineering, context-engineering, slash-commands
---
Quick Start
# Scaffold a new skill package
python scripts/skill_scaffolder.py my-new-skill --domain engineering --description "Brief description"
# Analyze and optimize an existing CLAUDE.md
python scripts/claudemd_optimizer.py path/to/CLAUDE.md
# Estimate context window usage across a project
python scripts/context_analyzer.py /path/to/project
# All tools support JSON output
python scripts/claudemd_optimizer.py CLAUDE.md --json---
Tools
Skill Scaffolder
Generates a skill directory with SKILL.md template, scripts/, references/, assets/ directories, and YAML frontmatter.
python scripts/skill_scaffolder.py my-skill --domain engineering --description "Does X"| Parameter | Description |
|---|---|
skill_name | Name for the skill (kebab-case) |
--domain, -d | Domain category |
--description | Brief description for frontmatter |
--version | Semantic version (default: 1.0.0) |
--license | License type (default: MIT) |
--output, -o | Parent directory for skill folder |
--json | Output as JSON |
CLAUDE.md Optimizer
Analyzes a CLAUDE.md file and produces optimization recommendations.
python scripts/claudemd_optimizer.py CLAUDE.md --token-limit 4000 --jsonOutput includes: line count, token estimate, section completeness, redundancy detection, missing sections, scored recommendations.
Context Analyzer
Scans a project to estimate context window consumption by file category.
python scripts/context_analyzer.py /path/to/project --max-depth 4 --jsonOutput includes: token estimates per category, percentage of context consumed, largest files, budget breakdown, reduction recommendations.
---
Workflow 1: Optimize a CLAUDE.md
1. Audit -- Run python scripts/claudemd_optimizer.py CLAUDE.md and capture the score. 2. Structure -- Reorganize into these sections:
## Project Purpose -- What the project is
## Architecture Overview -- Directory structure, key patterns
## Development Environment -- Build, test, setup commands
## Key Principles -- 3-7 non-obvious rules
## Anti-Patterns to Avoid -- Things that look right but are wrong
## Git Workflow -- Branch strategy, commit conventions3. Compress -- Convert paragraphs to bullets (saves ~30% tokens). Use code blocks for commands. Remove generic advice Claude already knows. 4. Hierarchize -- Move domain details to child CLAUDE.md files:
project/
├── CLAUDE.md # Global: purpose, architecture, principles
├── frontend/CLAUDE.md # Frontend-specific: React patterns, styling
├── backend/CLAUDE.md # Backend-specific: API patterns, DB conventions
└── .claude/CLAUDE.md # User-specific overrides (gitignored)5. Validate -- Run python scripts/claudemd_optimizer.py CLAUDE.md --token-limit 4000 and confirm score improved.
Workflow 2: Author a New Skill
1. Scaffold -- python scripts/skill_scaffolder.py my-skill -d engineering --description "..." 2. Write SKILL.md in this order:
- YAML frontmatter (name, description with trigger phrases, license, metadata)
- Title and one-line summary
- Quick Start (3-5 copy-pasteable commands)
- Tools (each script with usage and parameters table)
- Workflows (numbered step-by-step sequences)
- Reference links
3. Optimize the description for auto-discovery:
description: >-
This skill should be used when the user asks to "analyze performance",
"optimize queries", "profile memory", or "benchmark endpoints".
Use for performance engineering and capacity planning.4. Build Python tools -- standard library only, argparse CLI, --json flag, module docstring, error handling. 5. Verify -- Confirm the skill triggers on expected prompts and tools run without errors.
Workflow 3: Create a Subagent
1. Define scope -- One narrow responsibility per agent. 2. Create agent YAML at .claude/agents/agent-name.yaml:
name: security-reviewer
description: Reviews code for security vulnerabilities
model: claude-sonnet-4-20250514
allowed-tools:
- Read
- Glob
- Grep
- Bash(git diff*)
custom-instructions: |
For every change:
1. Check for hardcoded secrets
2. Identify injection vulnerabilities
3. Verify auth patterns
4. Flag insecure dependencies
Output a structured report with severity levels.3. Set tool access -- read-only (Read, Glob, Grep), read+commands (+ Bash(npm test*)), or write-capable (+ Edit, Write). 4. Invoke -- /agents/security-reviewer Review the last 3 commits 5. Validate -- Confirm the agent stays within scope and produces structured output.
Workflow 4: Configure Hooks
Hooks run custom scripts at lifecycle events without user approval.
| Hook | Fires When | Blocking |
|---|---|---|
PreToolUse | Before tool executes | Yes (exit 1 blocks) |
PostToolUse | After tool completes | No |
Notification | Claude sends notification | No |
Stop | Claude finishes turn | No |
1. Add hook config to .claude/settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [{ "type": "command", "command": "prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true" }]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "bash .claude/hooks/validate.sh" }]
}
]
}
}2. Test -- Trigger the relevant tool and confirm the hook fires. 3. Iterate -- Add matchers for additional tools as needed.
Workflow 5: Manage Context Budget
1. Audit -- python scripts/context_analyzer.py /path/to/project 2. Apply budget targets:
| Category | Budget | Purpose |
|---|---|---|
| System prompt + CLAUDE.md | 5-10% | Project configuration |
| Skill definitions | 5-15% | Active skill content |
| Source code (read files) | 30-50% | Files Claude reads |
| Conversation history | 20-30% | Messages and responses |
| Working memory | 10-20% | Reasoning space |
3. Reduce overhead -- Keep root CLAUDE.md under 4000 tokens. Use hierarchical loading. Avoid reading entire large files. Use /compact after completing subtasks. 4. Validate -- Re-run context analyzer and confirm overhead dropped.
---
Quick Reference
Slash Commands
| Command | Description |
|---|---|
/compact | Summarize conversation to free context |
/clear | Clear conversation history |
/model | Switch model mid-session |
/agents | List and invoke custom agents |
/permissions | View and modify tool permissions |
/cost | Show token usage and cost |
/doctor | Diagnose configuration issues |
/init | Generate CLAUDE.md for current project |
Permission Modes
| Mode | Behavior | Best For |
|---|---|---|
| Default | Asks permission for writes | Normal development |
| Allowlist | Auto-approves listed tools | Repetitive workflows |
| Yolo | Auto-approves everything | Trusted automation |
{ "permissions": { "allow": ["Read", "Glob", "Grep", "Bash(npm test*)"],
"deny": ["Bash(rm -rf*)", "Bash(git push*)"] } }CLAUDE.md Loading Order
1. ~/.claude/CLAUDE.md -- user global, always loaded 2. /project/CLAUDE.md -- project root, always loaded 3. /project/.claude/CLAUDE.md -- project config, always loaded 4. /project/subdir/CLAUDE.md -- subdirectory, loaded when files accessed
MCP Servers
| Server | Purpose |
|---|---|
server-filesystem | File access beyond project |
server-github | GitHub API (issues, PRs) |
server-postgres | Database queries |
server-memory | Persistent key-value store |
server-brave-search | Web search |
server-puppeteer | Browser automation |
---
Reference Documentation
| Document | Path |
|---|---|
| Skill Authoring Guide | references/skill-authoring-guide.md |
| Subagent Patterns | references/subagent-patterns.md |
| Hooks Cookbook | references/hooks-cookbook.md |
| Skill Template | assets/skill-template.md |
| Agent Template | assets/agent-template.md |
---
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
| CLAUDE.md changes not picked up | Claude loads CLAUDE.md at session start | Start a new conversation or use /clear to reload configuration |
| Skill not triggering on expected prompts | Description field in YAML frontmatter missing trigger phrases | Add quoted user phrases to the description field (e.g., "optimize queries", "profile memory") |
| Context window exhausted mid-task | Root CLAUDE.md too large or too many files read | Run context_analyzer.py to audit token usage, then move domain content to child CLAUDE.md files |
| Hook not firing after tool use | Matcher in .claude/settings.json does not match the tool name | Verify the matcher regex matches the exact tool name (e.g., `Edit\ |
| Subagent exceeds scope and edits unrelated files | allowed-tools list is too permissive | Restrict to read-only tools (Read, Glob, Grep) and add write tools only when necessary |
| Scaffolder fails with "Directory already exists" | Target skill directory already present on disk | Remove or rename the existing directory, or choose a different skill name |
| Optimizer reports low score despite good structure | Token count exceeds the default 6000 limit | Pass --token-limit matching your actual budget (e.g., --token-limit 10000) |
Success Criteria
- CLAUDE.md optimizer score of 80+ on all project CLAUDE.md files
- Root CLAUDE.md stays under 4000 tokens (verified by
claudemd_optimizer.py --token-limit 4000) - Auto-loaded configuration (all CLAUDE.md files combined) consumes less than 10% of the context window
- Every new skill scaffolded passes the optimizer with zero "critical" missing sections
- Subagents stay within their declared
allowed-toolsscope during testing - Hooks execute in under 500ms to avoid perceptible delay on tool use
- Context analyzer shows 50%+ of the context window available for source code and reasoning
Scope & Limitations
This skill covers:
- Authoring, structuring, and optimizing CLAUDE.md files for any project
- Scaffolding new skill packages with correct directory layout and frontmatter
- Creating and configuring Claude Code subagents with scoped tool access
- Analyzing and managing context window token budgets across a codebase
This skill does NOT cover:
- Writing application source code or implementing business logic (see senior-fullstack, senior-backend)
- MCP server development or custom transport protocols (see mcp-server-builder)
- Advanced prompt engineering techniques for LLM applications (see senior-prompt-engineer)
- CI/CD pipeline configuration or deployment automation (see senior-devops, ci-cd-pipeline-builder)
Integration Points
| Skill | Integration | Data Flow |
|---|---|---|
| senior-architect | Architecture decisions inform CLAUDE.md structure sections | Architecture diagrams and patterns feed into the Architecture Overview section of CLAUDE.md |
| code-reviewer | Subagent creation for automated code review | Claude Code Mastery creates the agent YAML; Code Reviewer provides the review logic |
| senior-prompt-engineer | Prompt optimization for skill descriptions and agent instructions | Prompt engineering techniques improve YAML frontmatter trigger phrases and agent custom-instructions |
| doc-drift-detector | Detects when CLAUDE.md drifts out of sync with the codebase | Context Analyzer output feeds drift detection; drift findings trigger CLAUDE.md optimization |
| context-engine | Advanced context management strategies | Context Analyzer provides token budgets; Context Engine applies compression and prioritization |
| senior-secops | Security hooks and permission mode configuration | SecOps policies define which tools to deny; Claude Code Mastery configures the permission allowlists |
Tool Reference
1. Skill Scaffolder (scripts/skill_scaffolder.py)
Purpose: Generate a complete skill package directory with SKILL.md template, starter Python script, reference document, and proper YAML frontmatter.
Usage:
python scripts/skill_scaffolder.py <skill_name> [options]Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
skill_name | positional | Yes | -- | Name for the skill in kebab-case (e.g., my-new-skill) |
--domain, -d | string | No | engineering | Domain category. Options: engineering, marketing, product, project-management, c-level, ra-qm, business-growth, finance, standards, development-tools |
--description | string | No | auto-generated | Brief description for YAML frontmatter, optimized for auto-discovery |
--version | string | No | 1.0.0 | Semantic version for metadata |
--license | string | No | MIT | License type for frontmatter |
--category | string | No | same as domain | Skill category for metadata |
--output, -o | string | No | . (current dir) | Parent directory for the skill folder |
--json | flag | No | off | Output results in JSON format |
Example:
python scripts/skill_scaffolder.py api-analyzer -d engineering --description "API analysis and optimization" --jsonOutput Formats:
- Human-readable (default): Prints skill name, domain, version, location, directory tree, and next-steps checklist.
- JSON (`--json`): Returns
{ success, path, name, domain, version, directories_created, files_created }.
---
2. CLAUDE.md Optimizer (scripts/claudemd_optimizer.py)
Purpose: Analyze a CLAUDE.md file for structure completeness, token efficiency, redundancy, and verbosity. Produces a scored report with prioritized optimization recommendations.
Usage:
python scripts/claudemd_optimizer.py <file_path> [options]Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
file_path | positional | Yes | -- | Path to the CLAUDE.md file to analyze |
--token-limit | integer | No | 6000 | Maximum recommended token count for the file |
--json | flag | No | off | Output results in JSON format |
Example:
python scripts/claudemd_optimizer.py path/to/CLAUDE.md --token-limit 4000Output Formats:
- Human-readable (default): Displays score (0-100), file metrics (lines, words, tokens), section breakdown with per-section token estimates, section completeness checklist (critical/high/medium), redundancy issues, and prioritized recommendations (HIGH/MEDIUM/LOW).
- JSON (`--json`): Returns
{ success, file, metrics, sections, completeness, redundancies, recommendations, score }.
---
3. Context Analyzer (scripts/context_analyzer.py)
Purpose: Scan a project directory to estimate how much of Claude Code's context window is consumed by CLAUDE.md files, skill definitions, source code, and configuration. Produces a token budget breakdown with reduction recommendations.
Usage:
python scripts/context_analyzer.py <project_path> [options]Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
project_path | positional | Yes | -- | Path to the project directory to analyze |
--max-depth | integer | No | 5 | Maximum directory traversal depth |
--context-window | integer | No | 200000 | Total context window size in tokens |
--json | flag | No | off | Output results in JSON format |
Example:
python scripts/context_analyzer.py /path/to/project --max-depth 3 --context-window 200000 --jsonOutput Formats:
- Human-readable (default): Displays project summary (files scanned, total tokens, auto-loaded tokens), context budget breakdown with visual bar chart, per-category breakdown (Claude Configuration, Skill Definitions, Reference Documents, Source Code, Config & Build, Documentation) with largest files listed, top 20 largest files, and prioritized recommendations.
- JSON (`--json`): Returns
{ success, project_path, context_window, summary, categories, budget, largest_files, recommendations }.
<!-- USAGE: Save this file to .claude/agents/your-agent-name.md Invoke with: /agents/your-agent-name <your instructions>
EXAMPLES: /agents/your-agent-name Review the authentication module /agents/your-agent-name Analyze the last 5 commits for issues /agents/your-agent-name Check all API endpoints for problems
CUSTOMIZATION GUIDE: 1. Replace [role], [domain], [scope] with your specifics 2. Adjust allowed-tools to match what the agent needs 3. Customize the Protocol steps for your workflow 4. Modify the Report format if a different structure fits better 5. Add/remove Rules based on your requirements
MODEL OPTIONS: claude-opus-4-20250514 - Complex analysis, architecture decisions claude-sonnet-4-20250514 - General coding, standard review (recommended default) claude-haiku-3-5-20241022 - Simple checks, formatting, quick tasks
TOOL ACCESS PATTERNS: Read-only (review): Read, Glob, Grep Read + git: Read, Glob, Grep, Bash(git diff), Bash(git log) Read + test: Read, Glob, Grep, Bash(npm test), Bash(pytest) Write (generation): Read, Write, Edit, Glob, Grep Full access: (omit allowed-tools entirely) -->
Your Skill Title
One-line summary of what this skill provides and who benefits from it.
Keywords
keyword1, keyword2, keyword3, keyword4, keyword5, action-verb1, action-verb2, domain-term1, domain-term2
---
Table of Contents
- Quick Start
- Tools Overview
- Tool One
- Tool Two
- Workflows
- Primary Workflow
- Secondary Workflow
- Reference Documentation
- Quick Reference
---
Quick Start
# Primary tool - basic usage
python scripts/tool_one.py input_file.txt
# Primary tool - with options
python scripts/tool_one.py input_file.txt --option value --json
# Secondary tool
python scripts/tool_two.py /path/to/dir --format table---
Tools Overview
1. Tool One
Brief description of what this tool does and when to use it.
# Basic usage
python scripts/tool_one.py input
# With options
python scripts/tool_one.py input --option value
# JSON output for piping
python scripts/tool_one.py input --json| Parameter | Description |
|---|---|
input | Description of the input parameter |
--option, -o | Description of the option (default: value) |
--format | Output format: table, json, csv (default: table) |
--json | Output in JSON format |
Example output:
Tool One Report
================
Input: example.txt
Status: Analyzed
Score: 85/100
Findings:
1. Finding description (severity)
2. Finding description (severity)2. Tool Two
Brief description of what this tool does and when to use it.
python scripts/tool_two.py /path/to/dir
python scripts/tool_two.py /path/to/dir --depth 3 --json| Parameter | Description |
|---|---|
path | Directory path to analyze |
--depth, -d | Analysis depth (default: 5) |
--json | Output in JSON format |
---
Workflows
Workflow 1: Primary Workflow
Description of when and why to use this workflow.
Step 1: Analyze the Current State
python scripts/tool_one.py target --json > analysis.jsonReview the output and identify areas that need attention.
Step 2: Apply Changes
Based on the analysis, take the following actions:
- Action based on finding type A
- Action based on finding type B
- Action based on finding type C
Step 3: Validate
python scripts/tool_one.py target --jsonVerify the score has improved and no regressions were introduced.
Workflow 2: Secondary Workflow
Description of the secondary use case.
Step 1: Setup
python scripts/tool_two.py /path/to/projectStep 2: Execute
Follow the recommendations from the tool output.
Step 3: Verify
Re-run the tool and confirm improvements.
---
Reference Documentation
| Document | Path | When to Use |
|---|---|---|
| Deep Guide | references/guide.md | Detailed patterns and strategies |
| Examples | references/examples.md | Real-world usage examples |
---
Quick Reference
Common Commands
| Task | Command |
|---|---|
| Basic analysis | python scripts/tool_one.py input |
| JSON output | python scripts/tool_one.py input --json |
| Directory scan | python scripts/tool_two.py /path |
| Help | python scripts/tool_one.py --help |
Decision Matrix
| Situation | Use This | Because |
|---|---|---|
| Scenario A | Tool One | Reason |
| Scenario B | Tool Two | Reason |
| Scenario C | Workflow 1 | Reason |
---
Last Updated: Month Year Version: 1.0.0
Hooks Cookbook
Practical hook recipes for automating code quality, security enforcement, workflow optimization, and developer experience with Claude Code.
---
Table of Contents
- Hook Architecture
- Lifecycle Events
- Hook Types
- Environment Variables
- Recipes: Code Quality
- Recipes: Security
- Recipes: Workflow
- Recipes: Notifications
- Recipes: Context Management
- Recipes: Logging and Audit
- Recipes: Advanced Patterns
- Best Practices
- Troubleshooting
---
Hook Architecture
Hooks are configured in .claude/settings.json (project-level, committed) or ~/.claude/settings.json (user-level, global). Project-level hooks apply to everyone working on the project. User-level hooks apply to all projects.
{
"hooks": {
"EventName": [
{
"matcher": "ToolNameRegex",
"hooks": [
{
"type": "command",
"command": "your-shell-command"
}
]
}
]
}
}---
Lifecycle Events
| Event | Fires When | Blocking | Use For |
|---|---|---|---|
PreToolUse | Before a tool executes | Yes (exit 1 blocks) | Validation, protection |
PostToolUse | After a tool completes | No | Formatting, logging |
Notification | Claude sends a notification | No | Desktop alerts |
Stop | Claude finishes a response | No | Session logging, cleanup |
SessionStart | Session begins or compact occurs | No | Context injection |
SubagentStart | A subagent is launched | No | Setup, logging |
SubagentStop | A subagent finishes | No | Cleanup, logging |
Blocking behavior: Only PreToolUse hooks can prevent an action. If the hook script exits with code 1, the tool call is blocked. All other events are informational -- the hook runs but cannot stop the action.
---
Hook Types
Command Hooks
Run a shell command. Fast, deterministic, no LLM cost.
{
"type": "command",
"command": "prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
}Prompt Hooks
Send a single-turn prompt to a fast model (Haiku by default). Useful for content evaluation that requires judgment.
{
"type": "prompt",
"prompt": "Check if this change introduces security issues. Output WARNING if yes, nothing if no.",
"model": "haiku"
}Agent Hooks
Launch a multi-turn agent with tool access. Most powerful but slowest and most expensive. Use sparingly.
{
"type": "agent",
"prompt": "Review the changed file for security vulnerabilities and report findings.",
"model": "sonnet",
"tools": ["Read", "Grep"]
}---
Environment Variables
These variables are available in hook commands:
| Variable | Available In | Description |
|---|---|---|
CLAUDE_TOOL_NAME | PreToolUse, PostToolUse | Name of the tool (Edit, Write, Bash, etc.) |
CLAUDE_TOOL_ARG_FILE_PATH | PreToolUse, PostToolUse | File path for Edit/Write/Read |
CLAUDE_TOOL_ARG_COMMAND | PreToolUse, PostToolUse | Command string for Bash |
CLAUDE_TOOL_ARG_PATTERN | PreToolUse, PostToolUse | Pattern for Grep/Glob |
CLAUDE_SESSION_ID | All events | Current session identifier |
CLAUDE_FILE_PATH | PostToolUse | File that was modified (Edit/Write) |
stdin: Hook commands also receive a JSON payload on stdin with the full tool input and context.
---
Recipes: Code Quality
Recipe 1: Auto-Format Python with Black
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "if [[ \"$CLAUDE_FILE_PATH\" == *.py ]]; then python3 -m black --quiet \"$CLAUDE_FILE_PATH\" 2>/dev/null; fi"
}
]
}
]
}
}Recipe 2: Auto-Format JavaScript/TypeScript with Prettier
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "if [[ \"$CLAUDE_FILE_PATH\" =~ \\.(js|jsx|ts|tsx|css|json|md)$ ]]; then npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true; fi"
}
]
}
]
}
}Recipe 3: Run ESLint Auto-Fix
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "if [[ \"$CLAUDE_FILE_PATH\" =~ \\.(ts|tsx|js|jsx)$ ]]; then npx eslint --fix \"$CLAUDE_FILE_PATH\" 2>/dev/null || true; fi"
}
]
}
]
}
}Recipe 4: Type-Check After TypeScript Edits
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "if [[ \"$CLAUDE_FILE_PATH\" =~ \\.tsx?$ ]]; then npx tsc --noEmit --pretty 2>&1 | head -20 || true; fi"
}
]
}
]
}
}Recipe 5: Run Ruff Linter on Python Files
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "if [[ \"$CLAUDE_FILE_PATH\" == *.py ]]; then ruff check --fix \"$CLAUDE_FILE_PATH\" 2>/dev/null && ruff format \"$CLAUDE_FILE_PATH\" 2>/dev/null; fi"
}
]
}
]
}
}Recipe 6: Validate JSON After Edits
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "if [[ \"$CLAUDE_FILE_PATH\" == *.json ]]; then python3 -c \"import json; json.load(open('$CLAUDE_FILE_PATH'))\" 2>&1 || echo 'WARNING: Invalid JSON in $CLAUDE_FILE_PATH' >&2; fi"
}
]
}
]
}
}---
Recipes: Security
Recipe 7: Protect Sensitive Files
Block modifications to files containing secrets or credentials.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "if echo \"$CLAUDE_TOOL_ARG_FILE_PATH\" | grep -qiE '(\\.env$|\\.env\\.|credentials|secrets?|private.key|id_rsa)'; then echo 'BLOCKED: Cannot modify sensitive files' >&2; exit 1; fi"
}
]
}
]
}
}Recipe 8: Block Dangerous Bash Commands
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "if echo \"$CLAUDE_TOOL_ARG_COMMAND\" | grep -qE '(rm -rf /|rm -rf \\*|DROP TABLE|DROP DATABASE|--force push|git push.*(--force|-f)|> /dev/sd|mkfs\\.|dd if=)'; then echo 'BLOCKED: Potentially destructive command' >&2; exit 1; fi"
}
]
}
]
}
}Recipe 9: Block Production Environment Access
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "if echo \"$CLAUDE_TOOL_ARG_COMMAND\" | grep -qiE '(production|prod\\.|prod-|PROD_|--prod)'; then echo 'BLOCKED: Production commands not allowed in development' >&2; exit 1; fi"
}
]
}
]
}
}Recipe 10: Prevent Editing Generated/Vendored Files
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "if echo \"$CLAUDE_TOOL_ARG_FILE_PATH\" | grep -qE '(generated|dist/|build/|\\.min\\.|vendor/|node_modules/)'; then echo 'BLOCKED: Cannot edit generated or vendored files' >&2; exit 1; fi"
}
]
}
]
}
}Recipe 11: AI-Powered Security Review (Prompt Hook)
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "prompt",
"prompt": "Check if this file change introduces security vulnerabilities (injection, XSS, hardcoded secrets, insecure crypto). If yes, output a brief WARNING with the issue. If clean, output nothing.",
"model": "haiku"
}
]
}
]
}
}---
Recipes: Workflow
Recipe 12: Enforce Conventional Commits
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "if echo \"$CLAUDE_TOOL_ARG_COMMAND\" | grep -q 'git commit'; then if ! echo \"$CLAUDE_TOOL_ARG_COMMAND\" | grep -qE '(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\\(|:)'; then echo 'BLOCKED: Commit must use conventional commits (feat|fix|docs|...)' >&2; exit 1; fi; fi"
}
]
}
]
}
}Recipe 13: Auto-Stage Written Files
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "git add \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
}
]
}
]
}
}Recipe 14: Remind About Barrel Exports
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "if [[ \"$CLAUDE_FILE_PATH\" =~ \\.(ts|tsx)$ ]] && [[ ! \"$CLAUDE_FILE_PATH\" =~ index\\.ts ]]; then DIR=$(dirname \"$CLAUDE_FILE_PATH\"); if [ -f \"$DIR/index.ts\" ]; then echo \"Note: Consider updating $DIR/index.ts with the new export\" >&2; fi; fi"
}
]
}
]
}
}Recipe 15: Run Related Tests After Edits
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "if [[ \"$CLAUDE_FILE_PATH\" =~ \\.py$ ]] && [[ ! \"$CLAUDE_FILE_PATH\" =~ test_ ]]; then TESTFILE=$(echo \"$CLAUDE_FILE_PATH\" | sed 's/\\(.*\\)\\/\\(.*\\)\\.py/\\1\\/test_\\2.py/'); if [ -f \"$TESTFILE\" ]; then python3 -m pytest \"$TESTFILE\" -x -q 2>&1 | tail -5; fi; fi"
}
]
}
]
}
}Recipe 16: Restrict Bash to Read-Only Commands
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "if echo \"$CLAUDE_TOOL_ARG_COMMAND\" | grep -qE '^(rm |mv |cp |chmod|chown|kill|pkill|mkdir|touch|tee |>|>>)'; then echo 'BLOCKED: Only read commands allowed in this mode' >&2; exit 1; fi"
}
]
}
]
}
}---
Recipes: Notifications
Recipe 17: macOS Desktop Notification on Task Complete
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code finished\" with title \"Claude Code\" sound name \"Glass\"' 2>/dev/null || true"
}
]
}
]
}
}Recipe 18: Linux Desktop Notification
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "notify-send --app-name='Claude Code' 'Task Complete' 'Claude Code finished its response' 2>/dev/null || true"
}
]
}
]
}
}Recipe 19: Play Sound on Completion
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "afplay /System/Library/Sounds/Glass.aiff 2>/dev/null || paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null || true"
}
]
}
]
}
}---
Recipes: Context Management
Recipe 20: Inject Context on Session Start
Re-inject critical context after compaction or at session start.
{
"hooks": {
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "echo \"Project: MyApp v2.1 | Stack: Next.js 14, PostgreSQL, Redis | Testing: Jest + Playwright | Deploy: Vercel + AWS\""
}
]
}
]
}
}Recipe 21: Load Session Notes on Start
{
"hooks": {
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "if [ -f .claude/session-notes.md ]; then echo '--- Session Notes ---'; cat .claude/session-notes.md; echo '---'; fi"
}
]
}
]
}
}Recipe 22: Inject Git Branch Context
{
"hooks": {
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "BRANCH=$(git branch --show-current 2>/dev/null); if [ -n \"$BRANCH\" ]; then echo \"Current branch: $BRANCH\"; BEHIND=$(git rev-list --count HEAD..origin/$BRANCH 2>/dev/null || echo 0); if [ \"$BEHIND\" -gt 0 ]; then echo \"WARNING: Branch is $BEHIND commits behind remote\"; fi; fi"
}
]
}
]
}
}---
Recipes: Logging and Audit
Recipe 23: Log All Tool Usage
{
"hooks": {
"PostToolUse": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "echo \"$(date -Iseconds) | $CLAUDE_TOOL_NAME | ${CLAUDE_FILE_PATH:-${CLAUDE_TOOL_ARG_COMMAND:-n/a}}\" >> .claude/tool-usage.log 2>/dev/null || true"
}
]
}
]
}
}Recipe 24: Log Session Duration
{
"hooks": {
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "echo \"SESSION_START $(date -Iseconds) $CLAUDE_SESSION_ID\" >> .claude/sessions.log 2>/dev/null || true"
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "echo \"SESSION_STOP $(date -Iseconds) $CLAUDE_SESSION_ID\" >> .claude/sessions.log 2>/dev/null || true"
}
]
}
]
}
}---
Recipes: Advanced Patterns
Recipe 25: Combine Multiple Hooks on One Event
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "if [[ \"$CLAUDE_FILE_PATH\" == *.py ]]; then python3 -m black --quiet \"$CLAUDE_FILE_PATH\" 2>/dev/null; fi"
},
{
"type": "command",
"command": "if [[ \"$CLAUDE_FILE_PATH\" == *.py ]]; then ruff check --fix \"$CLAUDE_FILE_PATH\" 2>/dev/null; fi"
},
{
"type": "command",
"command": "echo \"$(date -Iseconds) | FORMAT | $CLAUDE_FILE_PATH\" >> .claude/tool-usage.log 2>/dev/null || true"
}
]
}
]
}
}Recipe 26: Conditional Hook with External Script
Create a reusable hook script for complex logic:
`.claude/hooks/validate-edit.sh`:
#!/bin/bash
# Validate file edits with multiple checks
FILE="$CLAUDE_TOOL_ARG_FILE_PATH"
# Check 1: Not a lock file
if [[ "$FILE" =~ (lock|\.lock)$ ]]; then
echo "BLOCKED: Cannot edit lock files" >&2
exit 1
fi
# Check 2: Not in node_modules
if [[ "$FILE" =~ node_modules/ ]]; then
echo "BLOCKED: Cannot edit node_modules" >&2
exit 1
fi
# Check 3: File size limit (prevent editing huge files)
if [ -f "$FILE" ]; then
SIZE=$(wc -c < "$FILE")
if [ "$SIZE" -gt 100000 ]; then
echo "WARNING: File is $(( SIZE / 1024 ))KB - consider editing specific sections" >&2
fi
fi
exit 0`.claude/settings.json`:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/validate-edit.sh"
}
]
}
]
}
}---
Best Practices
1. Always fail safe -- Use 2>/dev/null || true for non-critical hooks. A failing PostToolUse hook should not break the workflow.
2. Keep hooks fast -- Command hooks should complete in under 2 seconds. Slow hooks degrade the interactive experience.
3. Use exit codes correctly -- Exit 1 in PreToolUse blocks the action. Exit 0 (or any code) in PostToolUse is informational only.
4. Write messages to stderr -- Hook output on stderr is shown to the user. Output on stdout may be captured differently.
5. Test in local settings first -- Use .claude/settings.local.json for personal hooks. Only commit to .claude/settings.json when proven stable.
6. Use prompt hooks sparingly -- They add latency (1-3 seconds) and cost money. Reserve them for security-critical checks.
7. Log for debugging -- Add a logging hook during development and remove it when everything works.
8. Document your hooks -- Add a comment (as a separate echo to /dev/null) or maintain a README explaining what each hook does.
9. Keep matchers specific -- "Edit|Write" is better than "" (which matches everything). Specific matchers reduce unnecessary hook executions.
10. Combine related hooks -- Use the hooks array to run multiple commands on the same event/matcher rather than creating separate entries.
---
Troubleshooting
Hook Not Firing
- Verify the event name is spelled correctly (case-sensitive)
- Check that the matcher regex matches the tool name
- Ensure the settings file is valid JSON (
python3 -c "import json; json.load(open('.claude/settings.json'))") - Check that the command exists and is executable
Hook Blocking Unexpectedly
- Add
echodebugging:echo "DEBUG: PATH=$CLAUDE_TOOL_ARG_FILE_PATH" >&2 - Check that your grep patterns are not too broad
- Verify that exit codes are correct (exit 0 = allow, exit 1 = block)
Hook Running Too Slowly
- Profile the command:
time your-command - Use
|| trueto skip slow operations that fail - Move complex logic to a compiled script
- Consider if the hook can run asynchronously (PostToolUse only)
Hook Errors in Logs
- Check stderr output: hooks log errors to the Claude Code console
- Verify file paths are properly quoted (spaces in paths)
- Ensure external tools (prettier, eslint, black) are installed
---
Last Updated: February 2026
Skill Authoring Guide
Comprehensive reference for writing effective Claude Code skills -- from YAML frontmatter to progressive disclosure, tool restrictions, and context optimization.
---
Table of Contents
- Skill Package Structure
- YAML Frontmatter
- Description Optimization
- SKILL.md Anatomy
- Progressive Disclosure
- Python Tool Standards
- Reference Document Standards
- Context Modes and Loading
- Model Selection Guidance
- Testing Your Skill
---
Skill Package Structure
Every skill follows this directory layout:
skill-name/
├── SKILL.md # Master documentation (always the entry point)
├── scripts/ # Python CLI tools
│ ├── tool_one.py
│ └── tool_two.py
├── references/ # Deep-dive knowledge bases
│ ├── guide_one.md
│ └── guide_two.md
└── assets/ # User-facing templates and examples
├── template.md
└── checklist.mdDesign rules:
1. Self-contained -- Every skill must work independently. No cross-skill imports. 2. SKILL.md is the interface -- Claude reads this first and decides what to use. 3. Scripts are tools, not libraries -- Each script is a CLI tool, not a shared module. 4. References are on-demand -- Only loaded when Claude needs deep knowledge. 5. Assets are for users -- Templates the user copies and customizes.
---
YAML Frontmatter
The frontmatter at the top of SKILL.md determines how Claude discovers and activates the skill.
Required Fields
---
name: skill-name
description: >-
This skill should be used when the user asks to "do X", "analyze Y",
"generate Z", or "optimize W". Use for domain expertise, workflow
automation, and analysis.
---`name` -- Kebab-case identifier matching the directory name. Used for referencing and logging.
`description` -- The most important field. This is what Claude reads to decide whether to activate the skill. Write it in third person and load it with trigger phrases.
Optional Fields
---
name: skill-name
description: >-
Description text...
license: MIT
metadata:
version: 1.0.0
category: engineering
domain: development-tools
author: Team Name
tags: [cli, automation, analysis]
allowed-tools:
- Read
- Glob
- Grep
- Bash(python*)
---`license` -- License type (MIT, Apache-2.0, proprietary, etc.).
`metadata` -- Structured metadata for categorization and versioning.
version-- Semantic version (major.minor.patch)category-- Broad category (engineering, marketing, product, etc.)domain-- Specific domain (development-tools, seo, compliance, etc.)author-- Creator or team nametags-- Array of discovery keywords
`allowed-tools` -- Restricts which tools the skill can use. Useful for creating read-only analysis skills or skills that should never write files.
---
Description Optimization
The description field is the skill's discovery mechanism. Claude scans descriptions to match user requests to relevant skills.
Writing Effective Descriptions
Pattern: Third person, trigger phrases in quotes, use cases at the end.
# GOOD -- Packed with trigger phrases, specific use cases
description: >-
This skill should be used when the user asks to "analyze API performance",
"benchmark endpoints", "profile response times", "identify bottlenecks",
or "optimize throughput". Use for REST API performance analysis, load
testing configuration, latency profiling, and capacity planning.
# BAD -- Vague, no trigger phrases
description: >-
A skill for working with APIs and performance.
# BAD -- First person, narrative style
description: >-
I help users analyze their API performance and find issues.Trigger Phrase Rules
1. Use verb phrases users actually say: "analyze X", "create Y", "optimize Z" 2. Include 5-10 trigger phrases minimum 3. Cover synonyms: "benchmark" and "profile" and "measure" 4. Include the domain: "REST API", "database queries", "frontend rendering" 5. End with a summary of use cases
Testing Discovery
Ask Claude: "I need to optimize my API response times." If your skill is not activated, add more trigger phrases related to that phrasing.
---
SKILL.md Anatomy
A well-structured SKILL.md follows this order:
1. YAML Frontmatter
See above.
2. Title and One-Line Summary
# API Performance Analyzer
Identify bottlenecks, benchmark endpoints, and optimize API throughput.3. Keywords
A comma-separated list of discovery terms that supplements the description.
## Keywords
api, performance, latency, throughput, benchmarking, profiling, bottleneck,
response-time, load-testing, capacity-planning4. Table of Contents
Link to all major sections for quick navigation.
5. Quick Start
Three to five commands that demonstrate the skill immediately. A user should be able to copy-paste these and see results.
6. Tools Overview
Each script with usage examples, parameter tables, and sample output.
7. Workflows
Step-by-step sequences that combine tools, knowledge, and judgment. Workflows are the most valuable part of a skill because they encode expertise.
8. Reference Documentation
Table linking to files in references/.
9. Quick Reference
Tables, cheat sheets, and at-a-glance summaries for common operations.
---
Progressive Disclosure
Structure skills so Claude loads only what it needs for the current task.
Layer 1: SKILL.md (Always Loaded When Active)
Contains the skill overview, tool descriptions, and workflow summaries. Keep under 400 lines if possible.
Layer 2: Reference Documents (Loaded on Demand)
Deep knowledge bases that Claude reads when it needs specific expertise. These are NOT loaded automatically.
## Reference Documentation
| Document | Path | When to Use |
|----------|------|-------------|
| API Patterns | references/api-patterns.md | Designing new API endpoints |
| Error Handling | references/error-handling.md | Implementing error responses |
| Caching Guide | references/caching-guide.md | Optimizing response times |Layer 3: Assets (User-Facing)
Templates and examples the user copies. Claude references these when helping users fill them out.
Loading Control
Use clear indicators in SKILL.md to tell Claude when to load reference docs:
> For detailed caching strategies, see [references/caching-guide.md](references/caching-guide.md)This is better than including all caching knowledge directly in SKILL.md.
---
Python Tool Standards
Every Python script in a skill must follow these standards:
Structure Template
#!/usr/bin/env python3
"""
Tool Name - One line description
Detailed description of what the tool does, what input it expects,
and what output it produces.
Usage:
python tool_name.py input_arg
python tool_name.py input_arg --option value
python tool_name.py input_arg --json
"""
import argparse
import json
import sys
from pathlib import Path
def main():
parser = argparse.ArgumentParser(
description="Tool description",
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument("input", help="Input to process")
parser.add_argument("--json", action="store_true", help="Output in JSON format")
args = parser.parse_args()
result = {"key": "value"}
if args.json:
print(json.dumps(result, indent=2))
else:
print_human_readable(result)
if __name__ == "__main__":
main()Rules
1. Standard library only -- No pip dependencies. Scripts must run anywhere. 2. argparse with --help -- Every script must have useful help text. 3. --json flag -- Support machine-readable JSON output. 4. Module docstring -- Include usage examples in the docstring. 5. Error handling -- Catch exceptions, print useful messages, exit with non-zero. 6. No LLM calls -- Scripts must be deterministic and fast. 7. No network calls -- Unless the skill explicitly requires it (and documents it). 8. Executable -- Set chmod +x and include the shebang line.
Output Conventions
- Human-readable: Clear labels, aligned columns, section headers
- JSON: Flat structure preferred, always include a
successboolean - Errors: Print to stderr, exit code 1
- Progress: Use stderr for progress messages so stdout stays clean for piping
---
Reference Document Standards
Structure
# Document Title
## Overview
One paragraph context.
## Section 1
Content with examples.
## Section 2
Content with examples.
## Quick Reference
Tables and cheat sheets.
---
**Last Updated:** Month YearRules
1. Single topic per file -- "Caching Strategies" not "Caching and Performance" 2. Actionable content -- Every section should tell the reader what to DO 3. Code examples -- Show, don't just tell 4. Tables for comparisons -- Use tables when comparing options 5. Under 500 lines -- Split longer guides into multiple files 6. No redundancy with SKILL.md -- Reference docs go deeper, not wider
---
Context Modes and Loading
Understanding how Claude Code loads files helps you structure skills efficiently.
Fork vs Main Context Modes
The context field in YAML frontmatter controls how the skill's conversation context relates to the main conversation.
Fork Mode (context: fork):
- Creates an isolated context branch for the skill
- Skill runs in its own conversation thread
- Does not pollute the main conversation history with file reads
- Results are summarized back to the main thread
- Best for: long-running analyses, tasks that read many files, heavy output
Main Mode (context: main, default):
- Skill runs in the current conversation context
- Has access to full conversation history
- Results stay in the main thread
- Best for: quick operations, tasks that build on recent conversation
| Scenario | Mode | Reason |
|---|---|---|
| Code review of 20 files | fork | Avoids flooding main context with file reads |
| Quick config generation | main | Needs to reference recent conversation |
| Test suite execution | fork | Output-heavy, isolate the noise |
| Editing a file discussed in chat | main | Needs conversation context |
Automatic Loading
These files load for EVERY conversation:
~/.claude/CLAUDE.md(user global)<project>/CLAUDE.md(project root)<project>/.claude/CLAUDE.md(project config)
On-Demand Loading
These load when Claude accesses files in the directory:
<project>/subdir/CLAUDE.md(subdirectory-specific)
Skill Loading
SKILL.md files load when:
- The user's request matches the skill description
- Claude determines the skill is relevant
- The user explicitly invokes the skill
Reference Loading
Reference files load when:
- Claude reads them with the Read tool
- They are referenced in a workflow Claude is executing
- The user asks Claude to consult them
Optimization Strategy
1. Put project-wide rules in root CLAUDE.md (auto-loaded, keep small) 2. Put domain rules in subdirectory CLAUDE.md files (on-demand) 3. Put workflow knowledge in SKILL.md (skill-triggered) 4. Put deep expertise in references/ (explicit read)
---
String Substitutions
Skills support special string substitutions that are replaced at invocation time. These allow skills to be parameterized and dynamic.
Available Substitutions
| Variable | Description | Example Value |
|---|---|---|
$ARGUMENTS | Full argument string passed to the skill | "review the auth module" |
$1 | First positional argument (space-separated) | "review" |
$2 | Second positional argument | "the" |
$N | Nth positional argument | (any word by position) |
$PROJECT_DIR | Absolute path to the project root | /home/user/my-project |
$FILE | Currently active file path (if applicable) | src/auth/login.ts |
Using Substitutions in SKILL.md
## Quick Start
Analyzing: $ARGUMENTS
\```bash
python scripts/analyzer.py $PROJECT_DIR $1
\```When the user invokes the skill with arguments, the variables are replaced before the skill content is processed.
Using Substitutions in Frontmatter
custom-instructions: |
Analyze the following request: $ARGUMENTS
Focus on the project at: $PROJECT_DIR
Currently active file: $FILEPractical Examples
Skill invoked with: /skill my-skill review src/auth/
| Variable | Resolves To |
|---|---|
$ARGUMENTS | review src/auth/ |
$1 | review |
$2 | src/auth/ |
$PROJECT_DIR | /home/user/my-project |
Best Practices for Substitutions
1. Always provide defaults -- Do not assume $ARGUMENTS is non-empty. 2. Document expected arguments -- In the Quick Start section, show what arguments the skill expects. 3. Use `$PROJECT_DIR` for scripts -- Ensures paths resolve correctly regardless of where the skill is invoked from. 4. Avoid `$FILE` in mandatory flows -- It may be empty if no file is active.
---
Model Selection Guidance
When creating agents or suggesting configurations, choose models based on the task:
| Task Type | Recommended Model | Rationale |
|---|---|---|
| Complex reasoning, architecture | claude-opus-4-20250514 | Highest capability |
| General coding, review | claude-sonnet-4-20250514 | Best speed/quality balance |
| Simple tasks, formatting | claude-haiku-3-5-20241022 | Fastest, cheapest |
| Subagent tasks | claude-sonnet-4-20250514 | Good balance for delegated work |
For agent definitions that specify a model:
# Complex analysis agent
model: claude-opus-4-20250514
# General-purpose coding agent
model: claude-sonnet-4-20250514
# Quick formatting/linting agent
model: claude-haiku-3-5-20241022---
Testing Your Skill
Functional Testing
1. Run every script with --help and verify output 2. Run every script with sample input and verify results 3. Run every script with --json and verify valid JSON 4. Run every script with invalid input and verify error handling
Integration Testing
1. Start a Claude Code session in a test project 2. Ask a question that should trigger your skill 3. Verify Claude finds and uses the correct tool 4. Verify the workflow produces expected results
Discovery Testing
1. Ask Claude variations of questions your skill should handle 2. Note which phrasings do NOT trigger the skill 3. Add those phrasings as trigger phrases in the description
Quality Checklist
- [ ] SKILL.md has valid YAML frontmatter
- [ ] Description contains 5+ trigger phrases
- [ ] Quick Start has 3+ copy-pasteable commands
- [ ] All scripts run with
--help - [ ] All scripts support
--json - [ ] All scripts handle errors gracefully
- [ ] Reference docs are single-topic and under 500 lines
- [ ] No dependencies beyond Python standard library
- [ ] No cross-skill imports or dependencies
---
Last Updated: February 2026
Subagent Patterns
Comprehensive guide to creating and using Claude Code subagents for parallel work, specialized review, automated workflows, and task delegation.
---
Table of Contents
- What Are Subagents
- Built-in Agent Support
- Custom Agent Creation
- Agent File Anatomy
- Tool Access Patterns
- Delegation Patterns
- Memory and State
- Isolation Modes
- Hooks Integration
- Production Recipes
---
What Are Subagents
Subagents are specialized Claude Code instances that run with their own system prompts, tool restrictions, and behavioral instructions. They operate in isolation from the main conversation but can return results.
Key properties:
- Run with a separate system prompt (custom-instructions)
- Can be restricted to specific tools (allowed-tools)
- Execute in the same project directory
- Return their output to the calling conversation
- Do not share conversation history with the main session
When to use subagents:
- Specialized review tasks (security, performance, accessibility)
- Parallel research across multiple files
- Automated generation with strict constraints
- Tasks that benefit from a fresh context window
---
Built-in Agent Support
Claude Code ships with several built-in agents that are always available without custom configuration.
Explore Agent
Purpose: Read-only codebase exploration and analysis.
Capabilities:
- Read files, search with Glob and Grep
- Navigate directory structures
- Cannot modify any files
When to use:
- Understanding unfamiliar codebases
- Finding where a feature is implemented
- Tracing data flow across files
- Answering "where is X defined" questions
Invocation:
/agents/explore How is authentication implemented in this project?Plan Agent
Purpose: Generate implementation plans without making changes.
Capabilities:
- Full read access to the codebase
- Produces structured plans with file lists and step-by-step instructions
- Cannot modify any files
When to use:
- Before starting a large refactor
- Planning a new feature across multiple files
- Estimating scope of a change
Invocation:
/agents/plan Plan the migration from REST to GraphQL for the user serviceGeneral-Purpose Subagent
Purpose: A delegated Claude Code instance with full capabilities.
Capabilities:
- All tools available (same as main session)
- Runs in an isolated context
- Results summarized back to parent
When to use:
- Parallel task execution
- Tasks that would flood the main context
- Work that benefits from a clean context slate
Custom Agents Directory
Custom agents live in .claude/agents/:
.claude/
└── agents/
├── security-reviewer.md
├── test-writer.md
├── doc-generator.md
└── migration-helper.mdInvocation:
/agents/security-reviewer Review the authentication module for vulnerabilities
/agents/test-writer Write unit tests for src/services/payment.ts
/agents/doc-generator Generate API documentation for the REST endpoints---
Custom Agent Creation
Step 1: Define the Agent's Purpose
Every agent needs a narrow, well-defined scope. Good agents do one thing well.
Good scopes:
- "Reviews code changes for security vulnerabilities"
- "Writes comprehensive test suites for TypeScript modules"
- "Generates OpenAPI documentation from route handlers"
- "Analyzes database queries for N+1 problems"
Bad scopes:
- "Helps with coding" (too broad)
- "Does everything" (defeats the purpose of specialization)
- "Reviews and fixes code" (conflates review and modification)
Step 2: Create the Agent File
Agent files use YAML frontmatter followed by optional markdown content.
---
name: security-reviewer
description: Reviews code changes for security vulnerabilities and compliance issues
model: claude-sonnet-4-20250514
allowed-tools:
- Read
- Glob
- Grep
- Bash(git diff*)
- Bash(git log*)
custom-instructions: |
You are a security-focused code reviewer. For every change you review:
1. Check for hardcoded secrets, credentials, API keys, or tokens
2. Identify injection vulnerabilities (SQL, XSS, command injection)
3. Verify authentication and authorization patterns
4. Flag insecure dependencies or deprecated crypto functions
5. Check for information disclosure in error messages
Output Format:
## Security Review Summary
- **Risk Level:** HIGH / MEDIUM / LOW / CLEAN
- **Issues Found:** N
## Issues
For each issue:
- File and line number
- Severity (Critical / High / Medium / Low / Info)
- Description
- Recommended fix
## Recommendations
Prioritized list of actions.
---Step 3: Test the Agent
/agents/security-reviewer Review the changes in the last commitVerify that:
- The agent activates correctly
- Tool restrictions are enforced
- Output follows the specified format
- It stays within its defined scope
---
Agent File Anatomy
Required Fields
name: agent-name # Kebab-case identifier
description: What it does # Brief description for discoveryOptional Fields
model: claude-sonnet-4-20250514 # Model override (default: session model)
allowed-tools: # Tool whitelist (default: all tools)
- Read
- Glob
custom-instructions: | # System prompt for the agent
Your behavioral instructions here.Field Details
`name` -- Used for invocation: /agents/<name>. Must be unique within the agents directory.
`description` -- Helps Claude decide when to suggest this agent. Also shown when listing agents with /agents.
`model` -- Override the model for this agent. Use cheaper/faster models for simple tasks:
claude-opus-4-20250514-- Complex analysis, architecture reviewclaude-sonnet-4-20250514-- General coding, standard reviewclaude-haiku-3-5-20241022-- Simple formatting, quick checks
`allowed-tools` -- Whitelist of tools the agent can use. Supports glob patterns for Bash commands:
Read-- Read filesGlob-- Find filesGrep-- Search contentEdit-- Modify filesWrite-- Create filesBash(pattern*)-- Run matching bash commandsWebFetch-- Fetch URLsWebSearch-- Search the web
`custom-instructions` -- The system prompt. This is where you define the agent's personality, workflow, output format, and constraints.
---
Tool Access Patterns
Read-Only Agent (Safe for Review)
allowed-tools:
- Read
- Glob
- GrepBest for: Code review, security audit, documentation analysis, architecture review.
Read + Specific Commands
allowed-tools:
- Read
- Glob
- Grep
- Bash(git diff*)
- Bash(git log*)
- Bash(npm test*)
- Bash(npm run lint*)Best for: Review tasks that need git context or test results.
Write-Capable Agent
allowed-tools:
- Read
- Write
- Edit
- Glob
- Grep
- Bash(mkdir*)Best for: Code generation, test writing, documentation generation.
Full Access Agent
# Omit allowed-tools entirely for full access
# Or explicitly:
allowed-tools:
- Read
- Write
- Edit
- Glob
- Grep
- Bash
- WebFetch
- WebSearchBest for: Complex multi-step tasks that need all capabilities.
Restricted Bash Patterns
allowed-tools:
- Bash(python scripts/*) # Only run project scripts
- Bash(npm run *) # Only run npm scripts
- Bash(docker compose *) # Only docker commands
- Bash(git status) # Specific git commands (no glob)
- Bash(git diff*) # Git diff with any arguments---
Delegation Patterns
Pattern 1: Review Then Act
Use a read-only agent to review, then act on the findings yourself.
# Step 1: Agent reviews
/agents/security-reviewer Review all files changed in the last 5 commits
# Step 2: Human or main session acts on findings
Fix the SQL injection vulnerability identified in src/db/queries.ts line 45Pattern 2: Generate Then Review
Use a write agent to generate code, then a review agent to check it.
# Step 1: Generate
/agents/test-writer Write comprehensive tests for src/services/auth.ts
# Step 2: Review
/agents/security-reviewer Review the newly generated test file for any security issuesPattern 3: Parallel Research
Use multiple agents to research different aspects simultaneously.
# Research architecture patterns
/agents/architecture-analyst Analyze the data flow in the payment processing module
# Research performance characteristics
/agents/performance-profiler Identify potential bottlenecks in the checkout flowPattern 4: Specialized Transformation
Use agents for specific, repeatable transformations.
# Convert JavaScript to TypeScript
/agents/ts-migrator Convert src/utils/helpers.js to TypeScript with strict mode
# Generate API docs from code
/agents/doc-generator Create OpenAPI spec from src/routes/*.tsPattern 5: Guardrail Agent
Use a pre-check agent before making changes.
# Check if change is safe
/agents/impact-analyzer What files and tests would be affected by renaming the User model to Account?
# Then proceed with the change
Rename the User model to Account across the entire codebase---
Memory and State
Agent Memory Scope
Subagents do NOT have access to:
- The main conversation history
- Previous agent invocation results
- Other agents' outputs
Subagents DO have access to:
- All project files (subject to allowed-tools)
- CLAUDE.md files (loaded automatically)
- The current git state
Persisting Agent Output
Agent output appears in the main conversation. To preserve findings:
1. Ask the agent to write to a file: Include in custom-instructions: "Write your findings to a file."
2. Capture in conversation: The agent's output is visible in the main session's context.
3. Use a handoff document:
/agents/analyzer Analyze the codebase and write a summary to .claude/analysis.mdCross-Agent Communication
Agents cannot communicate directly. Use files as the communication channel:
# Agent A writes findings
/agents/security-reviewer Review code and write findings to /tmp/security-review.md
# Agent B reads findings
/agents/fix-planner Read /tmp/security-review.md and create a prioritized fix plan---
Isolation Modes
Default Isolation
Agents run in the same project directory but with a fresh conversation context. They share the filesystem but not conversation state.
Worktree Isolation
For agents that modify files, consider using git worktrees for true isolation:
# Create isolated worktree
git worktree add .claude/worktrees/agent-work agent-branch
# Agent works in the worktree (configure in custom-instructions)Permission Isolation
Use allowed-tools to create hard boundaries:
# Agent cannot modify anything
allowed-tools:
- Read
- Glob
- Grep
# Agent can only modify test files
allowed-tools:
- Read
- Glob
- Grep
- Edit # But custom-instructions say: "Only edit files in __tests__/"
- Write # But custom-instructions say: "Only write to __tests__/"Note: allowed-tools enforces tool-level restrictions. For path-level restrictions, use custom-instructions (advisory, not enforced by the system).
---
Hooks Integration
Hooks can enhance agent workflows by running scripts before or after tool use.
Pre-Agent Validation Hook
Validate that an agent is appropriate for the current context:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Agent",
"command": "/path/to/validate-agent-context.sh"
}
]
}
}Post-Agent Logging Hook
Log all agent invocations for audit:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Agent",
"command": "echo \"$(date) Agent invoked: $CLAUDE_TOOL_INPUT\" >> .claude/agent-log.txt"
}
]
}
}Auto-Format After Agent Writes
Ensure agent-generated code matches project style:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"command": "prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
}
]
}
}---
Production Recipes
Recipe 1: Security Review Agent
---
name: security-reviewer
description: Reviews code for security vulnerabilities, secrets, and compliance issues
model: claude-sonnet-4-20250514
allowed-tools:
- Read
- Glob
- Grep
- Bash(git diff*)
- Bash(git log*)
- Bash(git show*)
custom-instructions: |
You are a senior security engineer performing code review.
Review Checklist:
1. Hardcoded secrets (API keys, passwords, tokens, connection strings)
2. Injection vulnerabilities (SQL, XSS, command, LDAP, template)
3. Authentication flaws (broken auth, missing checks, weak tokens)
4. Authorization gaps (IDOR, privilege escalation, missing RBAC)
5. Cryptographic issues (weak algorithms, missing encryption, bad RNG)
6. Information disclosure (verbose errors, stack traces, debug endpoints)
7. Dependency vulnerabilities (known CVEs, outdated packages)
Output a structured markdown report with severity levels.
Always end with a risk score: CRITICAL / HIGH / MEDIUM / LOW / CLEAN.
---Recipe 2: Test Writer Agent
---
name: test-writer
description: Generates comprehensive test suites with edge cases and mocking
model: claude-sonnet-4-20250514
allowed-tools:
- Read
- Write
- Glob
- Grep
- Bash(npm test*)
- Bash(npx jest*)
custom-instructions: |
You write comprehensive test suites. For every module you test:
1. Read the source code thoroughly
2. Identify all public functions and methods
3. Write tests covering:
- Happy path for each function
- Edge cases (null, empty, boundary values)
- Error cases (invalid input, network failures)
- Integration points (mocked external dependencies)
4. Use the project's existing test framework and patterns
5. Run the tests to verify they pass
Naming: describe("ModuleName", () => { it("should verb when condition", ...) })
Target: 90%+ line coverage for the tested module.
---Recipe 3: Documentation Generator
---
name: doc-generator
description: Generates API documentation, code comments, and README files
model: claude-sonnet-4-20250514
allowed-tools:
- Read
- Write
- Glob
- Grep
custom-instructions: |
You generate clear, accurate documentation from source code.
Documentation Types:
- API docs: Extract routes, parameters, response shapes from code
- Code comments: Add JSDoc/docstrings to undocumented functions
- README: Generate project overview from codebase analysis
Rules:
- Never invent features that don't exist in the code
- Include realistic examples based on actual code paths
- Use the project's existing documentation style
- Mark any assumptions with [ASSUMPTION] tag
---Recipe 4: Database Migration Agent
---
name: migration-helper
description: Generates database migration scripts and validates schema changes
model: claude-sonnet-4-20250514
allowed-tools:
- Read
- Write
- Glob
- Grep
- Bash(npx prisma*)
- Bash(npm run migrate*)
custom-instructions: |
You create safe database migration scripts.
Safety Rules:
1. NEVER drop columns or tables without explicit user confirmation
2. Always create reversible migrations (up AND down)
3. Add NOT NULL constraints in two steps (add nullable, backfill, alter)
4. Create indexes CONCURRENTLY when possible
5. Estimate data migration time for large tables
Output: Migration file + summary of changes + rollback plan.
---Recipe 5: Performance Profiler Agent
---
name: performance-profiler
description: Analyzes code for performance bottlenecks, N+1 queries, and memory leaks
model: claude-sonnet-4-20250514
allowed-tools:
- Read
- Glob
- Grep
- Bash(git log*)
custom-instructions: |
You are a performance engineering specialist.
Analysis Areas:
1. N+1 query patterns in ORM usage
2. Missing database indexes for common queries
3. Unbounded list operations (no pagination)
4. Memory leaks (event listeners, closures, caches without eviction)
5. Synchronous operations that should be async
6. Missing caching opportunities
7. Large payload responses without pagination
Severity Levels:
- P0: Will cause outage under load
- P1: Significant performance degradation
- P2: Noticeable slowdown
- P3: Optimization opportunity
Output a prioritized list with file:line references and fix suggestions.
------
When to Use Subagents vs Skills
| Criterion | Use a Skill | Use a Subagent |
|---|---|---|
| Needs isolated context | No | Yes |
| Needs restricted tools | No | Yes |
| Provides reusable knowledge | Yes | No |
| Has executable tools (scripts) | Yes | Optional |
| Defines a persona | No | Yes |
| Runs a focused, scoped task | Either | Yes |
| Bundles templates/references | Yes | No |
| Needs a different model | Either | Yes |
Rules of thumb:
1. Knowledge + tools + templates -> Make it a skill. 2. Focused task + persona + restrictions -> Make it an agent. 3. Reads many files, want clean context -> Agent in fork mode. 4. Quick question using conversation history -> Skill or inline prompt. 5. Repeatable specialized review -> Agent (security-reviewer, test-runner). 6. Domain expertise for multiple workflows -> Skill (covers broader scope).
---
Last Updated: February 2026
#!/usr/bin/env python3
"""
CLAUDE.md Optimizer - Analyze and optimize CLAUDE.md files
Produces actionable recommendations covering structure, token efficiency,
redundancy detection, and completeness. Helps keep CLAUDE.md files lean
and effective.
Usage:
python claudemd_optimizer.py path/to/CLAUDE.md
python claudemd_optimizer.py CLAUDE.md --token-limit 4000
python claudemd_optimizer.py CLAUDE.md --json
"""
import argparse
import json
import re
import sys
import textwrap
from collections import Counter
from pathlib import Path
from typing import Dict, List, Optional, Tuple
# Approximate characters per token for Claude models
CHARS_PER_TOKEN = 3.5
# Recommended sections for a CLAUDE.md file
RECOMMENDED_SECTIONS = {
"project purpose": {
"aliases": ["project purpose", "project overview", "about", "overview", "what is this"],
"importance": "critical",
"description": "One paragraph explaining what the project is and who it serves",
},
"architecture overview": {
"aliases": ["architecture", "structure", "directory structure", "repository structure", "project structure"],
"importance": "critical",
"description": "Directory layout, key patterns, data flow",
},
"development environment": {
"aliases": ["development environment", "development", "setup", "getting started", "quick start", "dev setup", "build", "environment"],
"importance": "critical",
"description": "Build commands, test commands, environment setup",
},
"key principles": {
"aliases": ["key principles", "principles", "guidelines", "rules", "conventions", "standards"],
"importance": "high",
"description": "3-7 non-obvious rules Claude must follow",
},
"anti-patterns": {
"aliases": ["anti-patterns", "anti patterns", "don't", "avoid", "pitfalls", "common mistakes"],
"importance": "high",
"description": "Things that look reasonable but are wrong in this project",
},
"git workflow": {
"aliases": ["git workflow", "git", "branching", "branch strategy", "commits", "version control"],
"importance": "medium",
"description": "Branch strategy, commit conventions, PR process",
},
"testing": {
"aliases": ["testing", "tests", "test", "test commands", "how to test"],
"importance": "medium",
"description": "How to run tests, testing conventions, coverage targets",
},
}
# Patterns that indicate redundant or generic content
GENERIC_PATTERNS = [
(r"write clean[,\s]+readable code", "Generic advice - Claude already writes clean code"),
(r"follow best practices", "Too vague - specify which practices"),
(r"use meaningful variable names", "Generic advice - already default behavior"),
(r"add comments where necessary", "Generic advice - specify commenting standards if non-obvious"),
(r"handle errors? (properly|gracefully|appropriately)", "Too vague - specify error handling patterns"),
(r"write unit tests", "Too vague without specifying framework, coverage target, or patterns"),
(r"keep (it|things|code) (simple|dry|clean)", "Generic advice - specify concrete constraints"),
(r"follow the (existing|current) (patterns?|conventions?|style)", "Good intent but vague - specify which patterns"),
(r"make sure to (test|validate|verify)", "Generic - specify what and how"),
(r"ensure (code )?quality", "Too vague - specify quality metrics or checks"),
]
# Patterns that suggest content could be more concise
VERBOSITY_PATTERNS = [
(r"it is important to note that", "Remove filler phrase"),
(r"please (make sure|ensure|remember) (to|that)", "Remove politeness filler"),
(r"you should (always|never)", "Simplify to direct instruction"),
(r"in order to", "Replace with 'to'"),
(r"at this point in time", "Replace with 'now' or remove"),
(r"due to the fact that", "Replace with 'because'"),
(r"it goes without saying", "If obvious, remove entirely"),
(r"as a matter of fact", "Remove filler"),
]
def estimate_tokens(text: str) -> int:
"""Estimate token count from text length."""
return int(len(text) / CHARS_PER_TOKEN)
def extract_sections(text: str) -> List[Dict]:
"""Extract markdown sections with their content."""
sections = []
lines = text.split("\n")
current_section = None
current_content = []
current_level = 0
for line in lines:
heading_match = re.match(r"^(#{1,6})\s+(.+)$", line)
if heading_match:
if current_section is not None:
content_text = "\n".join(current_content).strip()
sections.append({
"title": current_section,
"level": current_level,
"content": content_text,
"line_count": len([l for l in current_content if l.strip()]),
"token_estimate": estimate_tokens(content_text),
})
current_level = len(heading_match.group(1))
current_section = heading_match.group(2).strip()
current_content = []
else:
current_content.append(line)
# Don't forget the last section
if current_section is not None:
content_text = "\n".join(current_content).strip()
sections.append({
"title": current_section,
"level": current_level,
"content": content_text,
"line_count": len([l for l in current_content if l.strip()]),
"token_estimate": estimate_tokens(content_text),
})
return sections
def check_section_completeness(sections: List[Dict]) -> List[Dict]:
"""Check which recommended sections are present and which are missing."""
results = []
section_titles_lower = [s["title"].lower() for s in sections]
for section_name, info in RECOMMENDED_SECTIONS.items():
found = False
matched_title = None
for alias in info["aliases"]:
for title in section_titles_lower:
if alias in title or title in alias:
found = True
matched_title = title
break
if found:
break
results.append({
"section": section_name,
"importance": info["importance"],
"found": found,
"matched_as": matched_title,
"description": info["description"],
})
return results
def detect_redundancy(text: str) -> List[Dict]:
"""Detect redundant phrases and repeated instructions."""
issues = []
# Check for generic/redundant patterns
for pattern, message in GENERIC_PATTERNS:
matches = re.findall(pattern, text, re.IGNORECASE)
if matches:
issues.append({
"type": "generic_content",
"pattern": pattern,
"message": message,
"occurrences": len(matches),
})
# Check for verbosity patterns
for pattern, message in VERBOSITY_PATTERNS:
matches = re.findall(pattern, text, re.IGNORECASE)
if matches:
issues.append({
"type": "verbose_phrasing",
"pattern": pattern,
"message": message,
"occurrences": len(matches),
})
# Check for repeated sentences (exact duplicates)
sentences = re.split(r"[.!?]\s+", text)
sentences_clean = [s.strip().lower() for s in sentences if len(s.strip()) > 20]
sentence_counts = Counter(sentences_clean)
for sentence, count in sentence_counts.items():
if count > 1:
issues.append({
"type": "duplicate_sentence",
"message": f"Sentence appears {count} times: \"{sentence[:80]}...\"",
"occurrences": count,
})
# Check for repeated phrases (3+ word sequences appearing 3+ times)
words = text.lower().split()
trigrams = [" ".join(words[i : i + 3]) for i in range(len(words) - 2)]
trigram_counts = Counter(trigrams)
for trigram, count in trigram_counts.items():
if count >= 4 and len(trigram) > 10:
# Skip very common phrases
common_skip = {"in the the", "of the the", "and the the"}
if trigram not in common_skip:
issues.append({
"type": "repeated_phrase",
"message": f"Phrase \"{trigram}\" appears {count} times",
"occurrences": count,
})
return issues
def suggest_hierarchical_loading(text: str, sections: List[Dict], token_limit: int) -> List[str]:
"""Suggest sections that could be moved to child CLAUDE.md files."""
suggestions = []
total_tokens = estimate_tokens(text)
if total_tokens <= token_limit:
return suggestions
overage = total_tokens - token_limit
suggestions.append(
f"File is ~{total_tokens} tokens, {overage} tokens over the {token_limit} token target."
)
# Find the largest sections that could be moved
movable_sections = sorted(
[s for s in sections if s["level"] == 2 and s["token_estimate"] > 200],
key=lambda s: s["token_estimate"],
reverse=True,
)
tokens_to_move = 0
for section in movable_sections:
if tokens_to_move >= overage:
break
suggestions.append(
f"Move \"{section['title']}\" (~{section['token_estimate']} tokens) "
f"to a child CLAUDE.md or reference file"
)
tokens_to_move += section["token_estimate"]
return suggestions
def generate_recommendations(
text: str,
sections: List[Dict],
completeness: List[Dict],
redundancies: List[Dict],
hierarchical: List[str],
token_limit: int,
) -> List[Dict]:
"""Generate prioritized optimization recommendations."""
recommendations = []
total_tokens = estimate_tokens(text)
line_count = len(text.split("\n"))
# Check for missing critical sections
for check in completeness:
if not check["found"] and check["importance"] == "critical":
recommendations.append({
"priority": "high",
"category": "completeness",
"message": f"Add missing critical section: {check['section']} -- {check['description']}",
})
# Check for missing high-importance sections
for check in completeness:
if not check["found"] and check["importance"] == "high":
recommendations.append({
"priority": "medium",
"category": "completeness",
"message": f"Consider adding section: {check['section']} -- {check['description']}",
})
# Token budget recommendations
if total_tokens > token_limit:
recommendations.append({
"priority": "high",
"category": "token_budget",
"message": f"File exceeds target of {token_limit} tokens ({total_tokens} current). "
f"Use hierarchical loading to reduce.",
})
if total_tokens > token_limit * 2:
recommendations.append({
"priority": "high",
"category": "token_budget",
"message": "File is more than double the target size. Major restructuring recommended.",
})
# Redundancy recommendations
generic_count = sum(1 for r in redundancies if r["type"] == "generic_content")
if generic_count > 0:
recommendations.append({
"priority": "medium",
"category": "redundancy",
"message": f"Found {generic_count} generic/vague instructions. "
f"Replace with specific, actionable guidance or remove.",
})
verbose_count = sum(1 for r in redundancies if r["type"] == "verbose_phrasing")
if verbose_count > 0:
recommendations.append({
"priority": "low",
"category": "redundancy",
"message": f"Found {verbose_count} verbose phrases that can be simplified.",
})
duplicate_count = sum(1 for r in redundancies if r["type"] == "duplicate_sentence")
if duplicate_count > 0:
recommendations.append({
"priority": "medium",
"category": "redundancy",
"message": f"Found {duplicate_count} duplicate sentences. Remove repetition.",
})
# Structure recommendations
if line_count > 300:
recommendations.append({
"priority": "medium",
"category": "structure",
"message": f"File is {line_count} lines. Consider splitting into hierarchical CLAUDE.md files.",
})
h2_sections = [s for s in sections if s["level"] == 2]
if len(h2_sections) > 10:
recommendations.append({
"priority": "low",
"category": "structure",
"message": f"File has {len(h2_sections)} top-level sections. Consider consolidating.",
})
# Check for YAML frontmatter (not required for CLAUDE.md but good to flag)
if text.strip().startswith("---"):
# Check if frontmatter is well-formed
parts = text.split("---", 2)
if len(parts) >= 3:
frontmatter = parts[1].strip()
if not frontmatter:
recommendations.append({
"priority": "low",
"category": "structure",
"message": "YAML frontmatter is empty. Either add content or remove the delimiters.",
})
# Format recommendations
bullet_lines = sum(1 for line in text.split("\n") if line.strip().startswith(("- ", "* ", "1.")))
paragraph_lines = sum(
1
for line in text.split("\n")
if len(line.strip()) > 80 and not line.strip().startswith(("#", "-", "*", "|", "`", ">"))
)
if paragraph_lines > bullet_lines and paragraph_lines > 10:
recommendations.append({
"priority": "medium",
"category": "format",
"message": "Heavy use of paragraphs. Bullet points are ~30% more token-efficient "
"and easier for Claude to parse.",
})
# Add hierarchical loading suggestions
for suggestion in hierarchical:
recommendations.append({
"priority": "medium",
"category": "hierarchical_loading",
"message": suggestion,
})
return recommendations
def analyze_claudemd(file_path: str, token_limit: int = 6000) -> Dict:
"""Perform full analysis of a CLAUDE.md file."""
path = Path(file_path)
if not path.exists():
return {"success": False, "error": f"File not found: {file_path}"}
if not path.is_file():
return {"success": False, "error": f"Not a file: {file_path}"}
text = path.read_text(encoding="utf-8")
line_count = len(text.split("\n"))
non_empty_lines = len([l for l in text.split("\n") if l.strip()])
char_count = len(text)
token_estimate = estimate_tokens(text)
word_count = len(text.split())
sections = extract_sections(text)
completeness = check_section_completeness(sections)
redundancies = detect_redundancy(text)
hierarchical = suggest_hierarchical_loading(text, sections, token_limit)
recommendations = generate_recommendations(
text, sections, completeness, redundancies, hierarchical, token_limit
)
# Compute a simple score
score = 100
for rec in recommendations:
if rec["priority"] == "high":
score -= 15
elif rec["priority"] == "medium":
score -= 8
elif rec["priority"] == "low":
score -= 3
score = max(0, min(100, score))
return {
"success": True,
"file": str(path.resolve()),
"metrics": {
"line_count": line_count,
"non_empty_lines": non_empty_lines,
"character_count": char_count,
"word_count": word_count,
"token_estimate": token_estimate,
"token_limit": token_limit,
"within_budget": token_estimate <= token_limit,
"section_count": len(sections),
},
"sections": [
{"title": s["title"], "level": s["level"], "tokens": s["token_estimate"], "lines": s["line_count"]}
for s in sections
],
"completeness": completeness,
"redundancies": redundancies,
"recommendations": recommendations,
"score": score,
}
def print_human_readable(result: Dict) -> None:
"""Print analysis results in a human-readable format."""
if not result["success"]:
print(f"ERROR: {result['error']}")
sys.exit(1)
m = result["metrics"]
print("=" * 64)
print(" CLAUDE.md Analysis Report")
print("=" * 64)
print(f" File: {result['file']}")
print(f" Score: {result['score']}/100")
print(f" Lines: {m['line_count']} ({m['non_empty_lines']} non-empty)")
print(f" Words: {m['word_count']}")
print(f" Characters: {m['character_count']}")
print(f" Token estimate: ~{m['token_estimate']} tokens")
budget_status = "WITHIN BUDGET" if m["within_budget"] else "OVER BUDGET"
print(f" Token budget: {m['token_limit']} tokens ({budget_status})")
print(f" Sections: {m['section_count']}")
print()
# Section breakdown
print("--- Section Breakdown ---")
for s in result["sections"]:
indent = " " * (s["level"] - 1)
print(f" {indent}{'#' * s['level']} {s['title']} (~{s['tokens']} tokens, {s['lines']} lines)")
print()
# Completeness check
print("--- Section Completeness ---")
for check in result["completeness"]:
icon = "[FOUND] " if check["found"] else "[MISSING]"
imp = check["importance"].upper()
print(f" {icon} {check['section']} ({imp})")
if not check["found"]:
print(f" -> {check['description']}")
print()
# Redundancies
if result["redundancies"]:
print("--- Redundancy Issues ---")
for r in result["redundancies"]:
print(f" [{r['type']}] {r['message']}")
print()
# Recommendations
if result["recommendations"]:
print("--- Recommendations ---")
priority_order = {"high": 0, "medium": 1, "low": 2}
sorted_recs = sorted(result["recommendations"], key=lambda r: priority_order.get(r["priority"], 3))
for rec in sorted_recs:
tag = rec["priority"].upper()
print(f" [{tag}] ({rec['category']}) {rec['message']}")
print()
if result["score"] >= 80:
print("Overall: Good shape. Minor optimizations available.")
elif result["score"] >= 50:
print("Overall: Several improvements recommended. Focus on HIGH priority items.")
else:
print("Overall: Significant restructuring recommended.")
def main():
parser = argparse.ArgumentParser(
description="Analyze a CLAUDE.md file and suggest optimizations",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=textwrap.dedent("""\
Examples:
python claudemd_optimizer.py CLAUDE.md
python claudemd_optimizer.py path/to/CLAUDE.md --token-limit 4000
python claudemd_optimizer.py CLAUDE.md --json
"""),
)
parser.add_argument(
"file_path",
help="Path to the CLAUDE.md file to analyze",
)
parser.add_argument(
"--token-limit",
type=int,
default=6000,
help="Maximum recommended token count (default: 6000)",
)
parser.add_argument(
"--json",
action="store_true",
help="Output results in JSON format",
)
args = parser.parse_args()
result = analyze_claudemd(args.file_path, args.token_limit)
if args.json:
print(json.dumps(result, indent=2))
else:
print_human_readable(result)
if not result["success"]:
sys.exit(1)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Context Analyzer - Estimate context window usage across a project
Scans a project directory to estimate how much of Claude Code's context window
is consumed by CLAUDE.md files, skill definitions, source code, and configuration.
Helps users understand and manage their token budget.
Usage:
python context_analyzer.py /path/to/project
python context_analyzer.py . --max-depth 3
python context_analyzer.py /project --context-window 200000 --json
"""
import argparse
import json
import os
import sys
import textwrap
from pathlib import Path
from typing import Dict, List, Optional, Tuple
# Approximate characters per token for Claude models
CHARS_PER_TOKEN = 4
# File categories for analysis
FILE_CATEGORIES = {
"claude_config": {
"label": "Claude Configuration",
"patterns": ["CLAUDE.md", "claude.md", ".claude/settings.json", ".claude/agents/*.yaml", ".claude/agents/*.yml"],
"description": "CLAUDE.md files and .claude/ configuration (loaded automatically)",
},
"skill_files": {
"label": "Skill Definitions",
"patterns": ["SKILL.md", "skill.md"],
"description": "Skill master documents (loaded when skills are triggered)",
},
"reference_docs": {
"label": "Reference Documents",
"patterns": ["references/*.md", "references/**/*.md"],
"description": "Deep-dive reference guides (loaded on demand)",
},
"source_code": {
"label": "Source Code",
"extensions": [".py", ".js", ".ts", ".tsx", ".jsx", ".go", ".rs", ".java", ".rb", ".php", ".c", ".cpp", ".h", ".cs", ".swift", ".kt"],
"description": "Source files Claude reads during work",
},
"config_files": {
"label": "Config & Build",
"extensions": [".json", ".yaml", ".yml", ".toml", ".ini", ".cfg", ".env.example", ".gitignore"],
"names": ["Makefile", "Dockerfile", "docker-compose.yml", "package.json", "tsconfig.json", "pyproject.toml", "Cargo.toml", "go.mod"],
"description": "Configuration and build files",
},
"documentation": {
"label": "Documentation",
"extensions": [".md", ".rst", ".txt"],
"description": "Markdown and text documentation",
},
}
# Directories to always skip
SKIP_DIRS = {
".git", "node_modules", "__pycache__", ".venv", "venv", "env",
".tox", ".mypy_cache", ".pytest_cache", "dist", "build",
".next", ".nuxt", "coverage", ".coverage", "target",
".terraform", ".serverless", "vendor",
}
# Files to always skip
SKIP_FILES = {
".DS_Store", "Thumbs.db", "package-lock.json", "yarn.lock",
"pnpm-lock.yaml", "poetry.lock", "Gemfile.lock", "Cargo.lock",
"composer.lock",
}
# Max file size to analyze (skip very large files)
MAX_FILE_SIZE = 1_000_000 # 1 MB
def estimate_tokens(text: str) -> int:
"""Estimate token count from text."""
return int(len(text) / CHARS_PER_TOKEN)
def estimate_tokens_from_size(byte_size: int) -> int:
"""Estimate tokens from file size in bytes (assumes UTF-8)."""
return int(byte_size / CHARS_PER_TOKEN)
def categorize_file(filepath: Path, project_root: Path) -> str:
"""Categorize a file into one of the analysis categories."""
name = filepath.name
relative = filepath.relative_to(project_root)
relative_str = str(relative)
# Claude configuration files
if name.upper() == "CLAUDE.MD":
return "claude_config"
if ".claude/" in relative_str or ".claude\\" in relative_str:
return "claude_config"
# Skill files
if name.upper() == "SKILL.MD":
return "skill_files"
# Reference documents
parts = relative.parts
if "references" in parts:
return "reference_docs"
# Source code
suffix = filepath.suffix.lower()
source_extensions = FILE_CATEGORIES["source_code"]["extensions"]
if suffix in source_extensions:
return "source_code"
# Config files
config_extensions = FILE_CATEGORIES["config_files"]["extensions"]
config_names = FILE_CATEGORIES["config_files"].get("names", [])
if suffix in config_extensions or name in config_names:
return "config_files"
# Documentation
doc_extensions = FILE_CATEGORIES["documentation"]["extensions"]
if suffix in doc_extensions:
return "documentation"
return "other"
def scan_project(
project_path: str,
max_depth: int = 5,
context_window: int = 200_000,
) -> Dict:
"""Scan a project directory and analyze context window usage."""
root = Path(project_path).resolve()
if not root.exists():
return {"success": False, "error": f"Path does not exist: {project_path}"}
if not root.is_dir():
return {"success": False, "error": f"Not a directory: {project_path}"}
# Collect files by category
category_files: Dict[str, List[Dict]] = {
"claude_config": [],
"skill_files": [],
"reference_docs": [],
"source_code": [],
"config_files": [],
"documentation": [],
"other": [],
}
total_files = 0
skipped_files = 0
for dirpath, dirnames, filenames in os.walk(root):
# Compute current depth
rel_dir = Path(dirpath).relative_to(root)
depth = len(rel_dir.parts)
if depth > max_depth:
dirnames.clear()
continue
# Skip ignored directories
dirnames[:] = [d for d in dirnames if d not in SKIP_DIRS]
for filename in filenames:
if filename in SKIP_FILES:
skipped_files += 1
continue
filepath = Path(dirpath) / filename
# Skip very large files
try:
file_size = filepath.stat().st_size
except OSError:
skipped_files += 1
continue
if file_size > MAX_FILE_SIZE:
skipped_files += 1
continue
if file_size == 0:
continue
total_files += 1
category = categorize_file(filepath, root)
token_estimate = estimate_tokens_from_size(file_size)
category_files[category].append({
"path": str(filepath.relative_to(root)),
"size_bytes": file_size,
"token_estimate": token_estimate,
})
# Compute category totals
category_summaries = {}
total_tokens = 0
for cat_key, files in category_files.items():
cat_tokens = sum(f["token_estimate"] for f in files)
total_tokens += cat_tokens
label = FILE_CATEGORIES.get(cat_key, {}).get("label", cat_key.replace("_", " ").title())
description = FILE_CATEGORIES.get(cat_key, {}).get("description", "")
# Sort files by token count descending
sorted_files = sorted(files, key=lambda f: f["token_estimate"], reverse=True)
category_summaries[cat_key] = {
"label": label,
"description": description,
"file_count": len(files),
"total_tokens": cat_tokens,
"percentage_of_window": round(cat_tokens / context_window * 100, 1) if context_window > 0 else 0,
"largest_files": sorted_files[:10],
}
# Compute auto-loaded tokens (CLAUDE.md files load automatically)
auto_loaded_tokens = category_summaries.get("claude_config", {}).get("total_tokens", 0)
# Compute the recommended budget breakdown
budget = {
"system_prompt": {"tokens": 3000, "label": "System Prompt (fixed)"},
"claude_config": {"tokens": auto_loaded_tokens, "label": "CLAUDE.md Configuration (auto-loaded)"},
"active_skills": {"tokens": category_summaries.get("skill_files", {}).get("total_tokens", 0), "label": "Skill Definitions (on trigger)"},
"available_for_work": {
"tokens": context_window - 3000 - auto_loaded_tokens,
"label": "Available for Source Code + Conversation + Reasoning",
},
}
# Find top 20 largest files across all categories
all_files = []
for files in category_files.values():
all_files.extend(files)
largest_files = sorted(all_files, key=lambda f: f["token_estimate"], reverse=True)[:20]
# Generate recommendations
recommendations = []
if auto_loaded_tokens > context_window * 0.1:
recommendations.append({
"priority": "high",
"message": f"CLAUDE.md configuration uses {auto_loaded_tokens} tokens "
f"({round(auto_loaded_tokens / context_window * 100, 1)}% of context window). "
f"Target under 10%. Use hierarchical loading.",
})
if auto_loaded_tokens > 8000:
recommendations.append({
"priority": "high",
"message": "Root CLAUDE.md files exceed 8K tokens total. "
"Move domain-specific instructions to subdirectory CLAUDE.md files.",
})
skill_tokens = category_summaries.get("skill_files", {}).get("total_tokens", 0)
if skill_tokens > context_window * 0.15:
recommendations.append({
"priority": "medium",
"message": f"Skill definitions total {skill_tokens} tokens. "
f"Consider splitting large skills or using progressive disclosure.",
})
large_source_files = [
f for f in category_files.get("source_code", [])
if f["token_estimate"] > 5000
]
if large_source_files:
recommendations.append({
"priority": "medium",
"message": f"{len(large_source_files)} source files exceed 5K tokens. "
f"When reading these files, use line ranges instead of full reads.",
})
available = budget["available_for_work"]["tokens"]
if available < context_window * 0.5:
recommendations.append({
"priority": "high",
"message": f"Only {available} tokens ({round(available / context_window * 100, 1)}%) "
f"available for actual work. Reduce configuration overhead.",
})
claude_config_count = category_summaries.get("claude_config", {}).get("file_count", 0)
if claude_config_count == 0:
recommendations.append({
"priority": "medium",
"message": "No CLAUDE.md found. Create one to give Claude project-specific context.",
})
return {
"success": True,
"project_path": str(root),
"context_window": context_window,
"summary": {
"total_files_scanned": total_files,
"files_skipped": skipped_files,
"total_project_tokens": total_tokens,
"auto_loaded_tokens": auto_loaded_tokens,
"project_as_percentage_of_window": round(total_tokens / context_window * 100, 1) if context_window > 0 else 0,
},
"categories": category_summaries,
"budget": budget,
"largest_files": largest_files,
"recommendations": recommendations,
}
def format_tokens(tokens: int) -> str:
"""Format token count with K suffix for readability."""
if tokens >= 1000:
return f"{tokens / 1000:.1f}K"
return str(tokens)
def print_human_readable(result: Dict) -> None:
"""Print analysis in human-readable format."""
if not result["success"]:
print(f"ERROR: {result['error']}")
sys.exit(1)
s = result["summary"]
cw = result["context_window"]
print("=" * 64)
print(" Context Window Analysis")
print("=" * 64)
print(f" Project: {result['project_path']}")
print(f" Context window: {format_tokens(cw)} tokens")
print(f" Files scanned: {s['total_files_scanned']} ({s['files_skipped']} skipped)")
print(f" Total project: ~{format_tokens(s['total_project_tokens'])} tokens ({s['project_as_percentage_of_window']}% of window)")
print(f" Auto-loaded: ~{format_tokens(s['auto_loaded_tokens'])} tokens (CLAUDE.md config)")
print()
# Budget breakdown
print("--- Context Budget Breakdown ---")
budget = result["budget"]
for key, info in budget.items():
tokens = info["tokens"]
pct = round(tokens / cw * 100, 1) if cw > 0 else 0
bar_len = int(pct / 2)
bar = "#" * bar_len + "." * (50 - bar_len)
print(f" {info['label']}")
print(f" {format_tokens(tokens):>8} tokens ({pct:>5.1f}%) [{bar}]")
print()
# Category breakdown
print("--- Category Breakdown ---")
for cat_key, cat_info in result["categories"].items():
if cat_info["file_count"] == 0:
continue
print(f" {cat_info['label']} ({cat_info['file_count']} files)")
print(f" ~{format_tokens(cat_info['total_tokens'])} tokens ({cat_info['percentage_of_window']}% of window)")
if cat_info["largest_files"]:
top_count = min(5, len(cat_info["largest_files"]))
for f in cat_info["largest_files"][:top_count]:
print(f" {f['path']} (~{format_tokens(f['token_estimate'])} tokens)")
print()
# Largest files
print("--- Largest Files (Top 20) ---")
for i, f in enumerate(result["largest_files"], 1):
print(f" {i:>2}. {f['path']} (~{format_tokens(f['token_estimate'])} tokens)")
print()
# Recommendations
if result["recommendations"]:
print("--- Recommendations ---")
priority_order = {"high": 0, "medium": 1, "low": 2}
sorted_recs = sorted(result["recommendations"], key=lambda r: priority_order.get(r["priority"], 3))
for rec in sorted_recs:
print(f" [{rec['priority'].upper()}] {rec['message']}")
print()
def main():
parser = argparse.ArgumentParser(
description="Analyze a project to estimate Claude Code context window usage",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=textwrap.dedent("""\
Examples:
python context_analyzer.py /path/to/project
python context_analyzer.py . --max-depth 3
python context_analyzer.py /project --context-window 200000 --json
"""),
)
parser.add_argument(
"project_path",
help="Path to the project directory to analyze",
)
parser.add_argument(
"--max-depth",
type=int,
default=5,
help="Maximum directory traversal depth (default: 5)",
)
parser.add_argument(
"--context-window",
type=int,
default=200_000,
help="Total context window size in tokens (default: 200000)",
)
parser.add_argument(
"--json",
action="store_true",
help="Output results in JSON format",
)
args = parser.parse_args()
result = scan_project(
project_path=args.project_path,
max_depth=args.max_depth,
context_window=args.context_window,
)
if args.json:
print(json.dumps(result, indent=2))
else:
print_human_readable(result)
if not result["success"]:
sys.exit(1)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Skill Scaffolder - Generate a complete skill package directory
Creates a new skill directory with SKILL.md template, scripts/, references/,
assets/ directories, and properly formatted YAML frontmatter.
Usage:
python skill_scaffolder.py my-skill --domain engineering --description "Brief desc"
python skill_scaffolder.py my-skill --domain marketing --description "Campaign tools" --json
python skill_scaffolder.py my-skill -d product --description "User research" -o /path/to/skills/
"""
import argparse
import json
import os
import sys
import textwrap
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Optional
# Valid domains for categorization
VALID_DOMAINS = [
"engineering",
"marketing",
"product",
"project-management",
"c-level",
"ra-qm",
"business-growth",
"finance",
"standards",
"development-tools",
]
# Template for the SKILL.md file
SKILL_MD_TEMPLATE = textwrap.dedent('''\
---
name: {name}
description: >-
{description}
license: {license}
metadata:
version: {version}
category: {category}
domain: {domain}
---
# {title}
{summary}
## Keywords
{keywords}
---
## Table of Contents
- [Quick Start](#quick-start)
- [Tools Overview](#tools-overview)
- [Workflows](#workflows)
- [Reference Documentation](#reference-documentation)
---
## Quick Start
```bash
# TODO: Add quick start commands
python scripts/example_tool.py --help
```
---
## Tools Overview
### 1. Example Tool
Description of what this tool does.
```bash
python scripts/example_tool.py input --option value
python scripts/example_tool.py input --json
```
| Parameter | Description |
|-----------|-------------|
| `input` | Description of input parameter |
| `--option` | Description of option |
| `--json` | Output in JSON format |
---
## Workflows
### Workflow 1: Primary Workflow
**Step 1: Description**
```bash
# Command
```
**Step 2: Description**
```bash
# Command
```
---
## Reference Documentation
| Document | Path | Description |
|----------|------|-------------|
| Guide Name | [references/guide.md](references/guide.md) | Description |
---
**Last Updated:** {date}
**Version:** {version}
''')
# Template for a starter Python script
SCRIPT_TEMPLATE = textwrap.dedent('''\
#!/usr/bin/env python3
"""
{title} - {description}
Usage:
python {filename} --help
python {filename} input_arg
python {filename} input_arg --json
"""
import argparse
import json
import sys
from pathlib import Path
def main():
parser = argparse.ArgumentParser(
description="{description}",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
python {filename} example_input
python {filename} example_input --json
""",
)
parser.add_argument("input", help="Input to process")
parser.add_argument("--json", action="store_true", help="Output in JSON format")
args = parser.parse_args()
result = {{"input": args.input, "status": "success", "message": "TODO: Implement"}}
if args.json:
print(json.dumps(result, indent=2))
else:
print(f"Input: {{result['input']}}")
print(f"Status: {{result['status']}}")
print(f"Message: {{result['message']}}")
if __name__ == "__main__":
main()
''')
# Template for a starter reference document
REFERENCE_TEMPLATE = textwrap.dedent('''\
# {title}
## Overview
This reference guide covers {topic}.
## Key Concepts
### Concept 1
Description and details.
### Concept 2
Description and details.
## Best Practices
1. **Practice 1** -- Explanation
2. **Practice 2** -- Explanation
3. **Practice 3** -- Explanation
## Examples
### Example 1
```
Example content
```
## Additional Resources
- Resource 1
- Resource 2
---
**Last Updated:** {date}
''')
def to_title_case(name: str) -> str:
"""Convert kebab-case to Title Case."""
return " ".join(word.capitalize() for word in name.split("-"))
def validate_skill_name(name: str) -> Optional[str]:
"""Validate skill name format. Returns error message or None."""
if not name:
return "Skill name cannot be empty"
if not all(c.isalnum() or c == "-" for c in name):
return "Skill name must contain only alphanumeric characters and hyphens"
if name.startswith("-") or name.endswith("-"):
return "Skill name must not start or end with a hyphen"
if "--" in name:
return "Skill name must not contain consecutive hyphens"
return None
def create_skill_directory(
skill_name: str,
domain: str,
description: str,
version: str = "1.0.0",
license_type: str = "MIT",
category: str = "",
output_dir: str = ".",
) -> Dict:
"""Create the complete skill directory structure.
Returns a dict with creation results.
"""
skill_path = Path(output_dir) / skill_name
title = to_title_case(skill_name)
today = datetime.now().strftime("%B %Y")
if not category:
category = domain
# Define directory structure
directories = [
skill_path / "scripts",
skill_path / "references",
skill_path / "assets",
]
# Check if skill already exists
if skill_path.exists():
return {
"success": False,
"error": f"Directory already exists: {skill_path}",
"path": str(skill_path),
}
# Create directories
created_dirs = []
for d in directories:
d.mkdir(parents=True, exist_ok=True)
created_dirs.append(str(d))
# Generate keywords from name and domain
keywords = ", ".join(skill_name.split("-") + [domain, category])
# Create SKILL.md
skill_md_content = SKILL_MD_TEMPLATE.format(
name=skill_name,
description=description,
license=license_type,
version=version,
category=category,
domain=domain,
title=title,
summary=f"{title} skill with automation tools and reference guides.",
keywords=keywords,
date=today,
)
skill_md_path = skill_path / "SKILL.md"
skill_md_path.write_text(skill_md_content)
# Create starter script
script_name = skill_name.replace("-", "_") + "_tool.py"
script_content = SCRIPT_TEMPLATE.format(
title=title + " Tool",
description=f"Automation tool for {title.lower()}",
filename=script_name,
)
script_path = skill_path / "scripts" / script_name
script_path.write_text(script_content)
os.chmod(script_path, 0o755)
# Create starter reference
ref_content = REFERENCE_TEMPLATE.format(
title=f"{title} Guide",
topic=title.lower(),
date=today,
)
ref_path = skill_path / "references" / "guide.md"
ref_path.write_text(ref_content)
# Create .gitkeep in assets (empty directory placeholder)
gitkeep_path = skill_path / "assets" / ".gitkeep"
gitkeep_path.write_text("")
created_files = [
str(skill_md_path),
str(script_path),
str(ref_path),
str(gitkeep_path),
]
return {
"success": True,
"path": str(skill_path.resolve()),
"name": skill_name,
"domain": domain,
"version": version,
"directories_created": created_dirs,
"files_created": created_files,
}
def print_human_readable(result: Dict) -> None:
"""Print results in human-readable format."""
if not result["success"]:
print(f"ERROR: {result['error']}")
sys.exit(1)
print(f"Skill scaffolded successfully!")
print(f"")
print(f" Name: {result['name']}")
print(f" Domain: {result['domain']}")
print(f" Version: {result['version']}")
print(f" Location: {result['path']}")
print(f"")
print(f"Directory structure:")
print(f" {result['name']}/")
print(f" ├── SKILL.md")
print(f" ├── scripts/")
print(f" │ └── {result['name'].replace('-', '_')}_tool.py")
print(f" ├── references/")
print(f" │ └── guide.md")
print(f" └── assets/")
print(f" └── .gitkeep")
print(f"")
print(f"Next steps:")
print(f" 1. Edit SKILL.md with your skill's workflows and documentation")
print(f" 2. Implement your Python tools in scripts/")
print(f" 3. Add deep-dive guides to references/")
print(f" 4. Add user-facing templates to assets/")
def main():
parser = argparse.ArgumentParser(
description="Scaffold a new Claude Code skill package with proper structure",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=textwrap.dedent("""\
Examples:
python skill_scaffolder.py my-skill --domain engineering --description "Brief desc"
python skill_scaffolder.py api-analyzer -d engineering --description "API analysis" --json
python skill_scaffolder.py campaign-planner -d marketing --description "Campaign planning" -o /skills/
"""),
)
parser.add_argument(
"skill_name",
help="Name for the skill (kebab-case recommended, e.g., my-new-skill)",
)
parser.add_argument(
"--domain",
"-d",
default="engineering",
help=f"Domain category (default: engineering). Options: {', '.join(VALID_DOMAINS)}",
)
parser.add_argument(
"--description",
default="",
help="Brief description for YAML frontmatter (optimized for auto-discovery)",
)
parser.add_argument(
"--version",
default="1.0.0",
help="Semantic version (default: 1.0.0)",
)
parser.add_argument(
"--license",
dest="license_type",
default="MIT",
help="License type (default: MIT)",
)
parser.add_argument(
"--category",
default="",
help="Skill category for metadata (default: same as domain)",
)
parser.add_argument(
"--output",
"-o",
default=".",
help="Parent directory for the skill folder (default: current directory)",
)
parser.add_argument(
"--json",
action="store_true",
help="Output results in JSON format",
)
args = parser.parse_args()
# Validate skill name
error = validate_skill_name(args.skill_name)
if error:
if args.json:
print(json.dumps({"success": False, "error": error}))
else:
print(f"ERROR: {error}")
sys.exit(1)
# Validate domain
if args.domain not in VALID_DOMAINS:
warning = f"Warning: '{args.domain}' is not a standard domain. Standard domains: {', '.join(VALID_DOMAINS)}"
if not args.json:
print(warning)
# Generate default description if not provided
description = args.description
if not description:
title = to_title_case(args.skill_name)
description = (
f'This skill should be used when the user asks about {title.lower()}. '
f'Use for {title.lower()} workflows, analysis, and automation.'
)
# Validate output directory
output_path = Path(args.output)
if not output_path.exists():
if args.json:
print(json.dumps({"success": False, "error": f"Output directory does not exist: {args.output}"}))
else:
print(f"ERROR: Output directory does not exist: {args.output}")
sys.exit(1)
# Create the skill
result = create_skill_directory(
skill_name=args.skill_name,
domain=args.domain,
description=description,
version=args.version,
license_type=args.license_type,
category=args.category,
output_dir=args.output,
)
if args.json:
print(json.dumps(result, indent=2))
else:
print_human_readable(result)
if not result["success"]:
sys.exit(1)
if __name__ == "__main__":
main()
Related skills
FAQ
What tools does it include?
A skill scaffolder, a CLAUDE.md optimizer, and a context analyzer, all supporting JSON output.
What does the context analyzer do?
It scans a project to estimate context-window consumption by file category and recommends reductions.