Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 09:06:38 +08:00
commit ed3e4c84c3
76 changed files with 20449 additions and 0 deletions

View File

@@ -0,0 +1,655 @@
# Complete Hook Implementation for Skills Auto-Activation
This guide provides complete, production-ready code for implementing skills auto-activation using Claude Code hooks.
## Complete File Structure
```
~/.claude/
├── hooks/
│ └── user-prompt-submit/
│ └── skill-activator.js # Main hook script
├── skill-rules.json # Skill activation rules
└── hooks.json # Hook configuration
```
## Step 1: Create skill-rules.json
**Location:** `~/.claude/skill-rules.json`
```json
{
"backend-dev-guidelines": {
"type": "domain",
"enforcement": "suggest",
"priority": "high",
"promptTriggers": {
"keywords": [
"backend",
"controller",
"service",
"repository",
"API",
"endpoint",
"route",
"middleware",
"database",
"prisma",
"sequelize"
],
"intentPatterns": [
"(create|add|build|implement).*?(route|endpoint|controller|service|repository)",
"(how to|best practice|pattern|guide).*?(backend|API|database|server)",
"(setup|configure|initialize).*?(database|ORM|API)",
"implement.*(authentication|authorization|auth|security)",
"(error|exception).*(handling|catching|logging)"
]
},
"fileTriggers": {
"pathPatterns": [
"backend/**/*.ts",
"backend/**/*.js",
"server/**/*.ts",
"api/**/*.ts",
"src/controllers/**",
"src/services/**",
"src/repositories/**"
],
"contentPatterns": [
"express\\.Router",
"export.*Controller",
"export.*Service",
"export.*Repository",
"prisma\\.",
"@Controller",
"@Injectable"
]
}
},
"frontend-dev-guidelines": {
"type": "domain",
"enforcement": "suggest",
"priority": "high",
"promptTriggers": {
"keywords": [
"frontend",
"component",
"react",
"UI",
"layout",
"page",
"view",
"hooks",
"state",
"props",
"routing",
"navigation"
],
"intentPatterns": [
"(create|build|add|implement).*?(component|page|layout|view|screen)",
"(how to|pattern|best practice).*?(react|hooks|state|context|props)",
"(style|CSS|design).*?(component|layout|UI)",
"implement.*?(routing|navigation|route)",
"(state|data).*(management|flow|handling)"
]
},
"fileTriggers": {
"pathPatterns": [
"src/components/**/*.tsx",
"src/components/**/*.jsx",
"src/pages/**/*.tsx",
"src/views/**/*.tsx",
"frontend/**/*.tsx"
],
"contentPatterns": [
"import.*from ['\"]react",
"export.*function.*Component",
"export.*default.*function",
"useState",
"useEffect",
"React\\.FC"
]
}
},
"test-driven-development": {
"type": "process",
"enforcement": "suggest",
"priority": "high",
"promptTriggers": {
"keywords": [
"test",
"testing",
"TDD",
"spec",
"unit test",
"integration test",
"e2e",
"jest",
"vitest",
"mocha"
],
"intentPatterns": [
"(write|add|create|implement).*?(test|spec|unit test)",
"test.*(first|before|TDD|driven)",
"(bug|fix|issue).*?(reproduce|test)",
"(coverage|untested).*?(code|function)",
"(mock|stub|spy).*?(function|API|service)"
]
},
"fileTriggers": {
"pathPatterns": [
"**/*.test.ts",
"**/*.test.js",
"**/*.spec.ts",
"**/*.spec.js",
"**/__tests__/**",
"**/test/**"
],
"contentPatterns": [
"describe\\(",
"it\\(",
"test\\(",
"expect\\(",
"jest\\.fn",
"beforeEach\\(",
"afterEach\\("
]
}
},
"debugging-with-tools": {
"type": "process",
"enforcement": "suggest",
"priority": "medium",
"promptTriggers": {
"keywords": [
"debug",
"debugging",
"error",
"bug",
"crash",
"fails",
"broken",
"not working",
"issue",
"problem"
],
"intentPatterns": [
"(debug|fix|solve|investigate|troubleshoot).*?(error|bug|issue|problem)",
"(why|what).*?(failing|broken|not working|crashing)",
"(find|locate|identify).*?(bug|issue|problem|root cause)",
"reproduce.*(bug|issue|error)"
]
}
},
"refactoring-safely": {
"type": "process",
"enforcement": "suggest",
"priority": "medium",
"promptTriggers": {
"keywords": [
"refactor",
"refactoring",
"cleanup",
"improve",
"restructure",
"reorganize",
"simplify"
],
"intentPatterns": [
"(refactor|clean up|improve|restructure).*?(code|function|class|component)",
"(extract|split|separate).*?(function|method|component|logic)",
"(rename|move|relocate).*?(file|function|class)",
"remove.*(duplication|duplicate|repeated code)"
]
}
}
}
```
## Step 2: Create Hook Script
**Location:** `~/.claude/hooks/user-prompt-submit/skill-activator.js`
```javascript
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
// Configuration
const CONFIG = {
rulesPath: process.env.SKILL_RULES || path.join(process.env.HOME, '.claude/skill-rules.json'),
maxSkills: 3, // Limit to avoid context overload
debugMode: process.env.DEBUG === 'true'
};
// Load skill rules
function loadRules() {
try {
const content = fs.readFileSync(CONFIG.rulesPath, 'utf8');
return JSON.parse(content);
} catch (error) {
if (CONFIG.debugMode) {
console.error('Failed to load skill rules:', error.message);
}
return {};
}
}
// Read prompt from stdin
function readPrompt() {
return new Promise((resolve) => {
let data = '';
process.stdin.on('data', chunk => data += chunk);
process.stdin.on('end', () => {
try {
resolve(JSON.parse(data));
} catch (error) {
if (CONFIG.debugMode) {
console.error('Failed to parse prompt:', error.message);
}
resolve({ text: '' });
}
});
});
}
// Analyze prompt for skill matches
function analyzePrompt(promptText, rules) {
const lowerText = promptText.toLowerCase();
const activated = [];
for (const [skillName, config] of Object.entries(rules)) {
let matched = false;
let matchReason = '';
// Check keyword triggers
if (config.promptTriggers?.keywords) {
for (const keyword of config.promptTriggers.keywords) {
if (lowerText.includes(keyword.toLowerCase())) {
matched = true;
matchReason = `keyword: "${keyword}"`;
break;
}
}
}
// Check intent pattern triggers
if (!matched && config.promptTriggers?.intentPatterns) {
for (const pattern of config.promptTriggers.intentPatterns) {
try {
if (new RegExp(pattern, 'i').test(promptText)) {
matched = true;
matchReason = `intent pattern: "${pattern}"`;
break;
}
} catch (error) {
if (CONFIG.debugMode) {
console.error(`Invalid pattern "${pattern}":`, error.message);
}
}
}
}
if (matched) {
activated.push({
skill: skillName,
priority: config.priority || 'medium',
reason: matchReason,
type: config.type || 'general'
});
}
}
// Sort by priority (high > medium > low)
const priorityOrder = { high: 0, medium: 1, low: 2 };
activated.sort((a, b) => {
const priorityDiff = priorityOrder[a.priority] - priorityOrder[b.priority];
if (priorityDiff !== 0) return priorityDiff;
// Secondary sort: process types before domain types
const typeOrder = { process: 0, domain: 1, general: 2 };
return (typeOrder[a.type] || 2) - (typeOrder[b.type] || 2);
});
// Limit to max skills
return activated.slice(0, CONFIG.maxSkills);
}
// Generate activation context
function generateContext(skills) {
if (skills.length === 0) {
return null;
}
const lines = [
'',
'━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━',
'🎯 SKILL ACTIVATION CHECK',
'━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━',
'',
'Relevant skills for this prompt:',
''
];
for (const skill of skills) {
const emoji = skill.priority === 'high' ? '⭐' : skill.priority === 'medium' ? '📌' : '💡';
lines.push(`${emoji} **${skill.skill}** (${skill.priority} priority)`);
if (CONFIG.debugMode) {
lines.push(` Matched: ${skill.reason}`);
}
}
lines.push('');
lines.push('Before responding, check if any of these skills should be used.');
lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
lines.push('');
return lines.join('\n');
}
// Main execution
async function main() {
try {
// Load rules
const rules = loadRules();
if (Object.keys(rules).length === 0) {
if (CONFIG.debugMode) {
console.error('No rules loaded');
}
console.log(JSON.stringify({ decision: 'approve' }));
return;
}
// Read prompt
const prompt = await readPrompt();
if (!prompt.text || prompt.text.trim() === '') {
console.log(JSON.stringify({ decision: 'approve' }));
return;
}
// Analyze prompt
const activatedSkills = analyzePrompt(prompt.text, rules);
// Generate response
if (activatedSkills.length > 0) {
const context = generateContext(activatedSkills);
if (CONFIG.debugMode) {
console.error('Activated skills:', activatedSkills.map(s => s.skill).join(', '));
}
console.log(JSON.stringify({
decision: 'approve',
additionalContext: context
}));
} else {
if (CONFIG.debugMode) {
console.error('No skills activated');
}
console.log(JSON.stringify({ decision: 'approve' }));
}
} catch (error) {
if (CONFIG.debugMode) {
console.error('Hook error:', error.message, error.stack);
}
// Always approve on error
console.log(JSON.stringify({ decision: 'approve' }));
}
}
main();
```
## Step 3: Make Hook Executable
```bash
chmod +x ~/.claude/hooks/user-prompt-submit/skill-activator.js
```
## Step 4: Configure Hook
**Location:** `~/.claude/hooks.json`
```json
{
"hooks": [
{
"event": "UserPromptSubmit",
"command": "~/.claude/hooks/user-prompt-submit/skill-activator.js",
"description": "Analyze prompt and inject skill activation reminders",
"blocking": false,
"timeout": 1000
}
]
}
```
## Step 5: Test the Hook
### Test 1: Keyword Matching
```bash
# Create test prompt
echo '{"text": "How do I create a new API endpoint?"}' | \
node ~/.claude/hooks/user-prompt-submit/skill-activator.js
```
**Expected output:**
```json
{
"additionalContext": "\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n🎯 SKILL ACTIVATION CHECK\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\nRelevant skills for this prompt:\n\n⭐ **backend-dev-guidelines** (high priority)\n\nBefore responding, check if any of these skills should be used.\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
}
```
### Test 2: Intent Pattern Matching
```bash
echo '{"text": "I want to build a new React component"}' | \
node ~/.claude/hooks/user-prompt-submit/skill-activator.js
```
**Expected:** Should activate frontend-dev-guidelines
### Test 3: Multiple Skills
```bash
echo '{"text": "Write a test for the API endpoint"}' | \
node ~/.claude/hooks/user-prompt-submit/skill-activator.js
```
**Expected:** Should activate hyperpowers:test-driven-development and backend-dev-guidelines
### Test 4: Debug Mode
```bash
DEBUG=true echo '{"text": "How do I create a component?"}' | \
node ~/.claude/hooks/user-prompt-submit/skill-activator.js 2>&1
```
**Expected:** Debug output showing which skills matched and why
## Advanced: File-Based Triggers
To add file-based triggers, extend the hook to check which files are being edited:
```javascript
// Add to skill-activator.js
// Get recently edited files from Claude Code context
function getRecentFiles(prompt) {
// Claude Code provides context about files being edited
// This would come from the prompt context or a separate tracking mechanism
return prompt.files || [];
}
// Check file triggers
function checkFileTriggers(files, config) {
if (!files || files.length === 0) return false;
if (!config.fileTriggers) return false;
// Check path patterns
if (config.fileTriggers.pathPatterns) {
for (const file of files) {
for (const pattern of config.fileTriggers.pathPatterns) {
// Convert glob pattern to regex
const regex = globToRegex(pattern);
if (regex.test(file)) {
return true;
}
}
}
}
// Check content patterns (would require reading files)
// Omitted for performance - better to check in PostToolUse hook
return false;
}
// Convert glob pattern to regex
function globToRegex(glob) {
const regex = glob
.replace(/\*\*/g, '___DOUBLE_STAR___')
.replace(/\*/g, '[^/]*')
.replace(/___DOUBLE_STAR___/g, '.*')
.replace(/\?/g, '.');
return new RegExp(`^${regex}$`);
}
```
## Troubleshooting
### Hook Not Running
**Check:**
```bash
# Verify hook is configured
cat ~/.claude/hooks.json
# Test hook manually
echo '{"text": "test"}' | node ~/.claude/hooks/user-prompt-submit/skill-activator.js
# Check Claude Code logs
tail -f ~/.claude/logs/hooks.log
```
### No Skills Activating
**Enable debug mode:**
```bash
DEBUG=true node ~/.claude/hooks/user-prompt-submit/skill-activator.js < test-prompt.json
```
**Common causes:**
- skill-rules.json not found or invalid
- Keywords don't match (check casing, spelling)
- Patterns have regex errors
- Hook timing out (increase timeout)
### Too Many Skills Activating
**Adjust maxSkills:**
```javascript
const CONFIG = {
maxSkills: 2, // Reduce from 3
// ...
};
```
**Or tighten triggers:**
```json
{
"backend-dev-guidelines": {
"priority": "high", // Only high priority skills
"promptTriggers": {
"keywords": ["controller", "service"], // More specific keywords
// ...
}
}
}
```
### Performance Issues
**If hook is slow (>500ms):**
1. Reduce regex complexity
2. Limit number of patterns
3. Cache compiled regex patterns
4. Profile with:
```bash
time echo '{"text": "test"}' | node ~/.claude/hooks/user-prompt-submit/skill-activator.js
```
## Maintenance
### Monthly Review
```bash
# Check activation frequency
grep "Activated skills" ~/.claude/hooks/debug.log | sort | uniq -c
# Find prompts that didn't activate any skills
grep "No skills activated" ~/.claude/hooks/debug.log
```
### Updating Rules
When adding new skills:
1. Add to skill-rules.json
2. Test activation with sample prompts
3. Observe for false positives/negatives
4. Refine patterns based on usage
### Version Control
```bash
# Track rules in git
cd ~/.claude
git init
git add skill-rules.json hooks/
git commit -m "Initial skill activation rules"
```
## Integration with Other Hooks
The skill activator can work alongside other hooks:
```json
{
"hooks": [
{
"event": "UserPromptSubmit",
"command": "~/.claude/hooks/user-prompt-submit/00-log-prompt.sh",
"description": "Log prompts for analysis",
"blocking": false
},
{
"event": "UserPromptSubmit",
"command": "~/.claude/hooks/user-prompt-submit/10-skill-activator.js",
"description": "Activate relevant skills",
"blocking": false
}
]
}
```
**Naming convention:** Use numeric prefixes (00-, 10-, 20-) to control execution order.
## Performance Benchmarks
**Target performance:**
- Keyword matching: <50ms
- Intent pattern matching: <200ms
- Total hook execution: <500ms
**Actual performance (typical):**
- 2-3 skills: ~100-300ms
- 5+ skills: ~300-500ms
If performance degrades, profile and optimize patterns.

View File

@@ -0,0 +1,443 @@
# Skill Rules Examples
Example configurations for common skill types and scenarios.
## Domain-Specific Skills
### Backend Development
```json
{
"backend-dev-guidelines": {
"type": "domain",
"priority": "high",
"promptTriggers": {
"keywords": [
"backend", "server", "API", "endpoint", "route",
"controller", "service", "repository",
"middleware", "authentication", "authorization"
],
"intentPatterns": [
"(create|build|implement|add).*?(API|endpoint|route|controller)",
"how.*(backend|server|API)",
"(setup|configure).*(server|backend|API)",
"implement.*(auth|security)"
]
},
"fileTriggers": {
"pathPatterns": [
"backend/**/*.ts",
"server/**/*.ts",
"src/api/**"
]
}
}
}
```
### Frontend Development
```json
{
"frontend-dev-guidelines": {
"type": "domain",
"priority": "high",
"promptTriggers": {
"keywords": [
"frontend", "UI", "component", "react", "vue", "angular",
"page", "layout", "view", "hooks", "state"
],
"intentPatterns": [
"(create|build).*?(component|page|layout)",
"how.*(react|hooks|state)",
"(style|design).*?(component|UI)"
]
},
"fileTriggers": {
"pathPatterns": [
"src/components/**/*.tsx",
"src/pages/**/*.tsx"
]
}
}
}
```
## Process Skills
### Test-Driven Development
```json
{
"test-driven-development": {
"type": "process",
"priority": "high",
"promptTriggers": {
"keywords": ["test", "TDD", "testing", "spec", "jest", "vitest"],
"intentPatterns": [
"(write|create|add).*?test",
"test.*first",
"reproduce.*(bug|error)"
]
},
"fileTriggers": {
"pathPatterns": [
"**/*.test.ts",
"**/*.spec.ts",
"**/__tests__/**"
]
}
}
}
```
### Code Review
```json
{
"code-review": {
"type": "process",
"priority": "medium",
"promptTriggers": {
"keywords": ["review", "check", "verify", "audit", "quality"],
"intentPatterns": [
"review.*(code|changes|implementation)",
"(check|verify).*(quality|standards|best practices)"
]
}
}
}
```
## Technology-Specific Skills
### Database/Prisma
```json
{
"database-prisma": {
"type": "technology",
"priority": "high",
"promptTriggers": {
"keywords": [
"database", "prisma", "schema", "migration",
"query", "orm", "model"
],
"intentPatterns": [
"(create|update|modify).*?(schema|model|migration)",
"(query|fetch|get).*?database"
]
},
"fileTriggers": {
"pathPatterns": [
"**/prisma/**",
"**/*.prisma"
]
}
}
}
```
### Docker/DevOps
```json
{
"devops-docker": {
"type": "technology",
"priority": "medium",
"promptTriggers": {
"keywords": [
"docker", "dockerfile", "container",
"deployment", "CI/CD", "kubernetes"
],
"intentPatterns": [
"(create|build|configure).*?(docker|container)",
"(deploy|release|publish)"
]
},
"fileTriggers": {
"pathPatterns": [
"**/Dockerfile",
"**/.github/workflows/**",
"**/docker-compose.yml"
]
}
}
}
```
## Project-Specific Skills
### Feature-Specific (E-commerce Cart)
```json
{
"cart-feature": {
"type": "feature",
"priority": "medium",
"promptTriggers": {
"keywords": [
"cart", "shopping cart", "basket",
"add to cart", "checkout"
],
"intentPatterns": [
"(implement|create|modify).*?cart",
"cart.*(functionality|feature|logic)"
]
},
"fileTriggers": {
"pathPatterns": [
"src/features/cart/**",
"backend/cart-service/**"
]
}
}
}
```
## Priority-Based Configuration
### High Priority (Always Check)
```json
{
"critical-security": {
"type": "security",
"priority": "high",
"enforcement": "suggest",
"promptTriggers": {
"keywords": [
"security", "vulnerability", "authentication", "authorization",
"SQL injection", "XSS", "CSRF", "password", "token"
],
"intentPatterns": [
"secur(e|ity)",
"vulnerab(le|ility)",
"(auth|password|token).*(implement|handle|store)"
]
}
}
}
```
### Medium Priority (Contextual)
```json
{
"performance-optimization": {
"type": "optimization",
"priority": "medium",
"promptTriggers": {
"keywords": [
"performance", "optimize", "slow", "cache",
"memory", "speed", "latency"
],
"intentPatterns": [
"(improve|optimize).*(performance|speed)",
"(reduce|minimize).*(latency|memory|time)"
]
}
}
}
```
### Low Priority (Optional)
```json
{
"documentation-guide": {
"type": "documentation",
"priority": "low",
"promptTriggers": {
"keywords": [
"documentation", "docs", "comments", "readme",
"docstring", "jsdoc"
],
"intentPatterns": [
"(write|update|create).*?(documentation|docs)",
"document.*(API|function|component)"
]
}
}
}
```
## Multi-Repo Configuration
For projects with multiple repositories:
```json
{
"frontend-mobile": {
"type": "domain",
"priority": "high",
"promptTriggers": {
"keywords": ["mobile", "ios", "android", "react native"],
"intentPatterns": ["(create|build).*?(screen|component)"]
},
"fileTriggers": {
"pathPatterns": ["/mobile/**", "/apps/mobile/**"]
}
},
"frontend-web": {
"type": "domain",
"priority": "high",
"promptTriggers": {
"keywords": ["web", "website", "react", "nextjs"],
"intentPatterns": ["(create|build).*?(page|component)"]
},
"fileTriggers": {
"pathPatterns": ["/web/**", "/apps/web/**"]
}
}
}
```
## Advanced Pattern Matching
### Negative Patterns (Exclude)
```json
{
"backend-dev-guidelines": {
"promptTriggers": {
"keywords": ["backend"],
"intentPatterns": [
"backend",
"(?!.*test).*backend" // Match "backend" but not if "test" appears
]
}
}
}
```
### Compound Patterns
```json
{
"database-migration": {
"promptTriggers": {
"intentPatterns": [
"(create|generate|run).*(migration|schema change)",
"(add|remove|modify).*(column|table|index)"
]
}
}
}
```
### Context-Aware Patterns
```json
{
"error-handling": {
"promptTriggers": {
"keywords": ["error", "exception", "try", "catch"],
"intentPatterns": [
"(handle|catch|throw).*(error|exception)",
"error.*handling"
]
}
}
}
```
## Enforcement Levels
```json
{
"critical-skill": {
"enforcement": "block", // Block if not used (future feature)
"priority": "high"
},
"recommended-skill": {
"enforcement": "suggest", // Suggest usage
"priority": "medium"
},
"optional-skill": {
"enforcement": "optional", // Mention availability
"priority": "low"
}
}
```
## Full Example Configuration
Complete configuration for a full-stack TypeScript project:
```json
{
"backend-dev-guidelines": {
"type": "domain",
"priority": "high",
"promptTriggers": {
"keywords": ["backend", "API", "endpoint", "controller", "service"],
"intentPatterns": [
"(create|add|implement).*?(API|endpoint|route|controller|service)",
"how.*(backend|server|API)"
]
},
"fileTriggers": {
"pathPatterns": ["backend/**/*.ts", "server/**/*.ts"]
}
},
"frontend-dev-guidelines": {
"type": "domain",
"priority": "high",
"promptTriggers": {
"keywords": ["frontend", "component", "react", "UI"],
"intentPatterns": ["(create|build).*?(component|page)"]
},
"fileTriggers": {
"pathPatterns": ["src/components/**/*.tsx", "src/pages/**/*.tsx"]
}
},
"test-driven-development": {
"type": "process",
"priority": "high",
"promptTriggers": {
"keywords": ["test", "TDD", "testing"],
"intentPatterns": ["(write|create).*?test", "test.*first"]
},
"fileTriggers": {
"pathPatterns": ["**/*.test.ts", "**/*.spec.ts"]
}
},
"database-prisma": {
"type": "technology",
"priority": "high",
"promptTriggers": {
"keywords": ["database", "prisma", "schema", "migration"],
"intentPatterns": ["(create|modify).*?(schema|migration)"]
},
"fileTriggers": {
"pathPatterns": ["**/prisma/**"]
}
},
"debugging-with-tools": {
"type": "process",
"priority": "medium",
"promptTriggers": {
"keywords": ["debug", "bug", "error", "broken", "not working"],
"intentPatterns": ["(debug|fix|solve).*?(error|bug|issue)"]
}
},
"refactoring-safely": {
"type": "process",
"priority": "medium",
"promptTriggers": {
"keywords": ["refactor", "cleanup", "improve", "restructure"],
"intentPatterns": ["(refactor|clean up|improve).*?code"]
}
}
}
```
## Tips for Creating Rules
1. **Start broad, refine narrow** - Begin with general keywords, narrow based on false positives
2. **Use priority wisely** - High priority for critical skills only
3. **Test patterns** - Validate regex patterns before deploying
4. **Monitor activation** - Track which skills activate and adjust
5. **Keep it maintainable** - Comment complex patterns
6. **Version control** - Track changes to rules over time

View File

@@ -0,0 +1,557 @@
# Troubleshooting Skills Auto-Activation
Common issues and solutions for skills auto-activation system.
## Problem: Hook Not Running At All
### Symptoms
- No skill activation messages appear
- Prompts process normally without injected context
### Diagnosis
**Step 1: Check hook configuration**
```bash
cat ~/.claude/hooks.json
```
Should contain:
```json
{
"hooks": [
{
"event": "UserPromptSubmit",
"command": "~/.claude/hooks/user-prompt-submit/skill-activator.js"
}
]
}
```
**Step 2: Test hook manually**
```bash
echo '{"text": "test backend endpoint"}' | \
node ~/.claude/hooks/user-prompt-submit/skill-activator.js
```
Should output JSON with `decision` and possibly `additionalContext`.
**Step 3: Check file permissions**
```bash
ls -l ~/.claude/hooks/user-prompt-submit/skill-activator.js
```
Should be executable (`-rwxr-xr-x`). If not:
```bash
chmod +x ~/.claude/hooks/user-prompt-submit/skill-activator.js
```
**Step 4: Check Claude Code logs**
```bash
tail -f ~/.claude/logs/hooks.log
```
Look for errors related to skill-activator.
### Solutions
**Solution 1: Reinstall hook**
```bash
mkdir -p ~/.claude/hooks/user-prompt-submit
cp skill-activator.js ~/.claude/hooks/user-prompt-submit/
chmod +x ~/.claude/hooks/user-prompt-submit/skill-activator.js
```
**Solution 2: Verify Node.js**
```bash
which node
node --version
```
Ensure Node.js is installed and in PATH.
**Solution 3: Check hook timeout**
```json
{
"hooks": [
{
"event": "UserPromptSubmit",
"command": "~/.claude/hooks/user-prompt-submit/skill-activator.js",
"timeout": 2000 // Increase if needed
}
]
}
```
## Problem: No Skills Activating
### Symptoms
- Hook runs successfully
- No skills appear in activation messages
- Debug shows "No skills activated"
### Diagnosis
**Enable debug mode:**
```bash
DEBUG=true echo '{"text": "your test prompt"}' | \
node ~/.claude/hooks/user-prompt-submit/skill-activator.js 2>&1
```
**Check for:**
- "No rules loaded" → skill-rules.json not found
- "No skills activated" → Keywords/patterns don't match
### Solutions
**Solution 1: Verify skill-rules.json location**
```bash
cat ~/.claude/skill-rules.json
```
If not found:
```bash
cp skill-rules.json ~/.claude/skill-rules.json
```
**Solution 2: Test with known keyword**
```bash
echo '{"text": "create backend controller"}' | \
SKILL_RULES=~/.claude/skill-rules.json \
DEBUG=true \
node ~/.claude/hooks/user-prompt-submit/skill-activator.js 2>&1
```
Should match "backend-dev-guidelines" if configured.
**Solution 3: Check JSON syntax**
```bash
cat ~/.claude/skill-rules.json | jq '.'
```
If errors, fix JSON syntax.
**Solution 4: Simplify rules for testing**
```json
{
"test-skill": {
"type": "test",
"priority": "high",
"promptTriggers": {
"keywords": ["test"]
}
}
}
```
Test with:
```bash
echo '{"text": "test"}' | node ~/.claude/hooks/user-prompt-submit/skill-activator.js
```
## Problem: Wrong Skills Activating
### Symptoms
- Skills activate on irrelevant prompts
- Too many false positives
### Diagnosis
**Enable debug to see why skills matched:**
```bash
DEBUG=true echo '{"text": "your prompt"}' | \
node ~/.claude/hooks/user-prompt-submit/skill-activator.js 2>&1
```
Look for "Matched: keyword" or "Matched: intent pattern" to see why.
### Solutions
**Solution 1: Tighten keywords**
Before:
```json
{
"keywords": ["api", "test", "code"]
}
```
After (more specific):
```json
{
"keywords": ["API endpoint", "integration test", "refactor code"]
}
```
**Solution 2: Use negative patterns**
```json
{
"intentPatterns": [
"(?!.*test).*backend" // Match "backend" but not if "test" in prompt
]
}
```
**Solution 3: Increase priority thresholds**
```json
{
"test-skill": {
"priority": "low" // Will be deprioritized if others match
}
}
```
**Solution 4: Reduce maxSkills**
In skill-activator.js:
```javascript
const CONFIG = {
maxSkills: 2, // Reduce from 3
};
```
## Problem: Hook Is Slow
### Symptoms
- Noticeable delay before Claude responds
- Hook takes >1 second
### Diagnosis
**Measure hook performance:**
```bash
time echo '{"text": "test"}' | node ~/.claude/hooks/user-prompt-submit/skill-activator.js
```
Should be <500ms. If slower, diagnose:
**Check number of rules:**
```bash
cat ~/.claude/skill-rules.json | jq 'keys | length'
```
More than 10 rules may slow down.
**Check pattern complexity:**
```bash
cat ~/.claude/skill-rules.json | jq '.[].promptTriggers.intentPatterns'
```
Complex regex patterns slow matching.
### Solutions
**Solution 1: Optimize regex patterns**
Before (slow):
```json
{
"intentPatterns": [
".*create.*backend.*endpoint.*"
]
}
```
After (faster):
```json
{
"intentPatterns": [
"(create|build).*(backend|API).*(endpoint|route)"
]
}
```
**Solution 2: Cache compiled patterns**
Modify hook to compile patterns once:
```javascript
const compiledPatterns = new Map();
function getCompiledPattern(pattern) {
if (!compiledPatterns.has(pattern)) {
compiledPatterns.set(pattern, new RegExp(pattern, 'i'));
}
return compiledPatterns.get(pattern);
}
```
**Solution 3: Reduce number of rules**
Remove low-priority or rarely-used skills.
**Solution 4: Parallelize pattern matching**
For advanced users, use worker threads to match patterns in parallel.
## Problem: Skills Still Don't Activate in Claude
### Symptoms
- Hook injects activation message
- Claude still doesn't use the skills
### Diagnosis
This means the hook is working, but Claude is ignoring the suggestion.
**Check:**
1. Are skills actually installed?
2. Does Claude have access to read skills?
3. Are skill descriptions clear?
### Solutions
**Solution 1: Make activation message stronger**
In skill-activator.js, change:
```javascript
'Before responding, check if any of these skills should be used.'
```
To:
```javascript
'⚠️ IMPORTANT: You MUST check these skills before responding. Use the Skill tool to load them.'
```
**Solution 2: Block until skills loaded**
Change hook to blocking mode (use cautiously):
```json
{
"hooks": [
{
"event": "UserPromptSubmit",
"command": "~/.claude/hooks/user-prompt-submit/skill-activator.js",
"blocking": true // ⚠️ Experimental
}
]
}
```
**Solution 3: Improve skill descriptions**
Ensure skill descriptions are specific:
```yaml
name: backend-dev-guidelines
description: Use when creating API routes, controllers, services, or repositories - enforces TypeScript patterns, Prisma repository pattern, and Sentry error handling
```
**Solution 4: Reference skills in CLAUDE.md**
Add to project's CLAUDE.md:
```markdown
## Available Skills
- backend-dev-guidelines: Use for all backend code
- frontend-dev-guidelines: Use for all frontend code
- hyperpowers:test-driven-development: Use when writing tests
```
## Problem: Hook Crashes Claude Code
### Symptoms
- Claude Code freezes or crashes after hook execution
- Error in hooks.log
### Diagnosis
**Check error logs:**
```bash
tail -50 ~/.claude/logs/hooks.log
```
Look for errors related to skill-activator.
**Common causes:**
- Infinite loop in hook
- Memory leak
- Unhandled promise rejection
- Blocking operation
### Solutions
**Solution 1: Add error handling**
```javascript
async function main() {
try {
// ... hook logic
} catch (error) {
console.error('Hook error:', error.message);
// Always return approve on error
console.log(JSON.stringify({ decision: 'approve' }));
}
}
```
**Solution 2: Add timeout protection**
```javascript
const timeout = setTimeout(() => {
console.log(JSON.stringify({ decision: 'approve' }));
process.exit(0);
}, 900); // Exit before hook timeout
// Clear timeout if completed normally
clearTimeout(timeout);
```
**Solution 3: Test hook in isolation**
```bash
# Run hook with various inputs
for prompt in "test" "backend" "frontend" "debug"; do
echo "Testing: $prompt"
echo "{\"text\": \"$prompt\"}" | \
timeout 2s node ~/.claude/hooks/user-prompt-submit/skill-activator.js
done
```
**Solution 4: Simplify hook**
Remove complex logic and test minimal version:
```javascript
// Minimal hook for testing
console.log(JSON.stringify({
decision: 'approve',
additionalContext: '🎯 Test message'
}));
```
## Problem: Context Overload
### Symptoms
- Too many skill activation messages
- Context window fills quickly
- Claude seems overwhelmed
### Solutions
**Solution 1: Limit activated skills**
```javascript
const CONFIG = {
maxSkills: 1, // Only top match
};
```
**Solution 2: Use priorities strictly**
```json
{
"critical-skill": {
"priority": "high" // Only high priority
},
"optional-skill": {
"priority": "low" // Remove low priority
}
}
```
**Solution 3: Shorten activation message**
```javascript
function generateContext(skills) {
return `🎯 Use: ${skills.map(s => s.skill).join(', ')}`;
}
```
## Problem: Inconsistent Activation
### Symptoms
- Sometimes activates, sometimes doesn't
- Same prompt gives different results
### Diagnosis
**This is expected due to:**
- Prompt variations (punctuation, wording)
- Context differences (files being edited)
- Keyword order
### Solutions
**Solution 1: Add keyword variations**
```json
{
"keywords": [
"backend",
"back end",
"back-end",
"server side",
"server-side"
]
}
```
**Solution 2: Use more patterns**
```json
{
"intentPatterns": [
"create.*backend",
"backend.*create",
"build.*API",
"API.*build"
]
}
```
**Solution 3: Log all prompts for analysis**
```javascript
// Add to hook
fs.appendFileSync(
path.join(process.env.HOME, '.claude/prompt-log.txt'),
`${new Date().toISOString()} | ${prompt.text}\n`
);
```
Analyze monthly:
```bash
grep "backend" ~/.claude/prompt-log.txt | wc -l
```
## General Debugging Tips
**Enable full debug logging:**
```bash
# Add to hook
const logFile = path.join(process.env.HOME, '.claude/hook-debug.log');
function debug(msg) {
fs.appendFileSync(logFile, `${new Date().toISOString()} ${msg}\n`);
}
debug(`Analyzing prompt: ${prompt.text}`);
debug(`Activated skills: ${activatedSkills.map(s => s.skill).join(', ')}`);
```
**Test with controlled inputs:**
```bash
# Create test suite
cat > test-prompts.json <<EOF
[
{"text": "create backend endpoint", "expected": ["backend-dev-guidelines"]},
{"text": "build react component", "expected": ["frontend-dev-guidelines"]},
{"text": "write test for API", "expected": ["test-driven-development"]}
]
EOF
# Run tests
node test-hook.js
```
**Monitor in production:**
```bash
# Daily summary
grep "Activated skills" ~/.claude/hook-debug.log | \
grep "$(date +%Y-%m-%d)" | \
sort | uniq -c
```
## Getting Help
If problems persist:
1. Check GitHub issues for similar problems
2. Share debug output (sanitize sensitive info)
3. Test with minimal configuration
4. Verify with official examples
**Checklist before asking for help:**
- [ ] Hook runs manually without errors
- [ ] skill-rules.json is valid JSON
- [ ] Node.js version is current (v18+)
- [ ] Debug mode shows expected behavior
- [ ] Tested with simplified configuration
- [ ] Checked Claude Code logs