claude_hooks 1.1.0 → 1.2.1

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 (101) 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/AGENTS.md +46 -0
  5. data/CHANGELOG.md +64 -0
  6. data/README.md +303 -239
  7. data/docs/1.0.0_MIGRATION_GUIDE.md +6 -7
  8. data/docs/API/COMMON.md +7 -1
  9. data/docs/API/CONFIG_CHANGE.md +39 -0
  10. data/docs/API/CWD_CHANGED.md +34 -0
  11. data/docs/API/ELICITATION.md +44 -0
  12. data/docs/API/ELICITATION_RESULT.md +43 -0
  13. data/docs/API/FILE_CHANGED.md +37 -0
  14. data/docs/API/INSTRUCTIONS_LOADED.md +30 -0
  15. data/docs/API/MESSAGE_DISPLAY.md +38 -0
  16. data/docs/API/PERMISSION_DENIED.md +37 -0
  17. data/docs/API/PERMISSION_REQUEST.md +11 -8
  18. data/docs/API/POST_COMPACT.md +30 -0
  19. data/docs/API/POST_TOOL_BATCH.md +39 -0
  20. data/docs/API/POST_TOOL_USE_FAILURE.md +31 -0
  21. data/docs/API/PRE_COMPACT.md +10 -2
  22. data/docs/API/PRE_TOOL_USE.md +5 -1
  23. data/docs/API/SETUP.md +37 -0
  24. data/docs/API/STOP_FAILURE.md +19 -0
  25. data/docs/API/SUBAGENT_START.md +40 -0
  26. data/docs/API/TASK_COMPLETED.md +43 -0
  27. data/docs/API/TASK_CREATED.md +43 -0
  28. data/docs/API/TEAMMATE_IDLE.md +40 -0
  29. data/docs/API/USER_PROMPT_EXPANSION.md +43 -0
  30. data/docs/API/WORKTREE_CREATE.md +39 -0
  31. data/docs/API/WORKTREE_REMOVE.md +33 -0
  32. data/docs/PROMPT_BASED_HOOKS.md +386 -0
  33. data/docs/external/claude-hooks-reference.md +2406 -854
  34. data/docs/mitts/ideabox.md +12 -0
  35. data/docs/mitts/prd.md +417 -0
  36. data/docs/mitts/setup.md +303 -0
  37. data/docs/mitts/task.md +44 -0
  38. data/example_dotclaude/hooks/entrypoints/session_end.rb +5 -22
  39. data/example_dotclaude/hooks/entrypoints/user_prompt_submit.rb +4 -26
  40. data/example_dotclaude/hooks/{handlers/pre_tool_use/github_guard.rb → github_guard.rb} +7 -13
  41. data/example_dotclaude/settings.json +1 -1
  42. data/lib/claude_hooks/base.rb +25 -0
  43. data/lib/claude_hooks/cli.rb +84 -149
  44. data/lib/claude_hooks/config_change.rb +28 -0
  45. data/lib/claude_hooks/cwd_changed.rb +28 -0
  46. data/lib/claude_hooks/elicitation.rb +61 -0
  47. data/lib/claude_hooks/elicitation_result.rb +57 -0
  48. data/lib/claude_hooks/file_changed.rb +41 -0
  49. data/lib/claude_hooks/instructions_loaded.rb +23 -0
  50. data/lib/claude_hooks/message_display.rb +58 -0
  51. data/lib/claude_hooks/output/base.rb +46 -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 +50 -25
  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 +8 -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 +16 -9
  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 +10 -0
  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 +20 -2
  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 +40 -0
  100. metadata +71 -4
  101. data/example_dotclaude/hooks/entrypoints/pre_tool_use.rb +0 -25
@@ -169,18 +169,17 @@ merged_output.output_and_exit # Handles everything automatically
169
169
 
170
170
  ## Simplified Entrypoint Pattern
171
171
 
172
+ > [!NOTE]
173
+ > As of 1.2.1, `CLI.entrypoint` is deprecated in favour of `CLI.run_hook`. The examples below use the current API. `CLI.entrypoint` still works (with a deprecation warning) but will be removed in a future minor version.
174
+
172
175
  ### For Single Hooks
173
176
  ```ruby
174
177
  #!/usr/bin/env ruby
175
178
  require 'claude_hooks'
176
179
  require_relative '../handlers/my_hook'
177
180
 
178
- # Super simple - just 3 lines!
179
- ClaudeHooks::CLI.entrypoint do |input_data|
180
- hook = MyHook.new(input_data)
181
- hook.call
182
- hook.output_and_exit
183
- end
181
+ # Super simple - just 1 line!
182
+ ClaudeHooks::CLI.run_hook(MyHook)
184
183
  ```
185
184
 
186
185
  ### For Multiple Hooks with Merging
@@ -190,7 +189,7 @@ require 'claude_hooks'
190
189
  require_relative '../handlers/hook1'
191
190
  require_relative '../handlers/hook2'
192
191
 
193
- ClaudeHooks::CLI.entrypoint do |input_data|
192
+ ClaudeHooks::CLI.run_hook do |input_data|
194
193
  hook1 = Hook1.new(input_data)
195
194
  hook2 = Hook2.new(input_data)
196
195
  hook1.call
data/docs/API/COMMON.md CHANGED
@@ -12,7 +12,11 @@ Input helpers to access the data provided by Claude Code through `STDIN`.
12
12
  | `transcript_path` | Get path to the transcript file |
13
13
  | `cwd` | Get current working directory |
14
14
  | `hook_event_name` | Get the hook event name |
15
- | `permission_mode` | Get the permission mode: `'default'`, `'plan'`, `'acceptEdits'`, `'dontAsk'`, `'bypassPermissions'` (defaults to `'default'`) |
15
+ | `permission_mode` | Get the permission mode: `'default'`, `'plan'`, `'acceptEdits'`, `'auto'`, `'dontAsk'`, `'bypassPermissions'` (defaults to `'default'`) |
16
+ | `prompt_id` | Get the current prompt ID |
17
+ | `agent_id` | Get the agent ID (present in subagent contexts) |
18
+ | `agent_type` | Get the agent type (present in subagent contexts) |
19
+ | `effort` | Get the effort level string (reads `effort.level`) |
16
20
  | `read_transcript` | Read the transcript file |
17
21
  | `transcript` | Alias for `read_transcript` |
18
22
 
@@ -28,6 +32,7 @@ Hook state methods are helpers to modify the hook's internal state (`output_data
28
32
  | `clear_specifics!` | Clear hook-specific output |
29
33
  | `system_message!(message)` | Set a system message shown to the user (not to Claude) |
30
34
  | `clear_system_message!` | Clear the system message |
35
+ | `terminal_sequence!(seq)` | Emit an ANSI/terminal escape sequence in the output |
31
36
 
32
37
  ## Output Helpers
33
38
 
@@ -45,6 +50,7 @@ This object provides helpers to access output data, for merging multiple outputs
45
50
  | `output.suppress_output?` | Check if output should be suppressed from transcript |
46
51
  | `output.hook_specific_output` | Get the hook-specific output data |
47
52
  | `output.system_message` | Get the system message if any |
53
+ | `output.terminal_sequence` | Get the terminal escape sequence (if set) |
48
54
 
49
55
  ### Output data merging
50
56
  For each hook type, the `output` object provides a **class method** `merge` that will try to intelligently merge multiple hook results, e.g. `ClaudeHooks::Output::UserPromptSubmit.merge(output1, output2, output3)`.
@@ -0,0 +1,39 @@
1
+ # ConfigChange API
2
+
3
+ Available when inheriting from `ClaudeHooks::ConfigChange`:
4
+
5
+ Runs when Claude Code configuration changes. Can block the change for most sources (note: `policy_settings` changes cannot be blocked).
6
+
7
+ ## Input Helpers
8
+
9
+ [📚 Shared input helpers](COMMON.md#input-helpers)
10
+
11
+ | Method | Description |
12
+ |--------|-------------|
13
+ | `source` | The source of the config change (e.g. `'project'`, `'user'`, `'policy_settings'`) |
14
+ | `file_path` | Path to the changed config file (optional) |
15
+
16
+ ## Hook State Helpers
17
+
18
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
19
+
20
+ | Method | Description |
21
+ |--------|-------------|
22
+ | `block!(reason)` | Block the config change (ineffective for `policy_settings`) |
23
+
24
+ ## Output Helpers
25
+
26
+ [📚 Shared output helpers](COMMON.md#output-helpers)
27
+
28
+ | Method | Description |
29
+ |--------|-------------|
30
+ | `output.blocked?` | Check if the change was blocked |
31
+ | `output.decision` | Get the decision (`'block'` or nil) |
32
+ | `output.reason` | Get the block reason |
33
+
34
+ ## Hook Exit Codes
35
+
36
+ | Exit Code | Behavior |
37
+ |-----------|----------|
38
+ | `exit 0` | Config change proceeds |
39
+ | `exit 2` | Blocks the change; `STDERR` shown to Claude |
@@ -0,0 +1,34 @@
1
+ # CwdChanged API
2
+
3
+ Available when inheriting from `ClaudeHooks::CwdChanged`:
4
+
5
+ Runs when the working directory changes. Can update the list of watched paths.
6
+
7
+ ## Input Helpers
8
+
9
+ [📚 Shared input helpers](COMMON.md#input-helpers)
10
+
11
+ | Method | Description |
12
+ |--------|-------------|
13
+ | `old_cwd` | The previous working directory |
14
+ | `new_cwd` | The new working directory |
15
+
16
+ ## Hook State Helpers
17
+
18
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
19
+
20
+ | Method | Description |
21
+ |--------|-------------|
22
+ | `watch_paths!(paths)` | Set the list of paths Claude Code should watch for changes |
23
+
24
+ ## Output Helpers
25
+
26
+ [📚 Shared output helpers](COMMON.md#output-helpers)
27
+
28
+ | Method | Description |
29
+ |--------|-------------|
30
+ | `output.watch_paths` | Get the configured watch paths |
31
+
32
+ ## Hook Exit Codes
33
+
34
+ Non-blocking. Only `watchPaths` output is consumed.
@@ -0,0 +1,44 @@
1
+ # Elicitation API
2
+
3
+ Available when inheriting from `ClaudeHooks::Elicitation`:
4
+
5
+ Runs when an MCP server requests user input (an elicitation dialog). Can accept, decline, or cancel the request.
6
+
7
+ ## Input Helpers
8
+
9
+ [📚 Shared input helpers](COMMON.md#input-helpers)
10
+
11
+ | Method | Description |
12
+ |--------|-------------|
13
+ | `mcp_server_name` | The MCP server requesting input |
14
+ | `message` | The message / prompt shown to the user |
15
+ | `mode` | Optional interaction mode |
16
+ | `url` | Optional URL associated with the request |
17
+ | `elicitation_id` | Optional unique ID for this elicitation |
18
+ | `requested_schema` | Optional JSON schema describing the expected response |
19
+
20
+ ## Hook State Helpers
21
+
22
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
23
+
24
+ | Method | Description |
25
+ |--------|-------------|
26
+ | `accept!(content = {})` | Accept the elicitation with optional content hash |
27
+ | `decline!` | Decline the elicitation |
28
+ | `cancel!` | Cancel the elicitation |
29
+
30
+ ## Output Helpers
31
+
32
+ [📚 Shared output helpers](COMMON.md#output-helpers)
33
+
34
+ | Method | Description |
35
+ |--------|-------------|
36
+ | `output.action` | Get the chosen action: `'accept'`, `'decline'`, or `'cancel'` |
37
+ | `output.content` | Get the accepted content hash |
38
+ | `output.accepted?` | Check if the elicitation was accepted |
39
+ | `output.declined?` | Check if the elicitation was declined |
40
+ | `output.cancelled?` | Check if the elicitation was cancelled |
41
+
42
+ ## Hook Exit Codes
43
+
44
+ Uses the JSON API (exit 0 / stdout). The `hookSpecificOutput.action` field controls the response.
@@ -0,0 +1,43 @@
1
+ # ElicitationResult API
2
+
3
+ Available when inheriting from `ClaudeHooks::ElicitationResult`:
4
+
5
+ Runs after a user has responded to an elicitation dialog. Can override the action or content before it is sent back to the MCP server.
6
+
7
+ ## Input Helpers
8
+
9
+ [📚 Shared input helpers](COMMON.md#input-helpers)
10
+
11
+ | Method | Description |
12
+ |--------|-------------|
13
+ | `mcp_server_name` | The MCP server that requested input |
14
+ | `action` | The user's chosen action: `'accept'`, `'decline'`, or `'cancel'` |
15
+ | `mode` | Optional interaction mode |
16
+ | `elicitation_id` | Optional unique ID for this elicitation |
17
+ | `content` | The content the user provided (for `'accept'` action) |
18
+
19
+ ## Hook State Helpers
20
+
21
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
22
+
23
+ | Method | Description |
24
+ |--------|-------------|
25
+ | `accept!(content = {})` | Override the response with an accept + content |
26
+ | `decline!` | Override the response to decline |
27
+ | `cancel!` | Override the response to cancel |
28
+
29
+ ## Output Helpers
30
+
31
+ [📚 Shared output helpers](COMMON.md#output-helpers)
32
+
33
+ | Method | Description |
34
+ |--------|-------------|
35
+ | `output.action` | Get the (possibly overridden) action |
36
+ | `output.content` | Get the (possibly overridden) content |
37
+ | `output.accepted?` | Check if the action is `'accept'` |
38
+ | `output.declined?` | Check if the action is `'decline'` |
39
+ | `output.cancelled?` | Check if the action is `'cancel'` |
40
+
41
+ ## Hook Exit Codes
42
+
43
+ Uses the JSON API (exit 0 / stdout).
@@ -0,0 +1,37 @@
1
+ # FileChanged API
2
+
3
+ Available when inheriting from `ClaudeHooks::FileChanged`:
4
+
5
+ Runs when a watched file is created, modified, or deleted. Can update the watch paths list.
6
+
7
+ ## Input Helpers
8
+
9
+ [📚 Shared input helpers](COMMON.md#input-helpers)
10
+
11
+ | Method | Description |
12
+ |--------|-------------|
13
+ | `file_path` | The path of the changed file |
14
+ | `event` | The type of change: `'change'`, `'add'`, or `'unlink'` |
15
+ | `modified?` | Convenience: `event == 'change'` |
16
+ | `created?` | Convenience: `event == 'add'` |
17
+ | `deleted?` | Convenience: `event == 'unlink'` |
18
+
19
+ ## Hook State Helpers
20
+
21
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
22
+
23
+ | Method | Description |
24
+ |--------|-------------|
25
+ | `watch_paths!(paths)` | Update the list of paths Claude Code should watch |
26
+
27
+ ## Output Helpers
28
+
29
+ [📚 Shared output helpers](COMMON.md#output-helpers)
30
+
31
+ | Method | Description |
32
+ |--------|-------------|
33
+ | `output.watch_paths` | Get the configured watch paths |
34
+
35
+ ## Hook Exit Codes
36
+
37
+ Non-blocking. Only `watchPaths` output is consumed.
@@ -0,0 +1,30 @@
1
+ # InstructionsLoaded API
2
+
3
+ Available when inheriting from `ClaudeHooks::InstructionsLoaded`:
4
+
5
+ Runs when a `CLAUDE.md` instructions file is loaded. Non-blocking — exit code is ignored.
6
+
7
+ ## Input Helpers
8
+
9
+ [📚 Shared input helpers](COMMON.md#input-helpers)
10
+
11
+ | Method | Description |
12
+ |--------|-------------|
13
+ | `file_path` | Path to the loaded instructions file |
14
+ | `load_reason` | Why the file was loaded (e.g. `'startup'`, `'cwd_change'`) |
15
+
16
+ ## Hook State Helpers
17
+
18
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
19
+
20
+ No event-specific state methods — this hook is non-blocking.
21
+
22
+ ## Output Helpers
23
+
24
+ [📚 Shared output helpers](COMMON.md#output-helpers)
25
+
26
+ No event-specific output helpers.
27
+
28
+ ## Hook Exit Codes
29
+
30
+ Non-blocking. Exit code is ignored by Claude Code.
@@ -0,0 +1,38 @@
1
+ # MessageDisplay API
2
+
3
+ Available when inheriting from `ClaudeHooks::MessageDisplay`:
4
+
5
+ Runs when a message is about to be displayed. Can override the displayed text via `hookSpecificOutput.displayContent`.
6
+
7
+ ## Input Helpers
8
+
9
+ [📚 Shared input helpers](COMMON.md#input-helpers)
10
+
11
+ | Method | Description |
12
+ |--------|-------------|
13
+ | `turn_id` | ID of the current turn |
14
+ | `message_id` | ID of this message |
15
+ | `index` | Position of this message in the turn |
16
+ | `final` | Whether this is the final message chunk (`true`/`false`) |
17
+ | `delta` | The incremental text content of this message |
18
+ | `message_text` | Alias for `delta` |
19
+
20
+ ## Hook State Helpers
21
+
22
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
23
+
24
+ | Method | Description |
25
+ |--------|-------------|
26
+ | `display_content!(text)` | Override the displayed text for this message |
27
+
28
+ ## Output Helpers
29
+
30
+ [📚 Shared output helpers](COMMON.md#output-helpers)
31
+
32
+ | Method | Description |
33
+ |--------|-------------|
34
+ | `output.display_content` | Get the overridden display content (if set) |
35
+
36
+ ## Hook Exit Codes
37
+
38
+ Exit code and output stream are ignored for MessageDisplay. The only honored output is `hookSpecificOutput.displayContent`.
@@ -0,0 +1,37 @@
1
+ # PermissionDenied API
2
+
3
+ Available when inheriting from `ClaudeHooks::PermissionDenied`:
4
+
5
+ Runs when a permission request is denied. Can request that Claude Code retries the request.
6
+
7
+ ## Input Helpers
8
+
9
+ [📚 Shared input helpers](COMMON.md#input-helpers)
10
+
11
+ | Method | Description |
12
+ |--------|-------------|
13
+ | `tool_name` | The name of the tool whose permission was denied |
14
+ | `tool_input` | The input data for the tool |
15
+ | `tool_use_id` | The unique identifier for this tool use |
16
+ | `reason` | The reason the permission was denied |
17
+
18
+ ## Hook State Helpers
19
+
20
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
21
+
22
+ | Method | Description |
23
+ |--------|-------------|
24
+ | `retry!` | Request that Claude Code retry the permission request |
25
+ | `no_retry!` | Explicitly decline to retry (default) |
26
+
27
+ ## Output Helpers
28
+
29
+ [📚 Shared output helpers](COMMON.md#output-helpers)
30
+
31
+ | Method | Description |
32
+ |--------|-------------|
33
+ | `output.retry?` | Check if a retry was requested |
34
+
35
+ ## Hook Exit Codes
36
+
37
+ Exit code is ignored. Output is via `hookSpecificOutput.retry` (JSON API, exit 0 / stdout).
@@ -21,8 +21,8 @@ Hook state methods are helpers to modify the hook's internal state (`output_data
21
21
  | Method | Description |
22
22
  |--------|-------------|
23
23
  | `allow_permission!(reason = '')` | Allow the permission request with optional reason |
24
- | `deny_permission!(reason = '')` | Deny the permission request with reason |
25
- | `update_input_and_allow!(updated_input, reason = '')` | Update tool input and allow (convenience method) |
24
+ | `deny_permission!(reason = '', interrupt: nil)` | Deny the permission request with reason; pass `interrupt: true` to interrupt the current operation |
25
+ | `update_input_and_allow!(updated_input, reason = '', updated_permissions: nil)` | Update tool input and allow |
26
26
 
27
27
  ## Output Helpers
28
28
  Output helpers provide access to the hook's output data and helper methods for working with the output state.
@@ -34,9 +34,12 @@ Output helpers provide access to the hook's output data and helper methods for w
34
34
  | `output.allowed?` | Check if permission has been allowed |
35
35
  | `output.denied?` | Check if permission has been denied |
36
36
  | `output.input_updated?` | Check if tool input has been updated |
37
- | `output.permission_decision` | Get the permission decision: 'allow' or 'deny' |
38
- | `output.permission_reason` | Get the reason for the permission decision |
39
- | `output.updated_input` | Get the updated input (if provided) |
37
+ | `output.permission_decision` | Get the permission decision: `'allow'` or `'deny'` (reads nested `decision.behavior`; falls back to legacy flat key) |
38
+ | `output.permission_reason` | Get the decision message (reads nested `decision.message`; falls back to legacy `permissionDecisionReason`) |
39
+ | `output.updated_input` | Get the updated input (reads nested `decision.updatedInput`; falls back to legacy flat key) |
40
+ | `output.behavior` | Get the raw `decision.behavior` value |
41
+ | `output.updated_permissions` | Get the `decision.updatedPermissions` array (if provided) |
42
+ | `output.interrupt?` | Check if `decision.interrupt` was set to true |
40
43
 
41
44
  ## Hook Exit Codes
42
45
 
@@ -167,8 +170,8 @@ end
167
170
  When multiple PermissionRequest hooks are executed, their outputs merge with these rules:
168
171
 
169
172
  - **Decision**: `deny` > `allow` (most restrictive wins)
170
- - **Reasons**: All reasons are concatenated with `'; '`
171
- - **Updated Input**: Last updated input wins (most recent transformation)
173
+ - **Reasons**: All `decision.message` values are concatenated with `'; '`
174
+ - **Updated Input**: Last `decision.updatedInput` wins (most recent transformation)
172
175
 
173
176
  ```ruby
174
177
  # Hook 1
@@ -193,4 +196,4 @@ merged.permission_reason # => "Reason 1; Reason 2"
193
196
  - It can automatically allow or deny on behalf of the user
194
197
  - Uses the same JSON API pattern as PreToolUse hooks
195
198
  - Supports modifying tool inputs before execution
196
- - Works with all permission modes: `default`, `plan`, `acceptEdits`, `dontAsk`, `bypassPermissions`
199
+ - Works with all permission modes: `default`, `plan`, `acceptEdits`, `auto`, `dontAsk`, `bypassPermissions`
@@ -0,0 +1,30 @@
1
+ # PostCompact API
2
+
3
+ Available when inheriting from `ClaudeHooks::PostCompact`:
4
+
5
+ Runs after transcript compaction completes. Non-blocking — use for logging or post-compaction side effects.
6
+
7
+ ## Input Helpers
8
+
9
+ [📚 Shared input helpers](COMMON.md#input-helpers)
10
+
11
+ | Method | Description |
12
+ |--------|-------------|
13
+ | `trigger` | What triggered the compaction: `'auto'` or `'manual'` |
14
+ | `compact_summary` | The summary produced by the compaction |
15
+
16
+ ## Hook State Helpers
17
+
18
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
19
+
20
+ No event-specific state methods — this hook is non-blocking.
21
+
22
+ ## Output Helpers
23
+
24
+ [📚 Shared output helpers](COMMON.md#output-helpers)
25
+
26
+ No event-specific output helpers.
27
+
28
+ ## Hook Exit Codes
29
+
30
+ Non-blocking. Exit code is ignored.
@@ -0,0 +1,39 @@
1
+ # PostToolBatch API
2
+
3
+ Available when inheriting from `ClaudeHooks::PostToolBatch`:
4
+
5
+ Runs after a full batch of tool calls completes. Can block Claude from continuing.
6
+
7
+ ## Input Helpers
8
+
9
+ [📚 Shared input helpers](COMMON.md#input-helpers)
10
+
11
+ | Method | Description |
12
+ |--------|-------------|
13
+ | `tool_calls` | Array of tool call results; each entry has `tool_name`, `tool_input`, `tool_use_id`, `tool_response` |
14
+
15
+ ## Hook State Helpers
16
+
17
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
18
+
19
+ | Method | Description |
20
+ |--------|-------------|
21
+ | `block!(reason)` | Block Claude from continuing after this batch |
22
+ | `add_additional_context!(context)` | Add additional context visible to Claude |
23
+
24
+ ## Output Helpers
25
+
26
+ [📚 Shared output helpers](COMMON.md#output-helpers)
27
+
28
+ | Method | Description |
29
+ |--------|-------------|
30
+ | `output.blocked?` | Check if the batch was blocked |
31
+ | `output.decision` | Get the decision (`'block'` or nil) |
32
+ | `output.reason` | Get the block reason |
33
+
34
+ ## Hook Exit Codes
35
+
36
+ | Exit Code | Behavior |
37
+ |-----------|----------|
38
+ | `exit 0` | Claude continues |
39
+ | `exit 2` | Blocks Claude; `STDERR` shown to Claude |
@@ -0,0 +1,31 @@
1
+ # PostToolUseFailure API
2
+
3
+ Available when inheriting from `ClaudeHooks::PostToolUseFailure`:
4
+
5
+ Runs when a tool call fails. Non-blocking — output and exit code are ignored except for `additionalContext`.
6
+
7
+ ## Input Helpers
8
+
9
+ [📚 Shared input helpers](COMMON.md#input-helpers)
10
+
11
+ | Method | Description |
12
+ |--------|-------------|
13
+ | `tool_name` | The name of the tool that failed |
14
+ | `tool_input` | The input data for the tool |
15
+ | `tool_use_id` | The unique identifier for this tool use |
16
+ | `error` | The error message |
17
+ | `is_interrupt` | Whether the failure was caused by an interrupt (`true`/`false`) |
18
+ | `interrupt?` | Alias for `is_interrupt` |
19
+ | `duration_ms` | How long the tool ran before failing (milliseconds) |
20
+
21
+ ## Hook State Helpers
22
+
23
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
24
+
25
+ | Method | Description |
26
+ |--------|-------------|
27
+ | `add_additional_context!(context)` | Add additional context visible to Claude about the failure |
28
+
29
+ ## Hook Exit Codes
30
+
31
+ Non-blocking. Exit code and output are ignored by Claude Code; only `additionalContext` is consumed.
@@ -13,10 +13,13 @@ Input helpers to access the data provided by Claude Code through `STDIN`.
13
13
  | `custom_instructions` | Get custom instructions (only available for manual trigger) |
14
14
 
15
15
  ## Hook State Helpers
16
- No specific hook state methods are available to alter compaction behavior.
17
16
 
18
17
  [📚 Shared hook state methods](COMMON.md#hook-state-methods)
19
18
 
19
+ | Method | Description |
20
+ |--------|-------------|
21
+ | `block!(reason)` | Block the compaction with a reason (top-level `decision: 'block'`) |
22
+
20
23
  ## Utility Methods
21
24
  Utility methods for transcript management.
22
25
 
@@ -26,10 +29,15 @@ Utility methods for transcript management.
26
29
 
27
30
  ## Output Helpers
28
31
  Output helpers provide access to the hook's output data and helper methods for working with the output state.
29
- PreCompact hooks don't have any specific hook state and thus doesn't have any specific output helpers.
30
32
 
31
33
  [📚 Shared output helpers](COMMON.md#output-helpers)
32
34
 
35
+ | Method | Description |
36
+ |--------|-------------|
37
+ | `output.blocked?` | Check if the compaction was blocked |
38
+ | `output.decision` | Get the decision (`'block'` or nil) |
39
+ | `output.reason` | Get the block reason |
40
+
33
41
  ## Hook Exit Codes
34
42
 
35
43
  | Exit Code | Behavior |
@@ -23,7 +23,10 @@ Hook state methods are helpers to modify the hook's internal state (`output_data
23
23
  | `approve_tool!(reason)` | Explicitly approve tool usage |
24
24
  | `block_tool!(reason)` | Block tool usage with feedback |
25
25
  | `ask_for_permission!(reason)` | Request user permission |
26
+ | `defer_permission!` | Defer the permission decision to a later hook in the chain |
26
27
  | `update_tool_input!(updated_input)` | Update the tool input and automatically approve the tool (sets `permissionDecision` to `'allow'`) |
28
+ | `update_input!(updated_input)` | Update `updatedInput` without changing the permission decision |
29
+ | `add_additional_context!(context)` | Add additional context visible to Claude |
27
30
 
28
31
  ## Output Helpers
29
32
  Output helpers provide access to the hook's output data and helper methods for working with the output state.
@@ -35,9 +38,10 @@ Output helpers provide access to the hook's output data and helper methods for w
35
38
  | `output.allowed?` | Check if the tool has been explicitly allowed (permission_decision == 'allow') |
36
39
  | `output.denied?` | Check if the tool has been denied (permission_decision == 'deny') |
37
40
  | `output.blocked?` | Alias for `denied?` |
41
+ | `output.deferred?` | Check if the permission decision was deferred (permission_decision == 'defer') |
38
42
  | `output.should_ask_permission?` | Check if user permission is required (permission_decision == 'ask') |
39
43
  | `output.input_updated?` | Check if tool input has been updated |
40
- | `output.permission_decision` | Get the permission decision: 'allow', 'deny', or 'ask' |
44
+ | `output.permission_decision` | Get the permission decision: `'allow'`, `'deny'`, `'ask'`, or `'defer'` |
41
45
  | `output.permission_reason` | Get the reason for the permission decision |
42
46
  | `output.updated_input` | Get the updated input (if provided) |
43
47
 
data/docs/API/SETUP.md ADDED
@@ -0,0 +1,37 @@
1
+ # Setup API
2
+
3
+ Available when inheriting from `ClaudeHooks::Setup`:
4
+
5
+ Runs once during Claude Code startup (before any session begins). Use it to inject global context or perform one-time initialization.
6
+
7
+ ## Input Helpers
8
+
9
+ [📚 Shared input helpers](COMMON.md#input-helpers)
10
+
11
+ | Method | Description |
12
+ |--------|-------------|
13
+ | `source` | Startup reason: `'init'` (first launch) or `'maintenance'` |
14
+
15
+ ## Hook State Helpers
16
+
17
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
18
+
19
+ | Method | Description |
20
+ |--------|-------------|
21
+ | `add_additional_context!(context)` | Add contextual information for Claude |
22
+ | `add_context!(context)` | Alias for `add_additional_context!` |
23
+
24
+ ## Output Helpers
25
+
26
+ [📚 Shared output helpers](COMMON.md#output-helpers)
27
+
28
+ | Method | Description |
29
+ |--------|-------------|
30
+ | `output.additional_context` | Get the additional context that was added |
31
+
32
+ ## Hook Exit Codes
33
+
34
+ | Exit Code | Behavior |
35
+ |-----------|----------|
36
+ | `exit 0` | Continues normally; `STDOUT` added as context |
37
+ | `exit 2` | N/A — non-blocking event |
@@ -0,0 +1,19 @@
1
+ # StopFailure API
2
+
3
+ Available when inheriting from `ClaudeHooks::StopFailure`:
4
+
5
+ Runs when the stop phase itself errors. Purely a logging event — output and exit code are completely ignored by Claude Code.
6
+
7
+ ## Input Helpers
8
+
9
+ [📚 Shared input helpers](COMMON.md#input-helpers)
10
+
11
+ | Method | Description |
12
+ |--------|-------------|
13
+ | `error` | The error message |
14
+ | `error_details` | Additional error detail (stack trace, etc.) |
15
+ | `last_assistant_message` | The last message Claude produced before the failure |
16
+
17
+ ## Hook Exit Codes
18
+
19
+ Exit code and all output are ignored. Use this hook only for logging or alerting.
@@ -0,0 +1,40 @@
1
+ # SubagentStart API
2
+
3
+ Available when inheriting from `ClaudeHooks::SubagentStart`:
4
+
5
+ Runs when a subagent task starts. Use it to inject context specific to the subagent or log the start.
6
+
7
+ ## Input Helpers
8
+
9
+ [📚 Shared input helpers](COMMON.md#input-helpers)
10
+
11
+ The `agent_id` and `agent_type` common fields are populated for this event.
12
+
13
+ | Method | Description |
14
+ |--------|-------------|
15
+ | `agent_id` | The subagent's unique ID |
16
+ | `agent_type` | The subagent's type |
17
+
18
+ ## Hook State Helpers
19
+
20
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
21
+
22
+ | Method | Description |
23
+ |--------|-------------|
24
+ | `add_additional_context!(context)` | Add contextual information for the subagent |
25
+ | `add_context!(context)` | Alias for `add_additional_context!` |
26
+
27
+ ## Output Helpers
28
+
29
+ [📚 Shared output helpers](COMMON.md#output-helpers)
30
+
31
+ | Method | Description |
32
+ |--------|-------------|
33
+ | `output.additional_context` | Get the additional context that was added |
34
+
35
+ ## Hook Exit Codes
36
+
37
+ | Exit Code | Behavior |
38
+ |-----------|----------|
39
+ | `exit 0` | Continues normally; `STDOUT` added as context |
40
+ | `exit 2` | N/A — non-blocking event |