claude_hooks 1.0.2 → 1.2.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.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/.agents/skills/ci-monitoring/SKILL.md +103 -0
  3. data/.agents/skills/run-tests/SKILL.md +45 -0
  4. data/.claude/auto-fix.md +7 -0
  5. data/.claude/settings.local.json +21 -0
  6. data/AGENTS.md +46 -0
  7. data/CHANGELOG.md +93 -0
  8. data/README.md +159 -21
  9. data/docs/1.1.0_UPGRADE_GUIDE.md +269 -0
  10. data/docs/API/COMMON.md +7 -0
  11. data/docs/API/CONFIG_CHANGE.md +39 -0
  12. data/docs/API/CWD_CHANGED.md +34 -0
  13. data/docs/API/ELICITATION.md +44 -0
  14. data/docs/API/ELICITATION_RESULT.md +43 -0
  15. data/docs/API/FILE_CHANGED.md +37 -0
  16. data/docs/API/INSTRUCTIONS_LOADED.md +30 -0
  17. data/docs/API/MESSAGE_DISPLAY.md +38 -0
  18. data/docs/API/NOTIFICATION.md +1 -0
  19. data/docs/API/PERMISSION_DENIED.md +37 -0
  20. data/docs/API/PERMISSION_REQUEST.md +199 -0
  21. data/docs/API/POST_COMPACT.md +30 -0
  22. data/docs/API/POST_TOOL_BATCH.md +39 -0
  23. data/docs/API/POST_TOOL_USE.md +1 -0
  24. data/docs/API/POST_TOOL_USE_FAILURE.md +31 -0
  25. data/docs/API/PRE_COMPACT.md +10 -2
  26. data/docs/API/PRE_TOOL_USE.md +9 -1
  27. data/docs/API/SETUP.md +37 -0
  28. data/docs/API/STOP_FAILURE.md +19 -0
  29. data/docs/API/SUBAGENT_START.md +40 -0
  30. data/docs/API/TASK_COMPLETED.md +43 -0
  31. data/docs/API/TASK_CREATED.md +43 -0
  32. data/docs/API/TEAMMATE_IDLE.md +40 -0
  33. data/docs/API/USER_PROMPT_EXPANSION.md +43 -0
  34. data/docs/API/WORKTREE_CREATE.md +39 -0
  35. data/docs/API/WORKTREE_REMOVE.md +33 -0
  36. data/docs/PROMPT_BASED_HOOKS.md +386 -0
  37. data/docs/external/claude-hooks-reference.md +2846 -18
  38. data/docs/mitts/ideabox.md +12 -0
  39. data/docs/mitts/prd.md +417 -0
  40. data/docs/mitts/setup.md +303 -0
  41. data/docs/mitts/task.md +44 -0
  42. data/lib/claude_hooks/base.rb +30 -1
  43. data/lib/claude_hooks/config_change.rb +28 -0
  44. data/lib/claude_hooks/cwd_changed.rb +28 -0
  45. data/lib/claude_hooks/elicitation.rb +61 -0
  46. data/lib/claude_hooks/elicitation_result.rb +57 -0
  47. data/lib/claude_hooks/file_changed.rb +41 -0
  48. data/lib/claude_hooks/instructions_loaded.rb +23 -0
  49. data/lib/claude_hooks/message_display.rb +58 -0
  50. data/lib/claude_hooks/notification.rb +5 -1
  51. data/lib/claude_hooks/output/base.rb +48 -1
  52. data/lib/claude_hooks/output/config_change.rb +47 -0
  53. data/lib/claude_hooks/output/cwd_changed.rb +42 -0
  54. data/lib/claude_hooks/output/elicitation.rb +67 -0
  55. data/lib/claude_hooks/output/elicitation_result.rb +63 -0
  56. data/lib/claude_hooks/output/file_changed.rb +42 -0
  57. data/lib/claude_hooks/output/instructions_loaded.rb +19 -0
  58. data/lib/claude_hooks/output/message_display.rb +49 -0
  59. data/lib/claude_hooks/output/permission_denied.rb +42 -0
  60. data/lib/claude_hooks/output/permission_request.rb +120 -0
  61. data/lib/claude_hooks/output/post_compact.rb +18 -0
  62. data/lib/claude_hooks/output/post_tool_batch.rb +51 -0
  63. data/lib/claude_hooks/output/post_tool_use.rb +12 -0
  64. data/lib/claude_hooks/output/post_tool_use_failure.rb +42 -0
  65. data/lib/claude_hooks/output/pre_compact.rb +34 -3
  66. data/lib/claude_hooks/output/pre_tool_use.rb +26 -2
  67. data/lib/claude_hooks/output/session_start.rb +30 -8
  68. data/lib/claude_hooks/output/setup.rb +42 -0
  69. data/lib/claude_hooks/output/stop.rb +15 -0
  70. data/lib/claude_hooks/output/stop_failure.rb +19 -0
  71. data/lib/claude_hooks/output/subagent_start.rb +42 -0
  72. data/lib/claude_hooks/output/task_completed.rb +18 -0
  73. data/lib/claude_hooks/output/task_created.rb +18 -0
  74. data/lib/claude_hooks/output/teammate_idle.rb +18 -0
  75. data/lib/claude_hooks/output/user_prompt_expansion.rb +51 -0
  76. data/lib/claude_hooks/output/worktree_create.rb +60 -0
  77. data/lib/claude_hooks/output/worktree_remove.rb +19 -0
  78. data/lib/claude_hooks/permission_denied.rb +41 -0
  79. data/lib/claude_hooks/permission_request.rb +63 -0
  80. data/lib/claude_hooks/post_compact.rb +23 -0
  81. data/lib/claude_hooks/post_tool_batch.rb +59 -0
  82. data/lib/claude_hooks/post_tool_use.rb +15 -1
  83. data/lib/claude_hooks/post_tool_use_failure.rb +45 -0
  84. data/lib/claude_hooks/pre_compact.rb +7 -0
  85. data/lib/claude_hooks/pre_tool_use.rb +34 -1
  86. data/lib/claude_hooks/session_start.rb +28 -0
  87. data/lib/claude_hooks/setup.rb +25 -0
  88. data/lib/claude_hooks/stop.rb +17 -0
  89. data/lib/claude_hooks/stop_failure.rb +27 -0
  90. data/lib/claude_hooks/subagent_start.rb +23 -0
  91. data/lib/claude_hooks/subagent_stop.rb +5 -1
  92. data/lib/claude_hooks/task_completed.rb +35 -0
  93. data/lib/claude_hooks/task_created.rb +35 -0
  94. data/lib/claude_hooks/teammate_idle.rb +23 -0
  95. data/lib/claude_hooks/user_prompt_expansion.rb +45 -0
  96. data/lib/claude_hooks/version.rb +1 -1
  97. data/lib/claude_hooks/worktree_create.rb +27 -0
  98. data/lib/claude_hooks/worktree_remove.rb +19 -0
  99. data/lib/claude_hooks.rb +42 -0
  100. metadata +76 -2
@@ -0,0 +1,33 @@
1
+ # WorktreeRemove API
2
+
3
+ Available when inheriting from `ClaudeHooks::WorktreeRemove`:
4
+
5
+ Runs when a git worktree is removed. Non-blocking — only `suppressOutput` is honored.
6
+
7
+ ## Input Helpers
8
+
9
+ [📚 Shared input helpers](COMMON.md#input-helpers)
10
+
11
+ | Method | Description |
12
+ |--------|-------------|
13
+ | `worktree_path` | The path of the worktree being removed |
14
+
15
+ ## Hook State Helpers
16
+
17
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
18
+
19
+ | Method | Description |
20
+ |--------|-------------|
21
+ | `suppress_output!` | Hide this hook's `STDOUT` from transcript mode (the only honored output control) |
22
+
23
+ ## Output Helpers
24
+
25
+ [📚 Shared output helpers](COMMON.md#output-helpers)
26
+
27
+ | Method | Description |
28
+ |--------|-------------|
29
+ | `output.suppress_output?` | Whether output is suppressed |
30
+
31
+ ## Hook Exit Codes
32
+
33
+ Non-blocking. Exit code is ignored; only `suppressOutput` affects behavior.
@@ -0,0 +1,386 @@
1
+ # Prompt-Based Hooks
2
+
3
+ Claude Code supports two types of hooks: **command hooks** and **prompt-based hooks**. This guide explains prompt-based hooks and how they differ from traditional command hooks.
4
+
5
+ ## What are Prompt-Based Hooks?
6
+
7
+ Prompt-based hooks (`type: "prompt"`) delegate decision-making to an LLM (Haiku) instead of executing a bash command. When a hook event occurs, Claude Code sends your prompt and the hook input to the LLM, which responds with structured JSON containing a decision.
8
+
9
+ ## How They Work
10
+
11
+ ```mermaid
12
+ graph LR
13
+ A[Hook Event] --> B[Claude Code sends<br/>prompt + hook input<br/>to Haiku]
14
+ B --> C[LLM evaluates<br/>and responds<br/>with JSON]
15
+ C --> D[Claude Code<br/>processes decision]
16
+ ```
17
+
18
+ ## Configuration
19
+
20
+ In your `.claude/settings.json`:
21
+
22
+ ```json
23
+ {
24
+ "hooks": {
25
+ "Stop": [
26
+ {
27
+ "hooks": [
28
+ {
29
+ "type": "prompt",
30
+ "prompt": "Evaluate if Claude should stop: $ARGUMENTS. Check if all tasks are complete.",
31
+ "timeout": 30
32
+ }
33
+ ]
34
+ }
35
+ ]
36
+ }
37
+ }
38
+ ```
39
+
40
+ **Fields:**
41
+ - `type`: Must be `"prompt"` (vs. `"command"` for bash hooks)
42
+ - `prompt`: The prompt text to send to the LLM
43
+ - Use `$ARGUMENTS` as a placeholder for the hook input JSON
44
+ - If `$ARGUMENTS` is not present, input JSON is appended to the prompt
45
+ - `timeout`: (Optional) Timeout in seconds (default: 30)
46
+
47
+ ## Response Schema
48
+
49
+ The LLM must respond with JSON containing:
50
+
51
+ ```json
52
+ {
53
+ "decision": "approve" | "block",
54
+ "reason": "Explanation for the decision",
55
+ "continue": false, // Optional: stops Claude entirely
56
+ "stopReason": "Message shown to user", // Optional: custom stop message
57
+ "systemMessage": "Warning or context" // Optional: shown to user
58
+ }
59
+ ```
60
+
61
+ **Response fields:**
62
+ - `decision`: `"approve"` allows the action, `"block"` prevents it
63
+ - `reason`: Explanation shown to Claude when decision is `"block"`
64
+ - `continue`: (Optional) If `false`, stops Claude's execution entirely
65
+ - `stopReason`: (Optional) Message shown when `continue` is false
66
+ - `systemMessage`: (Optional) Additional message shown to the user
67
+
68
+ ## When to Use Prompt-Based Hooks
69
+
70
+ ### ✅ Use Prompt-Based Hooks For:
71
+ - **Context-aware decisions** - When the decision requires understanding natural language or complex context
72
+ - **Intelligent evaluation** - Determining if a task is complete or if follow-up work is needed
73
+ - **Nuanced judgment** - Situations where simple rules aren't sufficient
74
+ - **Dynamic scenarios** - When decision criteria change based on the current context
75
+
76
+ ### ❌ Use Command Hooks For:
77
+ - **Deterministic rules** - Simple, predictable logic (if X then Y)
78
+ - **Performance-critical operations** - When speed matters (command hooks are faster)
79
+ - **Security-sensitive checks** - When you need full control over the decision logic
80
+ - **Simple pattern matching** - Checking for specific strings, file patterns, etc.
81
+
82
+ ## Comparison: Prompt-Based vs Command Hooks
83
+
84
+ | Feature | Command Hooks (`type: "command"`) | Prompt-Based Hooks (`type: "prompt"`) |
85
+ |---------|-----------------------------------|---------------------------------------|
86
+ | **Execution** | Runs bash script/Ruby code | Queries LLM (Haiku) |
87
+ | **Decision logic** | You implement in code | LLM evaluates context |
88
+ | **Setup complexity** | Requires script file | Configure prompt in settings |
89
+ | **Context awareness** | Limited to script logic | Natural language understanding |
90
+ | **Performance** | Fast (local execution) | Slower (API call to LLM) |
91
+ | **Determinism** | Fully predictable | May vary based on context |
92
+ | **Cost** | Free (local execution) | Uses API tokens |
93
+ | **Use case** | Deterministic rules | Context-aware decisions |
94
+
95
+ ## Supported Hook Events
96
+
97
+ Prompt-based hooks work with any hook event, but are most useful for:
98
+
99
+ - **Stop**: Intelligently decide if Claude should continue working
100
+ - **SubagentStop**: Evaluate if a subagent has completed its task
101
+ - **UserPromptSubmit**: Validate user prompts with LLM assistance
102
+ - **PreToolUse**: Make context-aware permission decisions
103
+ - **PermissionRequest**: Intelligently allow or deny permission dialogs
104
+
105
+ ## Examples
106
+
107
+ ### Example 1: Intelligent Stop Hook
108
+
109
+ This prompt-based hook evaluates whether Claude should stop working by analyzing the conversation context:
110
+
111
+ ```json
112
+ {
113
+ "hooks": {
114
+ "Stop": [
115
+ {
116
+ "hooks": [
117
+ {
118
+ "type": "prompt",
119
+ "prompt": "You are evaluating whether Claude should stop working. Context: $ARGUMENTS\n\nAnalyze the conversation and determine if:\n1. All user-requested tasks are complete\n2. Any errors need to be addressed\n3. Follow-up work is needed\n\nRespond with JSON: {\"decision\": \"approve\" or \"block\", \"reason\": \"your explanation\"}",
120
+ "timeout": 30
121
+ }
122
+ ]
123
+ }
124
+ ]
125
+ }
126
+ }
127
+ ```
128
+
129
+ **When to use:** When you want Claude to continue working if there are incomplete tasks or unresolved errors.
130
+
131
+ ### Example 2: SubagentStop with Custom Logic
132
+
133
+ This hook evaluates whether a subagent has truly completed its assigned task:
134
+
135
+ ```json
136
+ {
137
+ "hooks": {
138
+ "SubagentStop": [
139
+ {
140
+ "hooks": [
141
+ {
142
+ "type": "prompt",
143
+ "prompt": "Evaluate if this subagent should stop. Input: $ARGUMENTS\n\nCheck if:\n- The subagent completed its assigned task\n- Any errors occurred that need fixing\n- Additional context gathering is needed\n\nReturn: {\"decision\": \"approve\" or \"block\", \"reason\": \"explanation\"}"
144
+ }
145
+ ]
146
+ }
147
+ ]
148
+ }
149
+ }
150
+ ```
151
+
152
+ **When to use:** When subagents might stop prematurely without fully completing their assigned work.
153
+
154
+ ### Example 3: Context-Aware PreToolUse
155
+
156
+ This hook uses the LLM to make nuanced decisions about tool usage:
157
+
158
+ ```json
159
+ {
160
+ "hooks": {
161
+ "PreToolUse": [
162
+ {
163
+ "matcher": "Bash|Write|Edit",
164
+ "hooks": [
165
+ {
166
+ "type": "prompt",
167
+ "prompt": "Evaluate this tool use for safety. Tool: $ARGUMENTS\n\nConsider:\n1. Is this a destructive operation?\n2. Does it modify critical files?\n3. Is this part of a reasonable workflow?\n\nRespond: {\"decision\": \"approve\" or \"block\", \"reason\": \"explanation\"}"
168
+ }
169
+ ]
170
+ }
171
+ ]
172
+ }
173
+ }
174
+ ```
175
+
176
+ **When to use:** When you want intelligent, context-aware safety checks beyond simple pattern matching.
177
+
178
+ ## Hybrid Approach: Combining Both Hook Types
179
+
180
+ You can use both command hooks and prompt-based hooks together for the best of both worlds:
181
+
182
+ ```json
183
+ {
184
+ "hooks": {
185
+ "PreToolUse": [
186
+ {
187
+ "matcher": "Bash",
188
+ "hooks": [
189
+ {
190
+ "type": "command",
191
+ "command": "~/.claude/hooks/entrypoints/bash_safety_check.rb"
192
+ },
193
+ {
194
+ "type": "prompt",
195
+ "prompt": "Review this bash command for safety: $ARGUMENTS\n\nIs this safe to execute? Respond with JSON."
196
+ }
197
+ ]
198
+ }
199
+ ]
200
+ }
201
+ }
202
+ ```
203
+
204
+ **Strategy:**
205
+ 1. **Command hook first**: Fast, deterministic checks (pattern matching, blacklists)
206
+ 2. **Prompt hook second**: Contextual evaluation for edge cases
207
+
208
+ This gives you both speed and intelligence!
209
+
210
+ ## Using This Ruby DSL with Prompt-Based Hooks
211
+
212
+ **Important:** Since prompt-based hooks are executed by Claude Code (not your script), you **don't need to use this Ruby DSL for prompt-based hooks**. The DSL is specifically for `type: "command"` hooks.
213
+
214
+ However, you can still use command hooks that leverage LLMs if you want more control:
215
+
216
+ ```ruby
217
+ #!/usr/bin/env ruby
218
+ require 'claude_hooks'
219
+ require 'anthropic' # or other LLM client
220
+
221
+ class IntelligentStopHandler < ClaudeHooks::Stop
222
+ def call
223
+ # You have full control over the LLM interaction
224
+ client = Anthropic::Client.new
225
+
226
+ response = client.messages(
227
+ model: "claude-haiku-4",
228
+ messages: [{
229
+ role: "user",
230
+ content: "Analyze this transcript and decide if Claude should stop: #{read_transcript}"
231
+ }]
232
+ )
233
+
234
+ # Process response and make decision
235
+ if should_continue?(response)
236
+ deny_stop!("More work needed")
237
+ else
238
+ approve_stop!("All tasks complete")
239
+ end
240
+
241
+ output
242
+ end
243
+ end
244
+ ```
245
+
246
+ **When to use command hooks with LLMs:**
247
+ - You need custom LLM interaction logic
248
+ - You want to use a different model or provider
249
+ - You need to combine LLM decisions with other logic
250
+ - You want full control over prompts and responses
251
+
252
+ ## Best Practices
253
+
254
+ ### 1. Be Specific in Prompts
255
+ **❌ Vague:**
256
+ ```json
257
+ {
258
+ "prompt": "Should this continue?"
259
+ }
260
+ ```
261
+
262
+ **✅ Clear:**
263
+ ```json
264
+ {
265
+ "prompt": "Evaluate if Claude should stop working. Context: $ARGUMENTS\n\nCheck if:\n1. All user tasks are complete\n2. No errors remain\n3. No follow-up work is needed\n\nRespond with JSON: {\"decision\": \"approve\" or \"block\", \"reason\": \"explanation\"}"
266
+ }
267
+ ```
268
+
269
+ ### 2. Include Decision Criteria
270
+ Tell the LLM exactly what to consider:
271
+ - List specific factors to evaluate
272
+ - Provide examples of approve vs block scenarios
273
+ - Explain the context and purpose
274
+
275
+ ### 3. Test Your Prompts
276
+ - Verify the LLM makes correct decisions for your use cases
277
+ - Test edge cases and ambiguous scenarios
278
+ - Adjust prompts based on results
279
+
280
+ ### 4. Set Appropriate Timeouts
281
+ - Default is 30 seconds
282
+ - Increase for complex evaluations
283
+ - Decrease for simple checks
284
+
285
+ ### 5. Use for Complex Decisions Only
286
+ - Bash hooks are better for simple, deterministic rules
287
+ - Prompt-based hooks excel at nuanced, context-aware decisions
288
+ - Consider the hybrid approach for best results
289
+
290
+ ### 6. Consider Cost and Performance
291
+ - Each prompt-based hook call uses API tokens
292
+ - Command hooks are free and faster
293
+ - Use prompt hooks where the added intelligence justifies the cost
294
+
295
+ ## Debugging Prompt-Based Hooks
296
+
297
+ Since prompt-based hooks are executed by Claude Code, debugging is different from command hooks:
298
+
299
+ ### 1. Use `--debug` flag
300
+ ```bash
301
+ claude --debug
302
+ ```
303
+ This shows hook execution details in the Claude Code output.
304
+
305
+ ### 2. Check Claude Code logs
306
+ Prompt-based hook decisions and LLM responses are logged by Claude Code.
307
+
308
+ ### 3. Test your prompts separately
309
+ Before adding a prompt-based hook, test your prompt directly with the Claude API to ensure it responds correctly.
310
+
311
+ ### 4. Start simple, then refine
312
+ Begin with a basic prompt, verify it works, then add complexity.
313
+
314
+ ## Migration: From Command Hooks to Prompt-Based Hooks
315
+
316
+ ### Before (Command Hook):
317
+ ```ruby
318
+ #!/usr/bin/env ruby
319
+ require 'claude_hooks'
320
+
321
+ class StopEvaluator < ClaudeHooks::Stop
322
+ def call
323
+ transcript = read_transcript
324
+
325
+ # Simple pattern matching
326
+ if transcript.include?("all tasks complete")
327
+ approve_stop!("Tasks done")
328
+ else
329
+ deny_stop!("Keep working")
330
+ end
331
+
332
+ output
333
+ end
334
+ end
335
+ ```
336
+
337
+ **Settings:**
338
+ ```json
339
+ {
340
+ "hooks": {
341
+ "Stop": [{
342
+ "hooks": [{
343
+ "type": "command",
344
+ "command": "~/.claude/hooks/stop_evaluator.rb"
345
+ }]
346
+ }]
347
+ }
348
+ }
349
+ ```
350
+
351
+ ### After (Prompt-Based Hook):
352
+ ```json
353
+ {
354
+ "hooks": {
355
+ "Stop": [
356
+ {
357
+ "hooks": [
358
+ {
359
+ "type": "prompt",
360
+ "prompt": "Evaluate if Claude should stop. Context: $ARGUMENTS\n\nCheck if all user tasks are complete or if more work is needed.\n\nRespond: {\"decision\": \"approve\" or \"block\", \"reason\": \"explanation\"}"
361
+ }
362
+ ]
363
+ }
364
+ ]
365
+ }
366
+ }
367
+ ```
368
+
369
+ **Benefits of migration:**
370
+ - No Ruby script to maintain
371
+ - More intelligent, context-aware decisions
372
+ - Simpler configuration
373
+
374
+ **Tradeoffs:**
375
+ - Slower (API call)
376
+ - Uses API tokens
377
+ - Less deterministic
378
+
379
+ ## Summary
380
+
381
+ Prompt-based hooks are a powerful addition to Claude Code that enable intelligent, context-aware decision-making. Use them when:
382
+ - Simple rules aren't sufficient
383
+ - You need natural language understanding
384
+ - Context and nuance matter
385
+
386
+ For everything else, stick with fast, deterministic command hooks or use this Ruby DSL for full control!