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.
- checksums.yaml +4 -4
- data/.agents/skills/ci-monitoring/SKILL.md +103 -0
- data/.agents/skills/run-tests/SKILL.md +45 -0
- data/.claude/auto-fix.md +7 -0
- data/.claude/settings.local.json +21 -0
- data/AGENTS.md +46 -0
- data/CHANGELOG.md +93 -0
- data/README.md +159 -21
- data/docs/1.1.0_UPGRADE_GUIDE.md +269 -0
- data/docs/API/COMMON.md +7 -0
- data/docs/API/CONFIG_CHANGE.md +39 -0
- data/docs/API/CWD_CHANGED.md +34 -0
- data/docs/API/ELICITATION.md +44 -0
- data/docs/API/ELICITATION_RESULT.md +43 -0
- data/docs/API/FILE_CHANGED.md +37 -0
- data/docs/API/INSTRUCTIONS_LOADED.md +30 -0
- data/docs/API/MESSAGE_DISPLAY.md +38 -0
- data/docs/API/NOTIFICATION.md +1 -0
- data/docs/API/PERMISSION_DENIED.md +37 -0
- data/docs/API/PERMISSION_REQUEST.md +199 -0
- data/docs/API/POST_COMPACT.md +30 -0
- data/docs/API/POST_TOOL_BATCH.md +39 -0
- data/docs/API/POST_TOOL_USE.md +1 -0
- data/docs/API/POST_TOOL_USE_FAILURE.md +31 -0
- data/docs/API/PRE_COMPACT.md +10 -2
- data/docs/API/PRE_TOOL_USE.md +9 -1
- data/docs/API/SETUP.md +37 -0
- data/docs/API/STOP_FAILURE.md +19 -0
- data/docs/API/SUBAGENT_START.md +40 -0
- data/docs/API/TASK_COMPLETED.md +43 -0
- data/docs/API/TASK_CREATED.md +43 -0
- data/docs/API/TEAMMATE_IDLE.md +40 -0
- data/docs/API/USER_PROMPT_EXPANSION.md +43 -0
- data/docs/API/WORKTREE_CREATE.md +39 -0
- data/docs/API/WORKTREE_REMOVE.md +33 -0
- data/docs/PROMPT_BASED_HOOKS.md +386 -0
- data/docs/external/claude-hooks-reference.md +2846 -18
- data/docs/mitts/ideabox.md +12 -0
- data/docs/mitts/prd.md +417 -0
- data/docs/mitts/setup.md +303 -0
- data/docs/mitts/task.md +44 -0
- data/lib/claude_hooks/base.rb +30 -1
- data/lib/claude_hooks/config_change.rb +28 -0
- data/lib/claude_hooks/cwd_changed.rb +28 -0
- data/lib/claude_hooks/elicitation.rb +61 -0
- data/lib/claude_hooks/elicitation_result.rb +57 -0
- data/lib/claude_hooks/file_changed.rb +41 -0
- data/lib/claude_hooks/instructions_loaded.rb +23 -0
- data/lib/claude_hooks/message_display.rb +58 -0
- data/lib/claude_hooks/notification.rb +5 -1
- data/lib/claude_hooks/output/base.rb +48 -1
- data/lib/claude_hooks/output/config_change.rb +47 -0
- data/lib/claude_hooks/output/cwd_changed.rb +42 -0
- data/lib/claude_hooks/output/elicitation.rb +67 -0
- data/lib/claude_hooks/output/elicitation_result.rb +63 -0
- data/lib/claude_hooks/output/file_changed.rb +42 -0
- data/lib/claude_hooks/output/instructions_loaded.rb +19 -0
- data/lib/claude_hooks/output/message_display.rb +49 -0
- data/lib/claude_hooks/output/permission_denied.rb +42 -0
- data/lib/claude_hooks/output/permission_request.rb +120 -0
- data/lib/claude_hooks/output/post_compact.rb +18 -0
- data/lib/claude_hooks/output/post_tool_batch.rb +51 -0
- data/lib/claude_hooks/output/post_tool_use.rb +12 -0
- data/lib/claude_hooks/output/post_tool_use_failure.rb +42 -0
- data/lib/claude_hooks/output/pre_compact.rb +34 -3
- data/lib/claude_hooks/output/pre_tool_use.rb +26 -2
- data/lib/claude_hooks/output/session_start.rb +30 -8
- data/lib/claude_hooks/output/setup.rb +42 -0
- data/lib/claude_hooks/output/stop.rb +15 -0
- data/lib/claude_hooks/output/stop_failure.rb +19 -0
- data/lib/claude_hooks/output/subagent_start.rb +42 -0
- data/lib/claude_hooks/output/task_completed.rb +18 -0
- data/lib/claude_hooks/output/task_created.rb +18 -0
- data/lib/claude_hooks/output/teammate_idle.rb +18 -0
- data/lib/claude_hooks/output/user_prompt_expansion.rb +51 -0
- data/lib/claude_hooks/output/worktree_create.rb +60 -0
- data/lib/claude_hooks/output/worktree_remove.rb +19 -0
- data/lib/claude_hooks/permission_denied.rb +41 -0
- data/lib/claude_hooks/permission_request.rb +63 -0
- data/lib/claude_hooks/post_compact.rb +23 -0
- data/lib/claude_hooks/post_tool_batch.rb +59 -0
- data/lib/claude_hooks/post_tool_use.rb +15 -1
- data/lib/claude_hooks/post_tool_use_failure.rb +45 -0
- data/lib/claude_hooks/pre_compact.rb +7 -0
- data/lib/claude_hooks/pre_tool_use.rb +34 -1
- data/lib/claude_hooks/session_start.rb +28 -0
- data/lib/claude_hooks/setup.rb +25 -0
- data/lib/claude_hooks/stop.rb +17 -0
- data/lib/claude_hooks/stop_failure.rb +27 -0
- data/lib/claude_hooks/subagent_start.rb +23 -0
- data/lib/claude_hooks/subagent_stop.rb +5 -1
- data/lib/claude_hooks/task_completed.rb +35 -0
- data/lib/claude_hooks/task_created.rb +35 -0
- data/lib/claude_hooks/teammate_idle.rb +23 -0
- data/lib/claude_hooks/user_prompt_expansion.rb +45 -0
- data/lib/claude_hooks/version.rb +1 -1
- data/lib/claude_hooks/worktree_create.rb +27 -0
- data/lib/claude_hooks/worktree_remove.rb +19 -0
- data/lib/claude_hooks.rb +42 -0
- metadata +76 -2
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# PermissionRequest API
|
|
2
|
+
|
|
3
|
+
Available when inheriting from `ClaudeHooks::PermissionRequest`:
|
|
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 requiring permission |
|
|
13
|
+
| `tool_input` | Get the input data for the tool |
|
|
14
|
+
| `tool_use_id` | Get the unique identifier for this tool use |
|
|
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
|
+
| `allow_permission!(reason = '')` | Allow the permission request with optional reason |
|
|
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
|
+
|
|
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.allowed?` | Check if permission has been allowed |
|
|
35
|
+
| `output.denied?` | Check if permission has been denied |
|
|
36
|
+
| `output.input_updated?` | Check if tool input has been updated |
|
|
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 |
|
|
43
|
+
|
|
44
|
+
## Hook Exit Codes
|
|
45
|
+
|
|
46
|
+
PermissionRequest hooks use the JSON API with exit code 0 for all permission decisions.
|
|
47
|
+
|
|
48
|
+
| Exit Code | Behavior |
|
|
49
|
+
|-----------|----------|
|
|
50
|
+
| `exit 0` | Permission decision processed<br/>`STDOUT` contains JSON with decision |
|
|
51
|
+
| `exit 1` | Non-blocking error<br/>`STDERR` shown to user |
|
|
52
|
+
| `exit 2` | **Not recommended for PermissionRequest**<br/>Use JSON API with exit 0 instead |
|
|
53
|
+
|
|
54
|
+
## Example: Basic Permission Guard
|
|
55
|
+
|
|
56
|
+
```ruby
|
|
57
|
+
#!/usr/bin/env ruby
|
|
58
|
+
require 'claude_hooks'
|
|
59
|
+
|
|
60
|
+
class PermissionGuard < ClaudeHooks::PermissionRequest
|
|
61
|
+
SENSITIVE_TOOLS = %w[rm git-push curl wget].freeze
|
|
62
|
+
SAFE_TOOLS = %w[ls cat grep find].freeze
|
|
63
|
+
|
|
64
|
+
def call
|
|
65
|
+
log "Permission requested for: #{tool_name}"
|
|
66
|
+
log "Tool use ID: #{tool_use_id}"
|
|
67
|
+
log "Permission mode: #{permission_mode}"
|
|
68
|
+
|
|
69
|
+
# Auto-allow safe tools
|
|
70
|
+
if SAFE_TOOLS.include?(tool_name)
|
|
71
|
+
allow_permission!("Safe tool, automatically allowed")
|
|
72
|
+
return output
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Block dangerous tools
|
|
76
|
+
if SENSITIVE_TOOLS.include?(tool_name)
|
|
77
|
+
deny_permission!("Dangerous tool #{tool_name} requires manual approval")
|
|
78
|
+
return output
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Default: allow with logging
|
|
82
|
+
allow_permission!("Tool allowed by default")
|
|
83
|
+
output
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
if __FILE__ == $PROGRAM_NAME
|
|
88
|
+
input_data = JSON.parse(STDIN.read)
|
|
89
|
+
hook = PermissionGuard.new(input_data)
|
|
90
|
+
hook.call
|
|
91
|
+
hook.output_and_exit
|
|
92
|
+
end
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Example: Permission Mode-Aware Guard
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
#!/usr/bin/env ruby
|
|
99
|
+
require 'claude_hooks'
|
|
100
|
+
|
|
101
|
+
class SmartPermissionGuard < ClaudeHooks::PermissionRequest
|
|
102
|
+
DANGEROUS_TOOLS = %w[rm git-reset curl wget].freeze
|
|
103
|
+
|
|
104
|
+
def call
|
|
105
|
+
log "Permission mode: #{permission_mode}"
|
|
106
|
+
|
|
107
|
+
# Block dangerous tools in bypass mode
|
|
108
|
+
if permission_mode == 'bypassPermissions' && dangerous_tool?
|
|
109
|
+
log "Blocking dangerous tool in bypass mode", level: :warn
|
|
110
|
+
deny_permission!("Cannot bypass permissions for dangerous tool: #{tool_name}")
|
|
111
|
+
return output
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Allow in 'dontAsk' mode if tool is not dangerous
|
|
115
|
+
if permission_mode == 'dontAsk' && !dangerous_tool?
|
|
116
|
+
allow_permission!("Auto-allowed in dontAsk mode")
|
|
117
|
+
return output
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Default behavior
|
|
121
|
+
allow_permission!("Permission granted")
|
|
122
|
+
output
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
def dangerous_tool?
|
|
128
|
+
DANGEROUS_TOOLS.include?(tool_name)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Example: Input Modification
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
#!/usr/bin/env ruby
|
|
137
|
+
require 'claude_hooks'
|
|
138
|
+
|
|
139
|
+
class InputSanitizer < ClaudeHooks::PermissionRequest
|
|
140
|
+
def call
|
|
141
|
+
case tool_name
|
|
142
|
+
when 'Bash'
|
|
143
|
+
# Add safety flags to bash commands
|
|
144
|
+
if tool_input['command']&.include?('rm')
|
|
145
|
+
sanitized_input = tool_input.merge(
|
|
146
|
+
'command' => tool_input['command'] + ' --interactive'
|
|
147
|
+
)
|
|
148
|
+
update_input_and_allow!(sanitized_input, "Added --interactive flag for safety")
|
|
149
|
+
else
|
|
150
|
+
allow_permission!("Bash command is safe")
|
|
151
|
+
end
|
|
152
|
+
when 'Write'
|
|
153
|
+
# Validate file paths before writing
|
|
154
|
+
if tool_input['file_path']&.start_with?('/tmp')
|
|
155
|
+
deny_permission!("Cannot write to /tmp directory")
|
|
156
|
+
else
|
|
157
|
+
allow_permission!("File write is safe")
|
|
158
|
+
end
|
|
159
|
+
else
|
|
160
|
+
allow_permission!("No special handling needed")
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
output
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Multiple Hooks Merging
|
|
169
|
+
|
|
170
|
+
When multiple PermissionRequest hooks are executed, their outputs merge with these rules:
|
|
171
|
+
|
|
172
|
+
- **Decision**: `deny` > `allow` (most restrictive wins)
|
|
173
|
+
- **Reasons**: All `decision.message` values are concatenated with `'; '`
|
|
174
|
+
- **Updated Input**: Last `decision.updatedInput` wins (most recent transformation)
|
|
175
|
+
|
|
176
|
+
```ruby
|
|
177
|
+
# Hook 1
|
|
178
|
+
hook1.deny_permission!("Reason 1")
|
|
179
|
+
|
|
180
|
+
# Hook 2
|
|
181
|
+
hook2.allow_permission!("Reason 2")
|
|
182
|
+
|
|
183
|
+
# Merged result
|
|
184
|
+
merged = ClaudeHooks::Output::PermissionRequest.merge(
|
|
185
|
+
hook1.output,
|
|
186
|
+
hook2.output
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
merged.denied? # => true (deny wins)
|
|
190
|
+
merged.permission_reason # => "Reason 1; Reason 2"
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Notes
|
|
194
|
+
|
|
195
|
+
- PermissionRequest runs when Claude Code shows a permission dialog
|
|
196
|
+
- It can automatically allow or deny on behalf of the user
|
|
197
|
+
- Uses the same JSON API pattern as PreToolUse hooks
|
|
198
|
+
- Supports modifying tool inputs before execution
|
|
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 |
|
data/docs/API/POST_TOOL_USE.md
CHANGED
|
@@ -12,6 +12,7 @@ Input helpers to access the data provided by Claude Code through `STDIN`.
|
|
|
12
12
|
| `tool_name` | Get the name of the tool that was used |
|
|
13
13
|
| `tool_input` | Get the input that was passed to the tool |
|
|
14
14
|
| `tool_response` | Get the tool's response/output |
|
|
15
|
+
| `tool_use_id` | Get the unique identifier for this tool use (e.g., `"toolu_01ABC123..."`) |
|
|
15
16
|
|
|
16
17
|
## Hook State Helpers
|
|
17
18
|
Hook state methods are helpers to modify the hook's internal state (`output_data`) before yielding back to Claude Code.
|
|
@@ -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.
|
data/docs/API/PRE_COMPACT.md
CHANGED
|
@@ -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 |
|
data/docs/API/PRE_TOOL_USE.md
CHANGED
|
@@ -11,6 +11,7 @@ Input helpers to access the data provided by Claude Code through `STDIN`.
|
|
|
11
11
|
|--------|-------------|
|
|
12
12
|
| `tool_name` | Get the name of the tool being used |
|
|
13
13
|
| `tool_input` | Get the input data for the tool |
|
|
14
|
+
| `tool_use_id` | Get the unique identifier for this tool use (e.g., `"toolu_01ABC123..."`) |
|
|
14
15
|
|
|
15
16
|
## Hook State Helpers
|
|
16
17
|
Hook state methods are helpers to modify the hook's internal state (`output_data`) before yielding back to Claude Code.
|
|
@@ -22,6 +23,10 @@ Hook state methods are helpers to modify the hook's internal state (`output_data
|
|
|
22
23
|
| `approve_tool!(reason)` | Explicitly approve tool usage |
|
|
23
24
|
| `block_tool!(reason)` | Block tool usage with feedback |
|
|
24
25
|
| `ask_for_permission!(reason)` | Request user permission |
|
|
26
|
+
| `defer_permission!` | Defer the permission decision to a later hook in the chain |
|
|
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 |
|
|
25
30
|
|
|
26
31
|
## Output Helpers
|
|
27
32
|
Output helpers provide access to the hook's output data and helper methods for working with the output state.
|
|
@@ -33,9 +38,12 @@ Output helpers provide access to the hook's output data and helper methods for w
|
|
|
33
38
|
| `output.allowed?` | Check if the tool has been explicitly allowed (permission_decision == 'allow') |
|
|
34
39
|
| `output.denied?` | Check if the tool has been denied (permission_decision == 'deny') |
|
|
35
40
|
| `output.blocked?` | Alias for `denied?` |
|
|
41
|
+
| `output.deferred?` | Check if the permission decision was deferred (permission_decision == 'defer') |
|
|
36
42
|
| `output.should_ask_permission?` | Check if user permission is required (permission_decision == 'ask') |
|
|
37
|
-
| `output.
|
|
43
|
+
| `output.input_updated?` | Check if tool input has been updated |
|
|
44
|
+
| `output.permission_decision` | Get the permission decision: `'allow'`, `'deny'`, `'ask'`, or `'defer'` |
|
|
38
45
|
| `output.permission_reason` | Get the reason for the permission decision |
|
|
46
|
+
| `output.updated_input` | Get the updated input (if provided) |
|
|
39
47
|
|
|
40
48
|
## Hook Exit Codes
|
|
41
49
|
|
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 |
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# TaskCompleted API
|
|
2
|
+
|
|
3
|
+
Available when inheriting from `ClaudeHooks::TaskCompleted`:
|
|
4
|
+
|
|
5
|
+
Runs when a teammate task completes. Can block Claude from continuing via `prevent_continue!` or exit 2.
|
|
6
|
+
|
|
7
|
+
## Input Helpers
|
|
8
|
+
|
|
9
|
+
[📚 Shared input helpers](COMMON.md#input-helpers)
|
|
10
|
+
|
|
11
|
+
| Method | Description |
|
|
12
|
+
|--------|-------------|
|
|
13
|
+
| `task_id` | The unique task ID |
|
|
14
|
+
| `task_subject` | Short title of the task |
|
|
15
|
+
| `task_description` | Optional longer description |
|
|
16
|
+
| `teammate_name` | The teammate who completed the task |
|
|
17
|
+
| `team_name` | The team name |
|
|
18
|
+
|
|
19
|
+
## Hook State Helpers
|
|
20
|
+
|
|
21
|
+
[📚 Shared hook state methods](COMMON.md#hook-state-methods)
|
|
22
|
+
|
|
23
|
+
| Method | Description |
|
|
24
|
+
|--------|-------------|
|
|
25
|
+
| `prevent_continue!(reason)` | Block Claude from continuing (`continue: false` + `stopReason`) |
|
|
26
|
+
|
|
27
|
+
There is no top-level `decision` field for this event — block via `prevent_continue!` or exit 2.
|
|
28
|
+
|
|
29
|
+
## Output Helpers
|
|
30
|
+
|
|
31
|
+
[📚 Shared output helpers](COMMON.md#output-helpers)
|
|
32
|
+
|
|
33
|
+
| Method | Description |
|
|
34
|
+
|--------|-------------|
|
|
35
|
+
| `output.continue?` | Whether Claude will continue |
|
|
36
|
+
| `output.stop_reason` | The reason Claude was stopped |
|
|
37
|
+
|
|
38
|
+
## Hook Exit Codes
|
|
39
|
+
|
|
40
|
+
| Exit Code | Behavior |
|
|
41
|
+
|-----------|----------|
|
|
42
|
+
| `exit 0` | Claude continues |
|
|
43
|
+
| `exit 2` | Blocks Claude (`continue: false`) |
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# TaskCreated API
|
|
2
|
+
|
|
3
|
+
Available when inheriting from `ClaudeHooks::TaskCreated`:
|
|
4
|
+
|
|
5
|
+
Runs when a teammate task is created. Can block Claude from continuing via `prevent_continue!` or exit 2.
|
|
6
|
+
|
|
7
|
+
## Input Helpers
|
|
8
|
+
|
|
9
|
+
[📚 Shared input helpers](COMMON.md#input-helpers)
|
|
10
|
+
|
|
11
|
+
| Method | Description |
|
|
12
|
+
|--------|-------------|
|
|
13
|
+
| `task_id` | The unique task ID |
|
|
14
|
+
| `task_subject` | Short title of the task |
|
|
15
|
+
| `task_description` | Optional longer description |
|
|
16
|
+
| `teammate_name` | The teammate assigned to the task |
|
|
17
|
+
| `team_name` | The team name |
|
|
18
|
+
|
|
19
|
+
## Hook State Helpers
|
|
20
|
+
|
|
21
|
+
[📚 Shared hook state methods](COMMON.md#hook-state-methods)
|
|
22
|
+
|
|
23
|
+
| Method | Description |
|
|
24
|
+
|--------|-------------|
|
|
25
|
+
| `prevent_continue!(reason)` | Block Claude from continuing (`continue: false` + `stopReason`) |
|
|
26
|
+
|
|
27
|
+
There is no top-level `decision` field for this event — block via `prevent_continue!` or exit 2.
|
|
28
|
+
|
|
29
|
+
## Output Helpers
|
|
30
|
+
|
|
31
|
+
[📚 Shared output helpers](COMMON.md#output-helpers)
|
|
32
|
+
|
|
33
|
+
| Method | Description |
|
|
34
|
+
|--------|-------------|
|
|
35
|
+
| `output.continue?` | Whether Claude will continue |
|
|
36
|
+
| `output.stop_reason` | The reason Claude was stopped |
|
|
37
|
+
|
|
38
|
+
## Hook Exit Codes
|
|
39
|
+
|
|
40
|
+
| Exit Code | Behavior |
|
|
41
|
+
|-----------|----------|
|
|
42
|
+
| `exit 0` | Claude continues |
|
|
43
|
+
| `exit 2` | Blocks Claude (`continue: false`) |
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# TeammateIdle API
|
|
2
|
+
|
|
3
|
+
Available when inheriting from `ClaudeHooks::TeammateIdle`:
|
|
4
|
+
|
|
5
|
+
Runs when a teammate goes idle. Can block Claude from continuing via `prevent_continue!` or exit 2.
|
|
6
|
+
|
|
7
|
+
## Input Helpers
|
|
8
|
+
|
|
9
|
+
[📚 Shared input helpers](COMMON.md#input-helpers)
|
|
10
|
+
|
|
11
|
+
| Method | Description |
|
|
12
|
+
|--------|-------------|
|
|
13
|
+
| `teammate_name` | The name of the idle teammate |
|
|
14
|
+
| `team_name` | The team name |
|
|
15
|
+
|
|
16
|
+
## Hook State Helpers
|
|
17
|
+
|
|
18
|
+
[📚 Shared hook state methods](COMMON.md#hook-state-methods)
|
|
19
|
+
|
|
20
|
+
| Method | Description |
|
|
21
|
+
|--------|-------------|
|
|
22
|
+
| `prevent_continue!(reason)` | Block Claude from continuing (`continue: false` + `stopReason`) |
|
|
23
|
+
|
|
24
|
+
There is no top-level `decision` field for this event — block via `prevent_continue!` or exit 2.
|
|
25
|
+
|
|
26
|
+
## Output Helpers
|
|
27
|
+
|
|
28
|
+
[📚 Shared output helpers](COMMON.md#output-helpers)
|
|
29
|
+
|
|
30
|
+
| Method | Description |
|
|
31
|
+
|--------|-------------|
|
|
32
|
+
| `output.continue?` | Whether Claude will continue |
|
|
33
|
+
| `output.stop_reason` | The reason Claude was stopped |
|
|
34
|
+
|
|
35
|
+
## Hook Exit Codes
|
|
36
|
+
|
|
37
|
+
| Exit Code | Behavior |
|
|
38
|
+
|-----------|----------|
|
|
39
|
+
| `exit 0` | Claude continues |
|
|
40
|
+
| `exit 2` | Blocks Claude (`continue: false`) |
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# UserPromptExpansion API
|
|
2
|
+
|
|
3
|
+
Available when inheriting from `ClaudeHooks::UserPromptExpansion`:
|
|
4
|
+
|
|
5
|
+
Runs when a slash command or other prompt-expansion mechanism is triggered. Can block the expansion.
|
|
6
|
+
|
|
7
|
+
## Input Helpers
|
|
8
|
+
|
|
9
|
+
[📚 Shared input helpers](COMMON.md#input-helpers)
|
|
10
|
+
|
|
11
|
+
| Method | Description |
|
|
12
|
+
|--------|-------------|
|
|
13
|
+
| `expansion_type` | Type of expansion (e.g. `'slash_command'`) |
|
|
14
|
+
| `command_name` | The command name (without the `/`) |
|
|
15
|
+
| `command_args` | The arguments passed to the command |
|
|
16
|
+
| `command_source` | Where the command was defined (`'user'`, `'project'`, etc.) |
|
|
17
|
+
| `prompt` | The expanded prompt text |
|
|
18
|
+
|
|
19
|
+
## Hook State Helpers
|
|
20
|
+
|
|
21
|
+
[📚 Shared hook state methods](COMMON.md#hook-state-methods)
|
|
22
|
+
|
|
23
|
+
| Method | Description |
|
|
24
|
+
|--------|-------------|
|
|
25
|
+
| `block!(reason)` | Block the expansion with a reason |
|
|
26
|
+
| `add_additional_context!(context)` | Add additional context visible to Claude |
|
|
27
|
+
|
|
28
|
+
## Output Helpers
|
|
29
|
+
|
|
30
|
+
[📚 Shared output helpers](COMMON.md#output-helpers)
|
|
31
|
+
|
|
32
|
+
| Method | Description |
|
|
33
|
+
|--------|-------------|
|
|
34
|
+
| `output.blocked?` | Check if the expansion was blocked |
|
|
35
|
+
| `output.decision` | Get the decision (`'block'` or nil) |
|
|
36
|
+
| `output.reason` | Get the block reason |
|
|
37
|
+
|
|
38
|
+
## Hook Exit Codes
|
|
39
|
+
|
|
40
|
+
| Exit Code | Behavior |
|
|
41
|
+
|-----------|----------|
|
|
42
|
+
| `exit 0` | Expansion proceeds |
|
|
43
|
+
| `exit 2` | Blocks the expansion; `STDERR` shown to Claude |
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# WorktreeCreate API
|
|
2
|
+
|
|
3
|
+
Available when inheriting from `ClaudeHooks::WorktreeCreate`:
|
|
4
|
+
|
|
5
|
+
Runs when Claude Code is about to create a git worktree. **Special contract**: the hook must print the worktree path as the last non-empty line of stdout and exit 0. An empty or missing path is treated as failure.
|
|
6
|
+
|
|
7
|
+
## Input Helpers
|
|
8
|
+
|
|
9
|
+
[📚 Shared input helpers](COMMON.md#input-helpers)
|
|
10
|
+
|
|
11
|
+
| Method | Description |
|
|
12
|
+
|--------|-------------|
|
|
13
|
+
| `name` | The slug/name for the worktree (e.g. `'feature-x'`) |
|
|
14
|
+
|
|
15
|
+
## Hook State Helpers
|
|
16
|
+
|
|
17
|
+
[📚 Shared hook state methods](COMMON.md#hook-state-methods)
|
|
18
|
+
|
|
19
|
+
| Method | Description |
|
|
20
|
+
|--------|-------------|
|
|
21
|
+
| `worktree_path!(path)` | Set the path where the worktree will be created |
|
|
22
|
+
|
|
23
|
+
## Output Helpers
|
|
24
|
+
|
|
25
|
+
[📚 Shared output helpers](COMMON.md#output-helpers)
|
|
26
|
+
|
|
27
|
+
| Method | Description |
|
|
28
|
+
|--------|-------------|
|
|
29
|
+
| `output.worktree_path` | Get the configured worktree path |
|
|
30
|
+
|
|
31
|
+
## Hook Exit Codes
|
|
32
|
+
|
|
33
|
+
| Exit Code | Behavior |
|
|
34
|
+
|-----------|----------|
|
|
35
|
+
| `exit 0` (with path on stdout) | Worktree created at the printed path |
|
|
36
|
+
| `exit 1` / empty stdout | Creation fails |
|
|
37
|
+
|
|
38
|
+
> [!IMPORTANT]
|
|
39
|
+
> `output_and_exit` for WorktreeCreate prints the **bare path** (not JSON). Do not emit JSON for this hook type.
|