@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.
@@ -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