Initial commit
This commit is contained in:
399
skills/skills-auto-activation/SKILL.md
Normal file
399
skills/skills-auto-activation/SKILL.md
Normal file
@@ -0,0 +1,399 @@
|
||||
---
|
||||
name: skills-auto-activation
|
||||
description: Use when skills aren't activating reliably - covers official solutions (better descriptions) and custom hook system for deterministic skill activation
|
||||
---
|
||||
|
||||
<skill_overview>
|
||||
Skills often don't activate despite keywords; make activation reliable through better descriptions, explicit triggers, or custom hooks.
|
||||
</skill_overview>
|
||||
|
||||
<rigidity_level>
|
||||
HIGH FREEDOM - Choose solution level based on project needs (Level 1 for simple, Level 3 for complex). Hook implementation is flexible pattern, not rigid process.
|
||||
</rigidity_level>
|
||||
|
||||
<quick_reference>
|
||||
| Level | Solution | Effort | Reliability | When to Use |
|
||||
|-------|----------|--------|-------------|-------------|
|
||||
| 1 | Better descriptions + explicit requests | Low | Moderate | Small projects, starting out |
|
||||
| 2 | CLAUDE.md references | Low | Moderate | Document patterns |
|
||||
| 3 | Custom hook system | High | Very High | Large projects, established patterns |
|
||||
|
||||
**Hyperpowers includes:** Auto-activation hook at `hooks/user-prompt-submit/10-skill-activator.js`
|
||||
</quick_reference>
|
||||
|
||||
<when_to_use>
|
||||
Use this skill when:
|
||||
- Skills you created aren't being used automatically
|
||||
- Need consistent skill activation across sessions
|
||||
- Large codebases with established patterns
|
||||
- Manual "/use skill-name" gets tedious
|
||||
|
||||
**Prerequisites:**
|
||||
- Skills properly configured (name, description, SKILL.md)
|
||||
- Code execution enabled (Settings > Capabilities)
|
||||
- Skills toggled on (Settings > Capabilities)
|
||||
</when_to_use>
|
||||
|
||||
<the_problem>
|
||||
## What Users Experience
|
||||
|
||||
**Symptoms:**
|
||||
- Keywords from skill descriptions present → skill not used
|
||||
- Working on files that should trigger skills → nothing
|
||||
- Skills exist but sit unused
|
||||
|
||||
**Community reports:**
|
||||
- GitHub Issue #9954: "Skills not available even if explicitly enabled"
|
||||
- "Claude knows it should use skills, but it's not reliable"
|
||||
- Skills activation is "not reliable yet"
|
||||
|
||||
**Root cause:** Skills rely on Claude recognizing relevance (not deterministic)
|
||||
</the_problem>
|
||||
|
||||
<solution_levels>
|
||||
## Level 1: Official Solutions (Start Here)
|
||||
|
||||
### 1. Improve Skill Descriptions
|
||||
|
||||
❌ **Bad:**
|
||||
```yaml
|
||||
name: backend-dev
|
||||
description: Helps with backend development
|
||||
```
|
||||
|
||||
✅ **Good:**
|
||||
```yaml
|
||||
name: backend-dev-guidelines
|
||||
description: Use when creating API routes, controllers, services, or repositories in backend - enforces TypeScript patterns, error handling with Sentry, and Prisma repository pattern
|
||||
```
|
||||
|
||||
**Key elements:**
|
||||
- Specific keywords: "API routes", "controllers", "services"
|
||||
- When to use: "Use when creating..."
|
||||
- What it enforces: Patterns, error handling
|
||||
|
||||
### 2. Be Explicit in Requests
|
||||
|
||||
Instead of: "How do I create an endpoint?"
|
||||
|
||||
Try: "Use my backend-dev-guidelines skill to create an endpoint"
|
||||
|
||||
**Result:** Works, but tedious
|
||||
|
||||
### 3. Check Settings
|
||||
|
||||
- Settings > Capabilities > Enable code execution
|
||||
- Settings > Capabilities > Toggle Skills on
|
||||
- Team/Enterprise: Check org-level settings
|
||||
|
||||
---
|
||||
|
||||
## Level 2: Skill References (Moderate)
|
||||
|
||||
Reference skills in CLAUDE.md:
|
||||
|
||||
```markdown
|
||||
## When Working on Backend
|
||||
|
||||
Before making changes:
|
||||
1. Check `/skills/backend-dev-guidelines` for patterns
|
||||
2. Follow repository pattern for database access
|
||||
|
||||
The backend-dev-guidelines skill contains complete examples.
|
||||
```
|
||||
|
||||
**Pros:** No custom code
|
||||
**Cons:** Claude still might not check
|
||||
|
||||
---
|
||||
|
||||
## Level 3: Custom Hook System (Advanced)
|
||||
|
||||
**How it works:**
|
||||
1. UserPromptSubmit hook analyzes prompt before Claude sees it
|
||||
2. Matches keywords, intent patterns, file paths
|
||||
3. Injects skill activation reminder into context
|
||||
4. Claude sees "🎯 USE these skills" before processing
|
||||
|
||||
**Result:** "Night and day difference" - skills consistently used
|
||||
|
||||
### Architecture
|
||||
|
||||
```
|
||||
User submits prompt
|
||||
↓
|
||||
UserPromptSubmit hook intercepts
|
||||
↓
|
||||
Analyze prompt (keywords, intent, files)
|
||||
↓
|
||||
Check skill-rules.json for matches
|
||||
↓
|
||||
Inject activation reminder
|
||||
↓
|
||||
Claude sees: "🎯 USE these skills: ..."
|
||||
↓
|
||||
Claude loads and uses relevant skills
|
||||
```
|
||||
|
||||
### Configuration: skill-rules.json
|
||||
|
||||
```json
|
||||
{
|
||||
"backend-dev-guidelines": {
|
||||
"type": "domain",
|
||||
"enforcement": "suggest",
|
||||
"priority": "high",
|
||||
"promptTriggers": {
|
||||
"keywords": ["backend", "controller", "service", "API", "endpoint"],
|
||||
"intentPatterns": [
|
||||
"(create|add|build).*?(route|endpoint|controller|service)",
|
||||
"(how to|pattern).*?(backend|API)"
|
||||
]
|
||||
},
|
||||
"fileTriggers": {
|
||||
"pathPatterns": ["backend/src/**/*.ts", "server/**/*.ts"],
|
||||
"contentPatterns": ["express\\.Router", "export.*Controller"]
|
||||
}
|
||||
},
|
||||
"test-driven-development": {
|
||||
"type": "process",
|
||||
"enforcement": "suggest",
|
||||
"priority": "high",
|
||||
"promptTriggers": {
|
||||
"keywords": ["test", "TDD", "testing"],
|
||||
"intentPatterns": [
|
||||
"(write|add|create).*?(test|spec)",
|
||||
"test.*(first|before|TDD)"
|
||||
]
|
||||
},
|
||||
"fileTriggers": {
|
||||
"pathPatterns": ["**/*.test.ts", "**/*.spec.ts"],
|
||||
"contentPatterns": ["describe\\(", "it\\(", "test\\("]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Trigger Types
|
||||
|
||||
1. **Keyword Triggers** - Simple string matching (case insensitive)
|
||||
2. **Intent Pattern Triggers** - Regex for actions + objects
|
||||
3. **File Path Triggers** - Glob patterns for file paths
|
||||
4. **Content Pattern Triggers** - Regex in file content
|
||||
|
||||
### Hook Implementation (High-Level)
|
||||
|
||||
```javascript
|
||||
#!/usr/bin/env node
|
||||
// ~/.claude/hooks/user-prompt-submit/skill-activator.js
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Load skill rules
|
||||
const rules = JSON.parse(fs.readFileSync(
|
||||
path.join(process.env.HOME, '.claude/skill-rules.json'), 'utf8'
|
||||
));
|
||||
|
||||
// Read prompt from stdin
|
||||
let promptData = '';
|
||||
process.stdin.on('data', chunk => promptData += chunk);
|
||||
|
||||
process.stdin.on('end', () => {
|
||||
const prompt = JSON.parse(promptData);
|
||||
|
||||
// Analyze prompt for skill matches
|
||||
const activatedSkills = analyzePrompt(prompt.text);
|
||||
|
||||
if (activatedSkills.length > 0) {
|
||||
// Inject skill activation reminder
|
||||
const context = `
|
||||
🎯 SKILL ACTIVATION CHECK
|
||||
|
||||
Relevant skills for this prompt:
|
||||
${activatedSkills.map(s => `- **${s.skill}** (${s.priority} priority)`).join('\n')}
|
||||
|
||||
Check if these skills should be used before responding.
|
||||
`;
|
||||
|
||||
console.log(JSON.stringify({
|
||||
decision: 'approve',
|
||||
additionalContext: context
|
||||
}));
|
||||
} else {
|
||||
console.log(JSON.stringify({ decision: 'approve' }));
|
||||
}
|
||||
});
|
||||
|
||||
function analyzePrompt(text) {
|
||||
// Match against all skill rules
|
||||
// Return list of activated skills with priorities
|
||||
}
|
||||
```
|
||||
|
||||
**For complete working implementation:** See [resources/hook-implementation.md](resources/hook-implementation.md)
|
||||
|
||||
### Progressive Enhancement
|
||||
|
||||
**Phase 1 (Week 1):** Basic keyword matching
|
||||
```json
|
||||
{"keywords": ["backend", "API", "controller"]}
|
||||
```
|
||||
|
||||
**Phase 2 (Week 2):** Add intent patterns
|
||||
```json
|
||||
{"intentPatterns": ["(create|add).*?(route|endpoint)"]}
|
||||
```
|
||||
|
||||
**Phase 3 (Week 3):** Add file triggers
|
||||
```json
|
||||
{"fileTriggers": {"pathPatterns": ["backend/**/*.ts"]}}
|
||||
```
|
||||
|
||||
**Phase 4 (Ongoing):** Refine based on observation
|
||||
</solution_levels>
|
||||
|
||||
<results>
|
||||
### Before Hook System
|
||||
|
||||
- Skills sit unused despite perfect keywords
|
||||
- Manual "/use skill-name" every time
|
||||
- Inconsistent patterns across codebase
|
||||
- Time spent fixing "creative interpretations"
|
||||
|
||||
### After Hook System
|
||||
|
||||
- Skills activate automatically and reliably
|
||||
- Consistent patterns enforced
|
||||
- Claude self-checks before showing code
|
||||
- "Night and day difference"
|
||||
|
||||
**Real user:** "Skills went from 'expensive decorations' to actually useful"
|
||||
</results>
|
||||
|
||||
<limitations>
|
||||
## Hook System Limitations
|
||||
|
||||
1. **Requires hook system** - Not built into Claude Code
|
||||
2. **Maintenance overhead** - skill-rules.json needs updates
|
||||
3. **May over-activate** - Too many skills overwhelm context
|
||||
4. **Not perfect** - Still relies on Claude using activated skills
|
||||
|
||||
## Considerations
|
||||
|
||||
**Token usage:**
|
||||
- Activation reminder adds ~50-100 tokens per prompt
|
||||
- Multiple skills add more tokens
|
||||
- Use priorities to limit activation
|
||||
|
||||
**Performance:**
|
||||
- Hook adds ~100-300ms to prompt processing
|
||||
- Acceptable for quality improvement
|
||||
- Optimize regex patterns if slow
|
||||
|
||||
**Maintenance:**
|
||||
- Update rules when adding new skills
|
||||
- Review activation logs monthly
|
||||
- Refine patterns based on misses
|
||||
</limitations>
|
||||
|
||||
<alternatives>
|
||||
## Approach 1: MCP Integration
|
||||
|
||||
Use Model Context Protocol to provide skills as context.
|
||||
|
||||
**Pros:** Built into Claude system
|
||||
**Cons:** Still not deterministic, same activation issues
|
||||
|
||||
## Approach 2: Custom System Prompt
|
||||
|
||||
Modify Claude's system prompt to always check certain skills.
|
||||
|
||||
**Pros:** Works without hooks
|
||||
**Cons:** Limited to Pro plan, can't customize per-project
|
||||
|
||||
## Approach 3: Manual Discipline
|
||||
|
||||
Always explicitly request skill usage.
|
||||
|
||||
**Pros:** No setup required
|
||||
**Cons:** Tedious, easy to forget, doesn't scale
|
||||
|
||||
## Approach 4: Skill Consolidation
|
||||
|
||||
Combine all guidelines into CLAUDE.md.
|
||||
|
||||
**Pros:** Always loaded
|
||||
**Cons:** Violates progressive disclosure, wastes tokens
|
||||
|
||||
**Recommendation:** Level 3 (hooks) for large projects, Level 1 for smaller projects
|
||||
</alternatives>
|
||||
|
||||
<critical_rules>
|
||||
## Rules That Have No Exceptions
|
||||
|
||||
1. **Try Level 1 first** → Better descriptions and explicit requests before building hooks
|
||||
2. **Observe before building** → Watch which prompts should activate skills
|
||||
3. **Start with keywords** → Add complexity incrementally (keywords → intent → files)
|
||||
4. **Keep hook fast (<1 second)** → Don't block prompt processing
|
||||
5. **Maintain skill-rules.json** → Update when skills change
|
||||
|
||||
## Common Excuses
|
||||
|
||||
All of these mean: **Try Level 1 first, then decide.**
|
||||
|
||||
- "Skills should just work automatically" (They should, but don't reliably - workaround needed)
|
||||
- "Hook system too complex" (Setup takes 2 hours, saves hundreds of hours)
|
||||
- "I'll manually specify skills" (You'll forget, it gets tedious)
|
||||
- "Improving descriptions will fix it" (Helps, but not deterministic)
|
||||
- "This is overkill" (Maybe - start Level 1, upgrade if needed)
|
||||
</critical_rules>
|
||||
|
||||
<verification_checklist>
|
||||
Before building hook system:
|
||||
|
||||
- [ ] Tried improving skill descriptions (Level 1)
|
||||
- [ ] Tried explicit skill requests (Level 1)
|
||||
- [ ] Checked all settings are enabled
|
||||
- [ ] Observed which prompts should activate skills
|
||||
- [ ] Identified patterns in failures
|
||||
- [ ] Project large enough to justify hook overhead
|
||||
- [ ] Have time for 2-hour setup + ongoing maintenance
|
||||
|
||||
**If Level 1 works:** Don't build hook system
|
||||
|
||||
**If Level 1 insufficient:** Build hook system (Level 3)
|
||||
</verification_checklist>
|
||||
|
||||
<integration>
|
||||
**This skill covers:** Skill activation strategies
|
||||
|
||||
**Related skills:**
|
||||
- hyperpowers:building-hooks (how to build hook system)
|
||||
- hyperpowers:using-hyper (when to use skills generally)
|
||||
- hyperpowers:writing-skills (creating skills that activate well)
|
||||
|
||||
**This skill enables:**
|
||||
- Consistent enforcement of patterns
|
||||
- Automatic guideline checking
|
||||
- Reliable skill usage across sessions
|
||||
|
||||
**Hyperpowers includes:** Auto-activation hook at `hooks/user-prompt-submit/10-skill-activator.js`
|
||||
</integration>
|
||||
|
||||
<resources>
|
||||
**Detailed implementation:**
|
||||
- [Complete working hook code](resources/hook-implementation.md)
|
||||
- [skill-rules.json examples](resources/skill-rules-examples.md)
|
||||
- [Troubleshooting guide](resources/troubleshooting.md)
|
||||
|
||||
**Official documentation:**
|
||||
- [Anthropic Skills Best Practices](https://docs.claude.com/en/docs/agents-and-tools/agent-skills/best-practices)
|
||||
- [Claude Code Hooks Guide](https://docs.claude.com/en/docs/claude-code/hooks-guide)
|
||||
|
||||
**When stuck:**
|
||||
- Skills still not activating → Check Settings > Capabilities
|
||||
- Hook not working → Check ~/.claude/logs/hooks.log
|
||||
- Over-activation → Reduce keywords, increase priority thresholds
|
||||
- Under-activation → Add more keywords, broaden intent patterns
|
||||
</resources>
|
||||
655
skills/skills-auto-activation/resources/hook-implementation.md
Normal file
655
skills/skills-auto-activation/resources/hook-implementation.md
Normal 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.
|
||||
443
skills/skills-auto-activation/resources/skill-rules-examples.md
Normal file
443
skills/skills-auto-activation/resources/skill-rules-examples.md
Normal 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
|
||||
557
skills/skills-auto-activation/resources/troubleshooting.md
Normal file
557
skills/skills-auto-activation/resources/troubleshooting.md
Normal 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
|
||||
Reference in New Issue
Block a user