mirror of
https://github.com/anthropics/claude-code.git
synced 2025-11-28 16:50:27 +08:00
Adds the plugin-dev plugin to public marketplace. A comprehensive toolkit for
developing Claude Code plugins with 7 expert skills, 3 AI-assisted agents, and
extensive documentation covering the complete plugin development lifecycle.
Key features:
- 7 skills: hook-development, mcp-integration, plugin-structure, plugin-settings,
command-development, agent-development, skill-development
- 3 agents: agent-creator (AI-assisted generation), plugin-validator (structure
validation), skill-reviewer (quality review)
- 1 command: /plugin-dev:create-plugin (guided 8-phase workflow)
- 10 utility scripts for validation and testing
- 21 reference docs with deep-dive guidance (~11k words)
- 9 working examples demonstrating best practices
Changes for public release:
- Replaced all references to internal repositories with "Claude Code"
- Updated MCP examples: internal.company.com → api.example.com
- Updated token variables: ${INTERNAL_TOKEN} → ${API_TOKEN}
- Reframed agent-creation-system-prompt as "proven in production"
- Preserved all ${CLAUDE_PLUGIN_ROOT} references (186 total)
- Preserved valuable test blocks in core modules
Validation:
- All 3 agents validated successfully with validate-agent.sh
- All JSON files validated with jq
- Zero internal references remaining
- 59 files migrated, 21,971 lines added
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
369 lines
8.1 KiB
Markdown
369 lines
8.1 KiB
Markdown
# Migrating from Basic to Advanced Hooks
|
|
|
|
This guide shows how to migrate from basic command hooks to advanced prompt-based hooks for better maintainability and flexibility.
|
|
|
|
## Why Migrate?
|
|
|
|
Prompt-based hooks offer several advantages:
|
|
|
|
- **Natural language reasoning**: LLM understands context and intent
|
|
- **Better edge case handling**: Adapts to unexpected scenarios
|
|
- **No bash scripting required**: Simpler to write and maintain
|
|
- **More flexible validation**: Can handle complex logic without coding
|
|
|
|
## Migration Example: Bash Command Validation
|
|
|
|
### Before (Basic Command Hook)
|
|
|
|
**Configuration:**
|
|
```json
|
|
{
|
|
"PreToolUse": [
|
|
{
|
|
"matcher": "Bash",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "bash validate-bash.sh"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Script (validate-bash.sh):**
|
|
```bash
|
|
#!/bin/bash
|
|
input=$(cat)
|
|
command=$(echo "$input" | jq -r '.tool_input.command')
|
|
|
|
# Hard-coded validation logic
|
|
if [[ "$command" == *"rm -rf"* ]]; then
|
|
echo "Dangerous command detected" >&2
|
|
exit 2
|
|
fi
|
|
```
|
|
|
|
**Problems:**
|
|
- Only checks for exact "rm -rf" pattern
|
|
- Doesn't catch variations like `rm -fr` or `rm -r -f`
|
|
- Misses other dangerous commands (`dd`, `mkfs`, etc.)
|
|
- No context awareness
|
|
- Requires bash scripting knowledge
|
|
|
|
### After (Advanced Prompt Hook)
|
|
|
|
**Configuration:**
|
|
```json
|
|
{
|
|
"PreToolUse": [
|
|
{
|
|
"matcher": "Bash",
|
|
"hooks": [
|
|
{
|
|
"type": "prompt",
|
|
"prompt": "Command: $TOOL_INPUT.command. Analyze for: 1) Destructive operations (rm -rf, dd, mkfs, etc) 2) Privilege escalation (sudo) 3) Network operations without user consent. Return 'approve' or 'deny' with explanation.",
|
|
"timeout": 15
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Benefits:**
|
|
- Catches all variations and patterns
|
|
- Understands intent, not just literal strings
|
|
- No script file needed
|
|
- Easy to extend with new criteria
|
|
- Context-aware decisions
|
|
- Natural language explanation in denial
|
|
|
|
## Migration Example: File Write Validation
|
|
|
|
### Before (Basic Command Hook)
|
|
|
|
**Configuration:**
|
|
```json
|
|
{
|
|
"PreToolUse": [
|
|
{
|
|
"matcher": "Write",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "bash validate-write.sh"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Script (validate-write.sh):**
|
|
```bash
|
|
#!/bin/bash
|
|
input=$(cat)
|
|
file_path=$(echo "$input" | jq -r '.tool_input.file_path')
|
|
|
|
# Check for path traversal
|
|
if [[ "$file_path" == *".."* ]]; then
|
|
echo '{"decision": "deny", "reason": "Path traversal detected"}' >&2
|
|
exit 2
|
|
fi
|
|
|
|
# Check for system paths
|
|
if [[ "$file_path" == "/etc/"* ]] || [[ "$file_path" == "/sys/"* ]]; then
|
|
echo '{"decision": "deny", "reason": "System file"}' >&2
|
|
exit 2
|
|
fi
|
|
```
|
|
|
|
**Problems:**
|
|
- Hard-coded path patterns
|
|
- Doesn't understand symlinks
|
|
- Missing edge cases (e.g., `/etc` vs `/etc/`)
|
|
- No consideration of file content
|
|
|
|
### After (Advanced Prompt Hook)
|
|
|
|
**Configuration:**
|
|
```json
|
|
{
|
|
"PreToolUse": [
|
|
{
|
|
"matcher": "Write|Edit",
|
|
"hooks": [
|
|
{
|
|
"type": "prompt",
|
|
"prompt": "File path: $TOOL_INPUT.file_path. Content preview: $TOOL_INPUT.content (first 200 chars). Verify: 1) Not system directories (/etc, /sys, /usr) 2) Not credentials (.env, tokens, secrets) 3) No path traversal 4) Content doesn't expose secrets. Return 'approve' or 'deny'."
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Benefits:**
|
|
- Context-aware (considers content too)
|
|
- Handles symlinks and edge cases
|
|
- Natural understanding of "system directories"
|
|
- Can detect secrets in content
|
|
- Easy to extend criteria
|
|
|
|
## When to Keep Command Hooks
|
|
|
|
Command hooks still have their place:
|
|
|
|
### 1. Deterministic Performance Checks
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# Check file size quickly
|
|
file_path=$(echo "$input" | jq -r '.tool_input.file_path')
|
|
size=$(stat -f%z "$file_path" 2>/dev/null || stat -c%s "$file_path" 2>/dev/null)
|
|
|
|
if [ "$size" -gt 10000000 ]; then
|
|
echo '{"decision": "deny", "reason": "File too large"}' >&2
|
|
exit 2
|
|
fi
|
|
```
|
|
|
|
**Use command hooks when:** Validation is purely mathematical or deterministic.
|
|
|
|
### 2. External Tool Integration
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# Run security scanner
|
|
file_path=$(echo "$input" | jq -r '.tool_input.file_path')
|
|
scan_result=$(security-scanner "$file_path")
|
|
|
|
if [ "$?" -ne 0 ]; then
|
|
echo "Security scan failed: $scan_result" >&2
|
|
exit 2
|
|
fi
|
|
```
|
|
|
|
**Use command hooks when:** Integrating with external tools that provide yes/no answers.
|
|
|
|
### 3. Very Fast Checks (< 50ms)
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# Quick regex check
|
|
command=$(echo "$input" | jq -r '.tool_input.command')
|
|
|
|
if [[ "$command" =~ ^(ls|pwd|echo)$ ]]; then
|
|
exit 0 # Safe commands
|
|
fi
|
|
```
|
|
|
|
**Use command hooks when:** Performance is critical and logic is simple.
|
|
|
|
## Hybrid Approach
|
|
|
|
Combine both for multi-stage validation:
|
|
|
|
```json
|
|
{
|
|
"PreToolUse": [
|
|
{
|
|
"matcher": "Bash",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/quick-check.sh",
|
|
"timeout": 5
|
|
},
|
|
{
|
|
"type": "prompt",
|
|
"prompt": "Deep analysis of bash command: $TOOL_INPUT",
|
|
"timeout": 15
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
The command hook does fast deterministic checks, while the prompt hook handles complex reasoning.
|
|
|
|
## Migration Checklist
|
|
|
|
When migrating hooks:
|
|
|
|
- [ ] Identify the validation logic in the command hook
|
|
- [ ] Convert hard-coded patterns to natural language criteria
|
|
- [ ] Test with edge cases the old hook missed
|
|
- [ ] Verify LLM understands the intent
|
|
- [ ] Set appropriate timeout (usually 15-30s for prompt hooks)
|
|
- [ ] Document the new hook in README
|
|
- [ ] Remove or archive old script files
|
|
|
|
## Migration Tips
|
|
|
|
1. **Start with one hook**: Don't migrate everything at once
|
|
2. **Test thoroughly**: Verify prompt hook catches what command hook caught
|
|
3. **Look for improvements**: Use migration as opportunity to enhance validation
|
|
4. **Keep scripts for reference**: Archive old scripts in case you need to reference the logic
|
|
5. **Document reasoning**: Explain why prompt hook is better in README
|
|
|
|
## Complete Migration Example
|
|
|
|
### Original Plugin Structure
|
|
|
|
```
|
|
my-plugin/
|
|
├── .claude-plugin/plugin.json
|
|
├── hooks/hooks.json
|
|
└── scripts/
|
|
├── validate-bash.sh
|
|
├── validate-write.sh
|
|
└── check-tests.sh
|
|
```
|
|
|
|
### After Migration
|
|
|
|
```
|
|
my-plugin/
|
|
├── .claude-plugin/plugin.json
|
|
├── hooks/hooks.json # Now uses prompt hooks
|
|
└── scripts/ # Archive or delete
|
|
└── archive/
|
|
├── validate-bash.sh
|
|
├── validate-write.sh
|
|
└── check-tests.sh
|
|
```
|
|
|
|
### Updated hooks.json
|
|
|
|
```json
|
|
{
|
|
"PreToolUse": [
|
|
{
|
|
"matcher": "Bash",
|
|
"hooks": [
|
|
{
|
|
"type": "prompt",
|
|
"prompt": "Validate bash command safety: destructive ops, privilege escalation, network access"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": "Write|Edit",
|
|
"hooks": [
|
|
{
|
|
"type": "prompt",
|
|
"prompt": "Validate file write safety: system paths, credentials, path traversal, content secrets"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"Stop": [
|
|
{
|
|
"matcher": "*",
|
|
"hooks": [
|
|
{
|
|
"type": "prompt",
|
|
"prompt": "Verify tests were run if code was modified"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Result:** Simpler, more maintainable, more powerful.
|
|
|
|
## Common Migration Patterns
|
|
|
|
### Pattern: String Contains → Natural Language
|
|
|
|
**Before:**
|
|
```bash
|
|
if [[ "$command" == *"sudo"* ]]; then
|
|
echo "Privilege escalation" >&2
|
|
exit 2
|
|
fi
|
|
```
|
|
|
|
**After:**
|
|
```
|
|
"Check for privilege escalation (sudo, su, etc)"
|
|
```
|
|
|
|
### Pattern: Regex → Intent
|
|
|
|
**Before:**
|
|
```bash
|
|
if [[ "$file" =~ \.(env|secret|key|token)$ ]]; then
|
|
echo "Credential file" >&2
|
|
exit 2
|
|
fi
|
|
```
|
|
|
|
**After:**
|
|
```
|
|
"Verify not writing to credential files (.env, secrets, keys, tokens)"
|
|
```
|
|
|
|
### Pattern: Multiple Conditions → Criteria List
|
|
|
|
**Before:**
|
|
```bash
|
|
if [ condition1 ] || [ condition2 ] || [ condition3 ]; then
|
|
echo "Invalid" >&2
|
|
exit 2
|
|
fi
|
|
```
|
|
|
|
**After:**
|
|
```
|
|
"Check: 1) condition1 2) condition2 3) condition3. Deny if any fail."
|
|
```
|
|
|
|
## Conclusion
|
|
|
|
Migrating to prompt-based hooks makes plugins more maintainable, flexible, and powerful. Reserve command hooks for deterministic checks and external tool integration.
|