claude_hooks 0.2.1 → 1.0.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +92 -0
  3. data/README.md +215 -357
  4. data/claude_hooks.gemspec +2 -2
  5. data/docs/API/COMMON.md +83 -0
  6. data/docs/API/NOTIFICATION.md +32 -0
  7. data/docs/API/POST_TOOL_USE.md +45 -0
  8. data/docs/API/PRE_COMPACT.md +39 -0
  9. data/docs/API/PRE_TOOL_USE.md +110 -0
  10. data/docs/API/SESSION_END.md +100 -0
  11. data/docs/API/SESSION_START.md +40 -0
  12. data/docs/API/STOP.md +47 -0
  13. data/docs/API/SUBAGENT_STOP.md +47 -0
  14. data/docs/API/USER_PROMPT_SUBMIT.md +47 -0
  15. data/docs/OUTPUT_MIGRATION_GUIDE.md +228 -0
  16. data/example_dotclaude/hooks/entrypoints/session_end.rb +35 -0
  17. data/example_dotclaude/hooks/entrypoints/user_prompt_submit.rb +17 -12
  18. data/example_dotclaude/hooks/handlers/session_end/cleanup_handler.rb +55 -0
  19. data/example_dotclaude/hooks/handlers/session_end/log_session_stats.rb +64 -0
  20. data/example_dotclaude/hooks/handlers/user_prompt_submit/append_rules.rb +1 -1
  21. data/example_dotclaude/hooks/handlers/user_prompt_submit/log_user_prompt.rb +2 -2
  22. data/example_dotclaude/settings.json +11 -0
  23. data/lib/claude_hooks/base.rb +16 -24
  24. data/lib/claude_hooks/cli.rb +75 -1
  25. data/lib/claude_hooks/logger.rb +0 -1
  26. data/lib/claude_hooks/output/base.rb +152 -0
  27. data/lib/claude_hooks/output/notification.rb +22 -0
  28. data/lib/claude_hooks/output/post_tool_use.rb +68 -0
  29. data/lib/claude_hooks/output/pre_compact.rb +20 -0
  30. data/lib/claude_hooks/output/pre_tool_use.rb +97 -0
  31. data/lib/claude_hooks/output/session_end.rb +24 -0
  32. data/lib/claude_hooks/output/session_start.rb +49 -0
  33. data/lib/claude_hooks/output/stop.rb +76 -0
  34. data/lib/claude_hooks/output/subagent_stop.rb +14 -0
  35. data/lib/claude_hooks/output/user_prompt_submit.rb +71 -0
  36. data/lib/claude_hooks/post_tool_use.rb +6 -12
  37. data/lib/claude_hooks/pre_tool_use.rb +0 -37
  38. data/lib/claude_hooks/session_end.rb +43 -0
  39. data/lib/claude_hooks/session_start.rb +0 -23
  40. data/lib/claude_hooks/stop.rb +0 -25
  41. data/lib/claude_hooks/user_prompt_submit.rb +0 -26
  42. data/lib/claude_hooks/version.rb +1 -1
  43. data/lib/claude_hooks.rb +15 -0
  44. metadata +33 -8
  45. /data/{WHY.md → docs/WHY.md} +0 -0
data/claude_hooks.gemspec CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.description = "A Ruby DSL framework for creating Claude Code hooks with composable hook scripts that enable teams to easily implement logging, security checks, and workflow automation."
13
13
  spec.homepage = "https://github.com/gabriel-dehan/claude_hooks"
14
14
  spec.license = "MIT"
15
- spec.required_ruby_version = ">= 2.7.0"
15
+ spec.required_ruby_version = ">= 3.2.0"
16
16
 
17
17
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
18
18
  spec.metadata["homepage_uri"] = spec.homepage
@@ -35,5 +35,5 @@ Gem::Specification.new do |spec|
35
35
 
36
36
  # Development dependencies
37
37
  spec.add_development_dependency "rake", "~> 13.0"
38
- spec.add_development_dependency "rspec", "~> 3.0"
38
+ spec.add_development_dependency "minitest", "~> 5.0"
39
39
  end
@@ -0,0 +1,83 @@
1
+ # Common API Methods
2
+
3
+ Those methods are available in **all hook types** and are inherited from `ClaudeHooks::Base`:
4
+
5
+ ## Input Helpers
6
+ Input helpers to access the data provided by Claude Code through `STDIN`.
7
+
8
+ | Method | Description |
9
+ |--------|-------------|
10
+ | `input_data` | Input data reader |
11
+ | `session_id` | Get the current session ID |
12
+ | `transcript_path` | Get path to the transcript file |
13
+ | `cwd` | Get current working directory |
14
+ | `hook_event_name` | Get the hook event name |
15
+ | `read_transcript` | Read the transcript file |
16
+ | `transcript` | Alias for `read_transcript` |
17
+
18
+ ## Hook State Helpers
19
+ Hook state methods are helpers to modify the hook's internal state (`output_data`) before yielding back to Claude Code.
20
+
21
+ | Method | Description |
22
+ |--------|-------------|
23
+ | `allow_continue!` | Allow Claude to continue (default) |
24
+ | `prevent_continue!(reason)` | Stop Claude with reason |
25
+ | `suppress_output!` | Hide stdout from transcript |
26
+ | `show_output!` | Show stdout in transcript (default) |
27
+ | `clear_specifics!` | Clear hook-specific output |
28
+ | `system_message!(message)` | Set a system message shown to the user (not to Claude) |
29
+ | `clear_system_message!` | Clear the system message |
30
+
31
+ ## Output Helpers
32
+
33
+ From a hook, you can always access the `output` object via `hook.output`.
34
+ This object provides helpers to access output data, for merging multiple outputs as well as sending the right exit codes and data back to Claude Code.
35
+
36
+ ### Output data access
37
+
38
+ | Method | Description |
39
+ |--------|-------------|
40
+ | `output` | Output object accessor |
41
+ | `output_data` | RAW output data accessor |
42
+ | `output.continue?` | Check if Claude should continue processing |
43
+ | `output.stop_reason` | Get the stop reason if continue is false |
44
+ | `output.suppress_output?` | Check if output should be suppressed from transcript |
45
+ | `output.hook_specific_output` | Get the hook-specific output data |
46
+ | `output.system_message` | Get the system message if any |
47
+
48
+ ### Output data merging
49
+ 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)`.
50
+
51
+ | Method | Description |
52
+ |--------|-------------|
53
+ | `merge(*outputs)` | Intelligently merge multiple outputs of the same type into a single output |
54
+
55
+ ### Exit Control and Yielding back to Claude Code
56
+
57
+ | Method | Description |
58
+ |--------|-------------|
59
+ | `output.output_and_exit` | Automatically output to correct stream and exit with proper code |
60
+ | `output.exit_code` | Get the calculated exit code based on hook state |
61
+ | `output.output_stream` | Get the proper output stream (:stdout or :stderr) depending on hook state |
62
+ | `output.to_json` | Generates a JSON string of the output |
63
+
64
+ ## Configuration and Utility Methods
65
+
66
+ ### Utility Methods
67
+ | Method | Description |
68
+ |--------|-------------|
69
+ | `log(message, level: :info)` | Log to session-specific file (levels: :info, :warn, :error) |
70
+
71
+ ### Configuration Methods
72
+ | Method | Description |
73
+ |--------|-------------|
74
+ | `home_claude_dir` | Get the home Claude directory (`$HOME/.claude`) |
75
+ | `project_claude_dir` | Get the project Claude directory (`$CLAUDE_PROJECT_DIR/.claude`, or `nil`) |
76
+ | `home_path_for(relative_path)` | Get absolute path relative to home Claude directory |
77
+ | `project_path_for(relative_path)` | Get absolute path relative to project Claude directory (or `nil`) |
78
+ | `base_dir` | Get the base Claude directory (**deprecated**) |
79
+ | `path_for(relative_path, base_dir=nil)` | Get absolute path relative to specified or default base dir (**deprecated**) |
80
+ | `config` | Access the merged configuration object |
81
+ | `config.get_config_value(env_key, config_file_key, default)` | Get any config value with fallback |
82
+ | `config.logs_directory` | Get logs directory path (always under home directory) |
83
+ | `config.your_custom_key` | Access any custom config via method_missing |
@@ -0,0 +1,32 @@
1
+ # Notification API
2
+
3
+ Available when inheriting from `ClaudeHooks::Notification`:
4
+
5
+ ## Input Helpers
6
+ Input helpers to access the data provided by Claude Code through `STDIN`.
7
+
8
+ [📚 Shared input helpers](COMMON.md#input-helpers)
9
+
10
+ | Method | Description |
11
+ |--------|-------------|
12
+ | `message` | Get the notification message content |
13
+ | `notification_message` | Alias for `message` |
14
+
15
+ ## Hook State Helpers
16
+ Notifications are outside facing and do not have any specific state to modify.
17
+
18
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
19
+
20
+ ## Output Helpers
21
+ Output helpers provide access to the hook's output data and helper methods for working with the output state.
22
+ Notifications don't have any specific hook state and thus doesn't have any specific output helpers.
23
+
24
+ [📚 Shared output helpers](COMMON.md#output-helpers)
25
+
26
+ ## Hook Exit Codes
27
+
28
+ | Exit Code | Behavior |
29
+ |-----------|----------|
30
+ | `exit 0` | Operation continues<br/>Logged to debug only (`--debug`) |
31
+ | `exit 1` | Non-blocking error<br/>Logged to debug only (`--debug`) |
32
+ | `exit 2` | N/A<br/>Logged to debug only (`--debug`) |
@@ -0,0 +1,45 @@
1
+ # PostToolUse API
2
+
3
+ Available when inheriting from `ClaudeHooks::PostToolUse`:
4
+
5
+ ## Input Helpers
6
+ Input helpers to access the data provided by Claude Code through `STDIN`.
7
+
8
+ [📚 Shared input helpers](COMMON.md#input-helpers)
9
+
10
+ | Method | Description |
11
+ |--------|-------------|
12
+ | `tool_name` | Get the name of the tool that was used |
13
+ | `tool_input` | Get the input that was passed to the tool |
14
+ | `tool_response` | Get the tool's response/output |
15
+
16
+ ## Hook State Helpers
17
+ Hook state methods are helpers to modify the hook's internal state (`output_data`) before yielding back to Claude Code.
18
+
19
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
20
+
21
+ | Method | Description |
22
+ |--------|-------------|
23
+ | `block_tool!(reason)` | Block the tool result from being used |
24
+ | `approve_tool!(reason)` | Clear any previous block decision (default behavior) |
25
+ | `add_additional_context!(context)` | Add context for Claude to consider after tool use |
26
+
27
+ ## Output Helpers
28
+ Output helpers provide access to the hook's output data and helper methods for working with the output state.
29
+
30
+ [📚 Shared output helpers](COMMON.md#output-helpers)
31
+
32
+ | Method | Description |
33
+ |--------|-------------|
34
+ | `output.decision` | Get the decision: "block" or nil (default) |
35
+ | `output.reason` | Get the reason that was set for the decision |
36
+ | `output.blocked?` | Check if the tool result has been blocked |
37
+ | `output.additional_context` | Get the additional context that was added |
38
+
39
+ ## Hook Exit Codes
40
+
41
+ | Exit Code | Behavior |
42
+ |-----------|----------|
43
+ | `exit 0` | Operation continues<br/>`STDOUT` shown to user in transcript mode |
44
+ | `exit 1` | Non-blocking error<br/>`STDERR` shown to user |
45
+ | `exit 2` | N/A<br/>`STDERR` shown to Claude *(tool already ran)* |
@@ -0,0 +1,39 @@
1
+ # PreCompact API
2
+
3
+ Available when inheriting from `ClaudeHooks::PreCompact`:
4
+
5
+ ## Input Helpers
6
+ Input helpers to access the data provided by Claude Code through `STDIN`.
7
+
8
+ [📚 Shared input helpers](COMMON.md#input-helpers)
9
+
10
+ | Method | Description |
11
+ |--------|-------------|
12
+ | `trigger` | Get the compaction trigger: `'manual'` or `'auto'` |
13
+ | `custom_instructions` | Get custom instructions (only available for manual trigger) |
14
+
15
+ ## Hook State Helpers
16
+ No specific hook state methods are available to alter compaction behavior.
17
+
18
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
19
+
20
+ ## Utility Methods
21
+ Utility methods for transcript management.
22
+
23
+ | Method | Description |
24
+ |--------|-------------|
25
+ | `backup_transcript!(backup_file_path)` | Create a backup of the transcript at the specified path |
26
+
27
+ ## Output Helpers
28
+ 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
+
31
+ [📚 Shared output helpers](COMMON.md#output-helpers)
32
+
33
+ ## Hook Exit Codes
34
+
35
+ | Exit Code | Behavior |
36
+ |-----------|----------|
37
+ | `exit 0` | Operation continues<br/>`STDOUT` shown to user in transcript mode |
38
+ | `exit 1` | Non-blocking error<br/>`STDERR` shown to user |
39
+ | `exit 2` | N/A<br/>`STDERR` shown to user only|
@@ -0,0 +1,110 @@
1
+ # PreToolUse API
2
+
3
+ Available when inheriting from `ClaudeHooks::PreToolUse`:
4
+
5
+ ## Input Helpers
6
+ Input helpers to access the data provided by Claude Code through `STDIN`.
7
+
8
+ [📚 Shared input helpers](COMMON.md#input-helpers)
9
+
10
+ | Method | Description |
11
+ |--------|-------------|
12
+ | `tool_name` | Get the name of the tool being used |
13
+ | `tool_input` | Get the input data for the tool |
14
+
15
+ ## Hook State Helpers
16
+ Hook state methods are helpers to modify the hook's internal state (`output_data`) before yielding back to Claude Code.
17
+
18
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
19
+
20
+ | Method | Description |
21
+ |--------|-------------|
22
+ | `approve_tool!(reason)` | Explicitly approve tool usage |
23
+ | `block_tool!(reason)` | Block tool usage with feedback |
24
+ | `ask_for_permission!(reason)` | Request user permission |
25
+
26
+ ## Output Helpers
27
+ Output helpers provide access to the hook's output data and helper methods for working with the output state.
28
+
29
+ [📚 Shared output helpers](COMMON.md#output-helpers)
30
+
31
+ | Method | Description |
32
+ |--------|-------------|
33
+ | `output.allowed?` | Check if the tool has been explicitly allowed (permission_decision == 'allow') |
34
+ | `output.denied?` | Check if the tool has been denied (permission_decision == 'deny') |
35
+ | `output.blocked?` | Alias for `denied?` |
36
+ | `output.should_ask_permission?` | Check if user permission is required (permission_decision == 'ask') |
37
+ | `output.permission_decision` | Get the permission decision: 'allow', 'deny', or 'ask' |
38
+ | `output.permission_reason` | Get the reason for the permission decision |
39
+
40
+ ## Hook Exit Codes
41
+
42
+ | Exit Code | Behavior |
43
+ |-----------|----------|
44
+ | `exit 0` | Operation continues<br/>`STDOUT` shown to user in transcript mode |
45
+ | `exit 1` | Non-blocking error<br/>`STDERR` shown to user |
46
+ | `exit 2` | **Blocks the tool call**<br/>`STDERR` shown to Claude |
47
+
48
+ ## Exit code behaviors related to chosen output stream
49
+ Outputting to a specific stream has a different effect depending on the exit code.
50
+
51
+ > [!TIP]
52
+ > The most common and useful cases expressed in the tables below are handled automatically by calling `hook.output_and_exit`.
53
+ > You only need to worry about this when you want very specific behavior.
54
+
55
+ ### ALLOW
56
+
57
+ #### Claude Code behavior depending on combination
58
+
59
+ | Exit Code | STDERR | STDOUT |
60
+ |------------|--------|--------|
61
+ | 0 | RUNS | RUNS |
62
+ | 1 | RUNS | RUNS |
63
+ | 2 | BLOCKS | RUNS |
64
+
65
+ #### Output visibility depending on exit code
66
+
67
+ | Output Visibility / Exit Code | 0 | 1 | 2 |
68
+ |-------------------------------|-------|-------|---------|
69
+ | **STDOUT sent to Claude** | ✅ YES | ✅ YES | ✅ YES |
70
+ | **STDOUT shown to User** | ❌ NO | ❌ NO | ❌ NO |
71
+ | **STDERR sent to Claude** | ❌ NO | ❌ NO | ✅ YES |
72
+ | **STDERR shown to User** | ❌ NO | ✅ YES | ✅ YES |
73
+
74
+ ### ASK
75
+
76
+ #### Claude Code behavior depending on combination
77
+
78
+ | Exit Code | STDERR | STDOUT |
79
+ |------------|--------|--------|
80
+ | 0 | RUNS | ASKS |
81
+ | 1 | RUNS | ASKS |
82
+ | 2 | BLOCKS | ASKS |
83
+
84
+ #### Output visibility depending on exit code
85
+
86
+ | Output Visibility / Exit Code | 0 | 1 | 2 |
87
+ |-------------------------------|-------|-------|---------|
88
+ | **STDOUT sent to Claude** | ✅ YES | ✅ YES | ✅ YES |
89
+ | **STDOUT shown to User** | ✅ YES | ✅ YES | ✅ YES |
90
+ | **STDERR sent to Claude** | ❌ NO | ❌ NO | ✅ YES |
91
+ | **STDERR shown to User** | ❌ NO | ✅ YES | ✅ YES |
92
+
93
+ ### DENY
94
+
95
+ #### Claude Code behavior depending on combination
96
+
97
+ | Exit Code | STDERR | STDOUT |
98
+ |------------|--------|--------|
99
+ | 0 | BLOCKS | BLOCKS |
100
+ | 1 | BLOCKS | BLOCKS |
101
+ | 2 | BLOCKS | BLOCKS |
102
+
103
+ #### Output visibility depending on exit code
104
+
105
+ | Output Visibility / Exit Code | 0 | 1 | 2 |
106
+ |-------------------------------|-------|-------|---------|
107
+ | **STDOUT sent to Claude** | ✅ YES | ✅ YES | ✅ YES |
108
+ | **STDOUT shown to User** | ✅ YES | ✅ YES | ✅ YES |
109
+ | **STDERR sent to Claude** | ❌ NO | ❌ NO | ✅ YES |
110
+ | **STDERR shown to User** | ❌ NO | ✅ YES | ✅ YES |
@@ -0,0 +1,100 @@
1
+ # SessionEnd API
2
+
3
+ > [!NOTE]
4
+ > SessionEnd hooks cannot block session termination - they are designed for cleanup tasks only.
5
+
6
+ Available when inheriting from `ClaudeHooks::SessionEnd`:
7
+
8
+ ## Input Helpers
9
+ Input helpers to access the data provided by Claude Code through `STDIN`.
10
+
11
+ [📚 Shared input helpers](COMMON.md#input-helpers)
12
+
13
+ | Method | Description |
14
+ |--------|-------------|
15
+ | `reason` | Get the reason for session termination |
16
+
17
+ ### Reason Helpers
18
+
19
+ | Method | Description |
20
+ |--------|-------------|
21
+ | `cleared?` | Check if session was cleared with `/clear` command |
22
+ | `logout?` | Check if user logged out |
23
+ | `prompt_input_exit?` | Check if user exited while prompt input was visible |
24
+ | `other_reason?` | Check if reason is unspecified or other |
25
+
26
+ ## Hook State Helpers
27
+ Hook state methods are helpers to modify the hook's internal state (`output_data`) before yielding back to Claude Code.
28
+ SessionEnd hooks do not have any specific state to modify.
29
+
30
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
31
+
32
+ ## Output Helpers
33
+ Output helpers provide access to the hook's output data and helper methods for working with the output state.
34
+ SessionEnd hooks don't have any specific hook state and thus doesn't have any specific output helpers.
35
+
36
+ [📚 Shared output helpers](COMMON.md#output-helpers)
37
+
38
+ ## Hook Exit Codes
39
+
40
+ | Exit Code | Behavior |
41
+ |-----------|----------|
42
+ | `exit 0` | Operation continues<br/>Logged to debug only (`--debug`) |
43
+ | `exit 1` | Non-blocking error<br/>Logged to debug only (`--debug`) |
44
+ | `exit 2` | N/A<br/>Logged to debug only (`--debug`) |
45
+
46
+ ## Example Usage
47
+
48
+ ```ruby
49
+ #!/usr/bin/env ruby
50
+
51
+ require 'claude_hooks'
52
+
53
+ class MySessionCleanup < ClaudeHooks::SessionEnd
54
+ def call
55
+ log "Session ending with reason: #{reason}"
56
+
57
+ if cleared?
58
+ log "Cleaning up after /clear command"
59
+ add_cleanup_message!("Temporary files cleaned")
60
+ elsif logout?
61
+ log "User logged out - saving state"
62
+ log_session_info!("Session saved successfully")
63
+ elsif prompt_input_exit?
64
+ log "Interrupted during prompt - partial cleanup"
65
+ add_cleanup_message!("Partial state saved")
66
+ else
67
+ log "General session cleanup"
68
+ add_cleanup_message!("Session ended normally")
69
+ end
70
+
71
+ output
72
+ end
73
+ end
74
+
75
+ # CLI testing
76
+ if __FILE__ == $0
77
+ ClaudeHooks::CLI.test_runner(MySessionCleanup)
78
+ end
79
+ ```
80
+
81
+ ## Session Configuration
82
+
83
+ Register the hook in your `.claude/settings.json`:
84
+
85
+ ```json
86
+ {
87
+ "hooks": {
88
+ "SessionEnd": [
89
+ {
90
+ "hooks": [
91
+ {
92
+ "type": "command",
93
+ "command": "~/.claude/hooks/entrypoints/session_end.rb"
94
+ }
95
+ ]
96
+ }
97
+ ]
98
+ }
99
+ }
100
+ ```
@@ -0,0 +1,40 @@
1
+ # SessionStart API
2
+
3
+ Available when inheriting from `ClaudeHooks::SessionStart`:
4
+
5
+ ## Input Helpers
6
+ Input helpers to access the data provided by Claude Code through `STDIN`.
7
+
8
+ [📚 Shared input helpers](COMMON.md#input-helpers)
9
+
10
+ | Method | Description |
11
+ |--------|-------------|
12
+ | `source` | Get the session start source: `'startup'`, `'resume'`, or `'clear'` |
13
+
14
+ ## Hook State Helpers
15
+ Hook state methods are helpers to modify the hook's internal state (`output_data`) before yielding back to Claude Code.
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's session |
22
+ | `add_context!(context)` | Alias for `add_additional_context!` |
23
+ | `empty_additional_context!` | Clear additional context |
24
+
25
+ ## Output Helpers
26
+ Output helpers provide access to the hook's output data and helper methods for working with the output state.
27
+
28
+ [📚 Shared output helpers](COMMON.md#output-helpers)
29
+
30
+ | Method | Description |
31
+ |--------|-------------|
32
+ | `output.additional_context` | Get the additional context that was added |
33
+
34
+ ## Hook Exit Codes
35
+
36
+ | Exit Code | Behavior |
37
+ |-----------|----------|
38
+ | `exit 0` | Operation continues<br/>**`STDOUT` added as context to Claude** |
39
+ | `exit 1` | Non-blocking error<br/>`STDERR` shown to user |
40
+ | `exit 2` | N/A<br/>`STDERR` shown to user only |
data/docs/API/STOP.md ADDED
@@ -0,0 +1,47 @@
1
+ # Stop API
2
+
3
+ Available when inheriting from `ClaudeHooks::Stop`:
4
+
5
+ ## Input Helpers
6
+ Input helpers to access the data provided by Claude Code through `STDIN`.
7
+
8
+ [📚 Shared input helpers](COMMON.md#input-helpers)
9
+
10
+ | Method | Description |
11
+ |--------|-------------|
12
+ | `stop_hook_active` | Check if Claude Code is already continuing as a result of a stop hook |
13
+
14
+ ## Hook State Helpers
15
+ Hook state methods are helpers to modify the hook's internal state (`output_data`) before yielding back to Claude Code.
16
+
17
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
18
+
19
+ > [!NOTE]
20
+ > In Stop hooks, the decision to "block" actually means to "force Claude to continue", we are "blocking" the blockage.
21
+ > This is counterintuitive and the reason why the method `block!` is aliased to `continue_with_instructions!`
22
+
23
+ | Method | Description |
24
+ |--------|-------------|
25
+ | `continue_with_instructions!(instructions)` | Block Claude from stopping and provide instructions to continue |
26
+ | `block!(instructions)` | Alias for `continue_with_instructions!` |
27
+ | `ensure_stopping!` | Allow Claude to stop normally (default behavior) |
28
+
29
+ ## Output Helpers
30
+ Output helpers provide access to the hook's output data and helper methods for working with the output state.
31
+
32
+ [📚 Shared output helpers](COMMON.md#output-helpers)
33
+
34
+ | Method | Description |
35
+ |--------|-------------|
36
+ | `output.should_continue?` | Check if Claude should be forced to continue (decision == 'block') |
37
+ | `output.should_stop?` | Check if Claude should stop normally (decision != 'block') |
38
+ | `output.continue_instructions` | Get the continue instructions (alias for `reason`) |
39
+ | `output.reason` | Get the reason for the decision |
40
+
41
+ ## Hook Exit Codes
42
+
43
+ | Exit Code | Behavior |
44
+ |-----------|----------|
45
+ | `exit 0` | Agent will stop<br/>`STDOUT` shown to user in transcript mode |
46
+ | `exit 1` | Non-blocking error<br/>`STDERR` shown to user |
47
+ | `exit 2` | **Blocks stoppage**<br/>`STDERR` shown to Claude |
@@ -0,0 +1,47 @@
1
+ # SubagentStop API
2
+
3
+ Available when inheriting from `ClaudeHooks::SubagentStop` (inherits from `ClaudeHooks::Stop`):
4
+
5
+ ## Input Helpers
6
+ Input helpers to access the data provided by Claude Code through `STDIN`.
7
+
8
+ [📚 Shared input helpers](COMMON.md#input-helpers)
9
+
10
+ | Method | Description |
11
+ |--------|-------------|
12
+ | `stop_hook_active` | Check if Claude Code is already continuing as a result of a stop hook |
13
+
14
+ ## Hook State Helpers
15
+ Hook state methods are helpers to modify the hook's internal state (`output_data`) before yielding back to Claude Code.
16
+
17
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
18
+
19
+ > [!NOTE]
20
+ > In Stop hooks, the decision to "block" actually means to "force Claude to continue", we are "blocking" the blockage.
21
+ > This is counterintuitive and the reason why the method `block!` is aliased to `continue_with_instructions!`
22
+
23
+ | Method | Description |
24
+ |--------|-------------|
25
+ | `continue_with_instructions!(instructions)` | Block Claude from stopping and provide instructions to continue |
26
+ | `block!(instructions)` | Alias for `continue_with_instructions!` |
27
+ | `ensure_stopping!` | Allow Claude to stop normally (default behavior) |
28
+
29
+ ## Output Helpers
30
+ Output helpers provide access to the hook's output data and helper methods for working with the output state.
31
+
32
+ [📚 Shared output helpers](COMMON.md#output-helpers)
33
+
34
+ | Method | Description |
35
+ |--------|-------------|
36
+ | `output.should_continue?` | Check if Claude should be forced to continue (decision == 'block') |
37
+ | `output.should_stop?` | Check if Claude should stop normally (decision != 'block') |
38
+ | `output.continue_instructions` | Get the continue instructions (alias for `reason`) |
39
+ | `output.reason` | Get the reason for the decision |
40
+
41
+ ## Hook Exit Codes
42
+
43
+ | Exit Code | Behavior |
44
+ |-----------|----------|
45
+ | `exit 0` | Subagent will stop<br/>`STDOUT` shown to user in transcript mode |
46
+ | `exit 1` | Non-blocking error<br/>`STDERR` shown to user |
47
+ | `exit 2` | **Blocks stoppage**<br/>`STDERR` shown to Claude subagent |
@@ -0,0 +1,47 @@
1
+ # UserPromptSubmit API
2
+
3
+ Available when inheriting from `ClaudeHooks::UserPromptSubmit`:
4
+
5
+ ## Input Helpers
6
+ Input helpers to access the data provided by Claude Code through `STDIN`.
7
+
8
+ [📚 Shared input helpers](COMMON.md#input-helpers)
9
+
10
+ | Method | Description |
11
+ |--------|-------------|
12
+ | `prompt` | Get the user's prompt text |
13
+ | `user_prompt` | Alias for `prompt` |
14
+ | `current_prompt` | Alias for `prompt` |
15
+
16
+ ## Hook State Helpers
17
+ Hook state methods are helpers to modify the hook's internal state (`output_data`) before yielding back to Claude Code.
18
+
19
+ [📚 Shared hook state methods](COMMON.md#hook-state-methods)
20
+
21
+ | Method | Description |
22
+ |--------|-------------|
23
+ | `add_additional_context!(context)` | Add context to the prompt |
24
+ | `add_context!(context)` | Alias for `add_additional_context!` |
25
+ | `empty_additional_context!` | Remove additional context |
26
+ | `block_prompt!(reason)` | Block the prompt from processing |
27
+ | `unblock_prompt!` | Unblock a previously blocked prompt |
28
+
29
+ ## Output Helpers
30
+ Output helpers provide access to the hook's output data and helper methods for working with the output state.
31
+
32
+ [📚 Shared output helpers](COMMON.md#output-helpers)
33
+
34
+ | Method | Description |
35
+ |--------|-------------|
36
+ | `output.decision` | Get the decision: "block" or nil (default) |
37
+ | `output.reason` | Get the reason for the decision |
38
+ | `output.blocked?` | Check if the prompt has been blocked (decision == 'block') |
39
+ | `output.additional_context` | Get the additional context that was added |
40
+
41
+ ## Hook Exit Codes
42
+
43
+ | Exit Code | Behavior |
44
+ |-----------|----------|
45
+ | `exit 0` | Operation continues<br/>**`STDOUT` added as context to Claude** |
46
+ | `exit 1` | Non-blocking error<br/>`STDERR` shown to user |
47
+ | `exit 2` | **Blocks prompt processing**<br/>**Erases prompt**<br/>`STDERR` shown to user only |