claude_hooks 0.2.0 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +98 -1
- data/README.md +221 -362
- data/claude_hooks.gemspec +2 -2
- data/docs/API/COMMON.md +83 -0
- data/docs/API/NOTIFICATION.md +32 -0
- data/docs/API/POST_TOOL_USE.md +45 -0
- data/docs/API/PRE_COMPACT.md +39 -0
- data/docs/API/PRE_TOOL_USE.md +110 -0
- data/docs/API/SESSION_END.md +100 -0
- data/docs/API/SESSION_START.md +40 -0
- data/docs/API/STOP.md +47 -0
- data/docs/API/SUBAGENT_STOP.md +47 -0
- data/docs/API/USER_PROMPT_SUBMIT.md +47 -0
- data/docs/OUTPUT_MIGRATION_GUIDE.md +228 -0
- data/example_dotclaude/hooks/entrypoints/session_end.rb +35 -0
- data/example_dotclaude/hooks/entrypoints/user_prompt_submit.rb +17 -12
- data/example_dotclaude/hooks/handlers/session_end/cleanup_handler.rb +55 -0
- data/example_dotclaude/hooks/handlers/session_end/log_session_stats.rb +64 -0
- data/example_dotclaude/hooks/handlers/user_prompt_submit/append_rules.rb +11 -9
- data/example_dotclaude/hooks/handlers/user_prompt_submit/log_user_prompt.rb +2 -14
- data/example_dotclaude/settings.json +11 -0
- data/lib/claude_hooks/base.rb +16 -24
- data/lib/claude_hooks/cli.rb +75 -1
- data/lib/claude_hooks/configuration.rb +9 -9
- data/lib/claude_hooks/logger.rb +0 -1
- data/lib/claude_hooks/output/base.rb +152 -0
- data/lib/claude_hooks/output/notification.rb +22 -0
- data/lib/claude_hooks/output/post_tool_use.rb +68 -0
- data/lib/claude_hooks/output/pre_compact.rb +20 -0
- data/lib/claude_hooks/output/pre_tool_use.rb +97 -0
- data/lib/claude_hooks/output/session_end.rb +24 -0
- data/lib/claude_hooks/output/session_start.rb +49 -0
- data/lib/claude_hooks/output/stop.rb +76 -0
- data/lib/claude_hooks/output/subagent_stop.rb +14 -0
- data/lib/claude_hooks/output/user_prompt_submit.rb +71 -0
- data/lib/claude_hooks/post_tool_use.rb +6 -12
- data/lib/claude_hooks/pre_tool_use.rb +0 -37
- data/lib/claude_hooks/session_end.rb +43 -0
- data/lib/claude_hooks/session_start.rb +0 -23
- data/lib/claude_hooks/stop.rb +0 -25
- data/lib/claude_hooks/user_prompt_submit.rb +0 -26
- data/lib/claude_hooks/version.rb +1 -1
- data/lib/claude_hooks.rb +15 -0
- metadata +33 -8
- /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.
|
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 "
|
38
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
39
39
|
end
|
data/docs/API/COMMON.md
ADDED
@@ -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 |
|