@codihaus/claude-skills 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -2
- package/skills/debrief/SKILL.md +10 -7
- package/skills/debrief/scripts/generate_questionnaire.py +0 -0
- package/skills/dev-coding/SKILL.md +302 -22
- package/skills/dev-coding-backend/SKILL.md +15 -1
- package/skills/dev-coding-backend/references/fundamentals.md +428 -0
- package/skills/dev-coding-frontend/SKILL.md +17 -1
- package/skills/dev-coding-frontend/references/fundamentals.md +577 -0
- package/skills/dev-scout/SKILL.md +36 -1
- package/skills/dev-specs/SKILL.md +25 -6
- package/src/commands/init.js +84 -13
- package/src/utils/config.js +54 -3
- package/src/utils/deps.js +164 -9
- package/src/utils/skills.js +27 -0
- package/templates/HOOK_TRIGGER_TEST.md +143 -0
- package/templates/hooks-guide.md +372 -0
- package/templates/scripts/safe-graph-update.sh +65 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
# Claude Code Hooks Configuration Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Hooks allow you to run commands automatically in response to Claude Code events. However, **poorly configured hooks can cause infinite retry loops** and block your workflow.
|
|
6
|
+
|
|
7
|
+
## Hook Failure Problem
|
|
8
|
+
|
|
9
|
+
**Symptom**: Hook fails repeatedly (>10 times) without stopping
|
|
10
|
+
**Impact**:
|
|
11
|
+
- Wastes resources
|
|
12
|
+
- Slows down workflow
|
|
13
|
+
- Can cause infinite loops
|
|
14
|
+
- Blocks Claude from proceeding
|
|
15
|
+
|
|
16
|
+
**Root Cause**: Missing retry limits and failure handling
|
|
17
|
+
|
|
18
|
+
## Best Practices
|
|
19
|
+
|
|
20
|
+
### 1. Always Add Retry Limits
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"postToolUse": [{
|
|
25
|
+
"matcher": {
|
|
26
|
+
"toolName": "Write|Edit",
|
|
27
|
+
"path": "plans/**/*.md"
|
|
28
|
+
},
|
|
29
|
+
"command": "bash .claude/scripts/safe-graph-update.sh $PATH",
|
|
30
|
+
"retries": {
|
|
31
|
+
"maxAttempts": 3,
|
|
32
|
+
"backoff": "exponential",
|
|
33
|
+
"failureAction": "warn"
|
|
34
|
+
},
|
|
35
|
+
"timeout": 5000
|
|
36
|
+
}]
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Key Fields:**
|
|
41
|
+
- `maxAttempts`: Stop after N failures (recommended: 2-3)
|
|
42
|
+
- `backoff`: Wait strategy ("none", "linear", "exponential")
|
|
43
|
+
- `failureAction`: What to do after max attempts
|
|
44
|
+
- `"warn"` - Show warning, continue (recommended)
|
|
45
|
+
- `"error"` - Stop and ask user for help
|
|
46
|
+
- `"ignore"` - Silent failure (not recommended)
|
|
47
|
+
- `timeout`: Kill hook after N milliseconds (recommended: 5000-10000)
|
|
48
|
+
|
|
49
|
+
### 2. Make Commands Fail Gracefully
|
|
50
|
+
|
|
51
|
+
Always append `|| true` to prevent hook failures from blocking:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Good - fails gracefully
|
|
55
|
+
python3 scripts/graph.py --check-path $PATH || true
|
|
56
|
+
|
|
57
|
+
# Bad - failure blocks Claude
|
|
58
|
+
python3 scripts/graph.py --check-path $PATH
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 3. Add Timeout Guards
|
|
62
|
+
|
|
63
|
+
Protect against hanging commands:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"command": "timeout 10s python3 scripts/graph.py --check-path $PATH || true",
|
|
68
|
+
"timeout": 15000
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Double protection:
|
|
73
|
+
- `timeout 10s` - Linux/macOS command-level timeout
|
|
74
|
+
- `"timeout": 15000` - Claude Code timeout (slightly longer as buffer)
|
|
75
|
+
|
|
76
|
+
### 4. Use Specific Path Matchers
|
|
77
|
+
|
|
78
|
+
Match only the files that need processing to avoid unnecessary hook runs:
|
|
79
|
+
|
|
80
|
+
| Pattern | Matches | Use Case |
|
|
81
|
+
|---------|---------|----------|
|
|
82
|
+
| `plans/**/*` | All files in plans/ | ❌ Too broad - includes images, xlsx, etc. |
|
|
83
|
+
| `plans/**/*.md` | Only .md files in plans/ | ✅ Good - documentation only |
|
|
84
|
+
| `plans/brd/**/*.md` | Only .md in plans/brd/ | ✅ More specific |
|
|
85
|
+
| `*.md` | All .md files | ❌ Too broad - includes root README.md |
|
|
86
|
+
| `**/*.md` | All .md files anywhere | ❌ Too broad - performance issue |
|
|
87
|
+
|
|
88
|
+
**Why specificity matters:**
|
|
89
|
+
```
|
|
90
|
+
Bad: path: "plans/**/*"
|
|
91
|
+
→ Triggers on: .md, .xlsx, .png, .json (wastes resources)
|
|
92
|
+
→ Hook runs 100 times when only 20 needed
|
|
93
|
+
|
|
94
|
+
Good: path: "plans/**/*.md"
|
|
95
|
+
→ Triggers on: .md only
|
|
96
|
+
→ Hook runs 20 times, saves 80% of executions
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Example - Multiple patterns:**
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"postToolUse": [
|
|
103
|
+
{
|
|
104
|
+
"matcher": {
|
|
105
|
+
"toolName": "Write|Edit",
|
|
106
|
+
"path": "plans/**/*.md"
|
|
107
|
+
},
|
|
108
|
+
"command": "bash .claude/scripts/safe-graph-update.sh $PATH"
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"matcher": {
|
|
112
|
+
"toolName": "Write",
|
|
113
|
+
"path": "src/**/*.ts"
|
|
114
|
+
},
|
|
115
|
+
"command": "npm run lint-staged"
|
|
116
|
+
}
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### 5. Keep Hooks Fast
|
|
122
|
+
|
|
123
|
+
| Duration | Recommendation |
|
|
124
|
+
|----------|----------------|
|
|
125
|
+
| < 1s | Excellent |
|
|
126
|
+
| 1-2s | Good |
|
|
127
|
+
| 2-5s | Acceptable |
|
|
128
|
+
| > 5s | Too slow - optimize or make async |
|
|
129
|
+
|
|
130
|
+
**Slow hooks block your workflow.** If a hook needs > 5s, consider:
|
|
131
|
+
- Running it on-demand instead of as a hook
|
|
132
|
+
- Making it asynchronous
|
|
133
|
+
- Optimizing the script
|
|
134
|
+
|
|
135
|
+
### 5. Add Dependency Checks
|
|
136
|
+
|
|
137
|
+
Check if required tools exist before running:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"command": "command -v python3 >/dev/null 2>&1 && python3 scripts/graph.py --check-path $PATH || true"
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Or use a wrapper script:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
#!/bin/bash
|
|
149
|
+
# .claude/scripts/safe-graph-update.sh
|
|
150
|
+
|
|
151
|
+
if ! command -v python3 &> /dev/null; then
|
|
152
|
+
echo "Python3 not found, skipping graph update"
|
|
153
|
+
exit 0
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
if [ ! -f "scripts/graph.py" ]; then
|
|
157
|
+
echo "graph.py not found, skipping"
|
|
158
|
+
exit 0
|
|
159
|
+
fi
|
|
160
|
+
|
|
161
|
+
timeout 10s python3 scripts/graph.py --check-path "$1" || true
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Then in hooks.json:
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"command": "bash .claude/scripts/safe-graph-update.sh $PATH"
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Failure Action Strategy
|
|
172
|
+
|
|
173
|
+
Choose the right `failureAction` based on hook criticality:
|
|
174
|
+
|
|
175
|
+
| Hook Type | Criticality | Recommended Action |
|
|
176
|
+
|-----------|-------------|-------------------|
|
|
177
|
+
| Documentation updates (graph.py) | Low | `"warn"` - Show warning, continue |
|
|
178
|
+
| Linting/formatting | Medium | `"warn"` - Show warning, continue |
|
|
179
|
+
| Security checks | High | `"error"` - Stop and ask user |
|
|
180
|
+
| Required validations | Critical | `"error"` - Stop and ask user |
|
|
181
|
+
|
|
182
|
+
**Example - Non-critical hook:**
|
|
183
|
+
```json
|
|
184
|
+
{
|
|
185
|
+
"command": "python3 scripts/graph.py --check-path $PATH || true",
|
|
186
|
+
"retries": {
|
|
187
|
+
"maxAttempts": 3,
|
|
188
|
+
"failureAction": "warn"
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Example - Critical hook:**
|
|
194
|
+
```json
|
|
195
|
+
{
|
|
196
|
+
"command": "npm run validate-security",
|
|
197
|
+
"retries": {
|
|
198
|
+
"maxAttempts": 2,
|
|
199
|
+
"failureAction": "error"
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Debugging Hook Failures
|
|
205
|
+
|
|
206
|
+
If a hook keeps failing:
|
|
207
|
+
|
|
208
|
+
### 1. Check Hook Logs
|
|
209
|
+
|
|
210
|
+
Claude Code logs hook output. Look for:
|
|
211
|
+
```
|
|
212
|
+
[Hook Failed] postToolUse: python3 scripts/graph.py
|
|
213
|
+
Exit code: 1
|
|
214
|
+
Stderr: ModuleNotFoundError: No module named 'networkx'
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### 2. Test Command Manually
|
|
218
|
+
|
|
219
|
+
Run the hook command directly:
|
|
220
|
+
```bash
|
|
221
|
+
cd /path/to/project
|
|
222
|
+
python3 scripts/graph.py --check-path plans/brd/README.md
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### 3. Common Issues
|
|
226
|
+
|
|
227
|
+
| Error | Cause | Fix |
|
|
228
|
+
|-------|-------|-----|
|
|
229
|
+
| `ModuleNotFoundError` | Missing Python package | Install: `pip3 install --user <package>` |
|
|
230
|
+
| `command not found` | Tool not installed | Install tool or remove hook |
|
|
231
|
+
| `Permission denied` | Script not executable | `chmod +x scripts/*.sh` |
|
|
232
|
+
| `Timeout` | Script too slow | Optimize script or increase timeout |
|
|
233
|
+
| `File not found` | Path mismatch | Check $PATH variable substitution |
|
|
234
|
+
|
|
235
|
+
### 4. Temporary Disable
|
|
236
|
+
|
|
237
|
+
To temporarily disable a problematic hook:
|
|
238
|
+
|
|
239
|
+
```json
|
|
240
|
+
{
|
|
241
|
+
"postToolUse": [
|
|
242
|
+
{
|
|
243
|
+
"matcher": {
|
|
244
|
+
"toolName": "Write|Edit",
|
|
245
|
+
"path": "plans/**/*"
|
|
246
|
+
},
|
|
247
|
+
"command": "python3 scripts/graph.py --check-path $PATH || true",
|
|
248
|
+
"enabled": false
|
|
249
|
+
}
|
|
250
|
+
]
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Or delete `.claude/hooks.json` entirely (hooks are optional).
|
|
255
|
+
|
|
256
|
+
## Example: Robust Hook Configuration
|
|
257
|
+
|
|
258
|
+
```json
|
|
259
|
+
{
|
|
260
|
+
"postToolUse": [
|
|
261
|
+
{
|
|
262
|
+
"matcher": {
|
|
263
|
+
"toolName": "Write|Edit",
|
|
264
|
+
"path": "plans/**/*"
|
|
265
|
+
},
|
|
266
|
+
"command": "bash .claude/scripts/safe-graph-update.sh $PATH",
|
|
267
|
+
"retries": {
|
|
268
|
+
"maxAttempts": 3,
|
|
269
|
+
"backoff": "exponential",
|
|
270
|
+
"failureAction": "warn"
|
|
271
|
+
},
|
|
272
|
+
"timeout": 10000,
|
|
273
|
+
"enabled": true
|
|
274
|
+
}
|
|
275
|
+
],
|
|
276
|
+
"preToolUse": [],
|
|
277
|
+
"onError": []
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
With `.claude/scripts/safe-graph-update.sh`:
|
|
282
|
+
```bash
|
|
283
|
+
#!/bin/bash
|
|
284
|
+
set -e
|
|
285
|
+
|
|
286
|
+
# Exit early if tools missing
|
|
287
|
+
command -v python3 >/dev/null 2>&1 || exit 0
|
|
288
|
+
|
|
289
|
+
# Exit early if script missing
|
|
290
|
+
[ -f "scripts/graph.py" ] || exit 0
|
|
291
|
+
|
|
292
|
+
# Run with timeout and graceful failure
|
|
293
|
+
timeout 10s python3 scripts/graph.py --check-path "$1" || {
|
|
294
|
+
echo "Graph update failed (non-critical), continuing..."
|
|
295
|
+
exit 0
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## Migration Guide
|
|
300
|
+
|
|
301
|
+
### Old Configuration (Problematic)
|
|
302
|
+
|
|
303
|
+
```json
|
|
304
|
+
{
|
|
305
|
+
"postToolUse": [{
|
|
306
|
+
"matcher": { "toolName": "Write|Edit", "path": "plans/**/*" },
|
|
307
|
+
"command": "python3 scripts/graph.py --check-path $PATH"
|
|
308
|
+
}]
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
**Problems:**
|
|
313
|
+
- ❌ No retry limit (infinite retries)
|
|
314
|
+
- ❌ No timeout (can hang forever)
|
|
315
|
+
- ❌ Failures block Claude
|
|
316
|
+
- ❌ Too broad path matcher (triggers on images, xlsx, etc.)
|
|
317
|
+
|
|
318
|
+
### New Configuration (Robust)
|
|
319
|
+
|
|
320
|
+
```json
|
|
321
|
+
{
|
|
322
|
+
"postToolUse": [{
|
|
323
|
+
"matcher": { "toolName": "Write|Edit", "path": "plans/**/*.md" },
|
|
324
|
+
"command": "bash .claude/scripts/safe-graph-update.sh $PATH",
|
|
325
|
+
"retries": {
|
|
326
|
+
"maxAttempts": 3,
|
|
327
|
+
"backoff": "exponential",
|
|
328
|
+
"failureAction": "warn"
|
|
329
|
+
},
|
|
330
|
+
"timeout": 5000
|
|
331
|
+
}]
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
**Improvements:**
|
|
336
|
+
- ✅ Max 3 retry attempts (stops infinite loops)
|
|
337
|
+
- ✅ 5 second timeout per attempt (prevents hanging)
|
|
338
|
+
- ✅ Exponential backoff between retries (less aggressive)
|
|
339
|
+
- ✅ Warns but doesn't block on failure (non-blocking)
|
|
340
|
+
- ✅ Specific path matcher `**/*.md` (only markdown files)
|
|
341
|
+
- ✅ Safe wrapper script with multiple protections
|
|
342
|
+
|
|
343
|
+
## When to Ask User for Help
|
|
344
|
+
|
|
345
|
+
Configure `"failureAction": "error"` when:
|
|
346
|
+
1. Hook has failed `maxAttempts` times
|
|
347
|
+
2. Issue is not automatically fixable
|
|
348
|
+
3. User intervention is needed
|
|
349
|
+
4. Hook is critical to workflow
|
|
350
|
+
|
|
351
|
+
Claude Code will then:
|
|
352
|
+
1. Stop execution
|
|
353
|
+
2. Show error message with hook details
|
|
354
|
+
3. Ask: "Hook 'postToolUse:graph.py' failed 3 times. What would you like to do?"
|
|
355
|
+
- Fix and retry
|
|
356
|
+
- Skip this hook
|
|
357
|
+
- Disable hook permanently
|
|
358
|
+
- Continue without hook
|
|
359
|
+
|
|
360
|
+
## Summary Checklist
|
|
361
|
+
|
|
362
|
+
When configuring hooks, ensure:
|
|
363
|
+
|
|
364
|
+
- [ ] `maxAttempts` set (2-3 recommended)
|
|
365
|
+
- [ ] `timeout` set (5000-10000ms recommended)
|
|
366
|
+
- [ ] `failureAction` appropriate for criticality
|
|
367
|
+
- [ ] Command ends with `|| true` for graceful failure
|
|
368
|
+
- [ ] Hook completes in < 2 seconds ideally
|
|
369
|
+
- [ ] Dependencies checked before execution
|
|
370
|
+
- [ ] Tested manually before committing
|
|
371
|
+
|
|
372
|
+
**Remember**: Hooks are helpers, not requirements. It's better to have no hook than a broken one that blocks your workflow.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# Safe Graph Update Wrapper
|
|
4
|
+
#
|
|
5
|
+
# This script provides resilient execution of graph.py with:
|
|
6
|
+
# - Dependency checking
|
|
7
|
+
# - Graceful failure handling
|
|
8
|
+
# - Timeout protection
|
|
9
|
+
# - Clear error messages
|
|
10
|
+
#
|
|
11
|
+
|
|
12
|
+
set -e
|
|
13
|
+
|
|
14
|
+
# Configuration
|
|
15
|
+
TIMEOUT_SECONDS=10
|
|
16
|
+
GRAPH_SCRIPT="scripts/graph.py"
|
|
17
|
+
MAX_RETRIES=0 # Let Claude Code handle retries
|
|
18
|
+
|
|
19
|
+
# Colors for output (optional)
|
|
20
|
+
RED='\033[0;31m'
|
|
21
|
+
YELLOW='\033[1;33m'
|
|
22
|
+
GREEN='\033[0;32m'
|
|
23
|
+
NC='\033[0m' # No Color
|
|
24
|
+
|
|
25
|
+
# Check if Python3 is available
|
|
26
|
+
if ! command -v python3 &> /dev/null; then
|
|
27
|
+
echo -e "${YELLOW}Python3 not found. Skipping graph update.${NC}" >&2
|
|
28
|
+
exit 0
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# Check if graph.py exists
|
|
32
|
+
if [ ! -f "$GRAPH_SCRIPT" ]; then
|
|
33
|
+
echo -e "${YELLOW}$GRAPH_SCRIPT not found. Skipping graph update.${NC}" >&2
|
|
34
|
+
exit 0
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# Get the file path argument
|
|
38
|
+
FILE_PATH="$1"
|
|
39
|
+
|
|
40
|
+
if [ -z "$FILE_PATH" ]; then
|
|
41
|
+
echo -e "${YELLOW}No file path provided. Skipping graph update.${NC}" >&2
|
|
42
|
+
exit 0
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# Only update graph for .md files in plans/ directory
|
|
46
|
+
if [[ ! "$FILE_PATH" =~ ^plans/.*\.md$ ]]; then
|
|
47
|
+
exit 0
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Run graph.py with timeout
|
|
51
|
+
if timeout "$TIMEOUT_SECONDS" python3 "$GRAPH_SCRIPT" --check-path "$FILE_PATH" 2>/dev/null; then
|
|
52
|
+
# Success - silent
|
|
53
|
+
exit 0
|
|
54
|
+
else
|
|
55
|
+
EXIT_CODE=$?
|
|
56
|
+
if [ $EXIT_CODE -eq 124 ]; then
|
|
57
|
+
# Timeout
|
|
58
|
+
echo -e "${YELLOW}Graph update timed out after ${TIMEOUT_SECONDS}s (non-critical).${NC}" >&2
|
|
59
|
+
elif [ $EXIT_CODE -ne 0 ]; then
|
|
60
|
+
# Other error
|
|
61
|
+
echo -e "${YELLOW}Graph update failed with exit code $EXIT_CODE (non-critical).${NC}" >&2
|
|
62
|
+
fi
|
|
63
|
+
# Always exit 0 to prevent blocking Claude
|
|
64
|
+
exit 0
|
|
65
|
+
fi
|