Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions sdk/guides/hooks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,27 @@
| SessionStart | When conversation starts | No |
| SessionEnd | When conversation ends | No |

## Exit Codes

Hook scripts signal their result through their exit code. The SDK matches the
[Claude Code hook contract](https://docs.claude.com/en/docs/claude-code/hooks):

- **`0` — success.** The operation proceeds. `stdout` is parsed as JSON for
structured output (`decision`, `reason`, `additionalContext`, `continue`).
- **`2` — block.** The operation is denied. For `PreToolUse` and
`UserPromptSubmit` this rejects the action; for `Stop` it prevents the
agent from finishing and the conversation continues. `stderr` / `reason`
is surfaced as feedback.
- **Any other non-zero exit code — non-blocking error.** `success` is set to
`False` and the error is logged via `HookExecutionEvent`, but the
operation still proceeds.

<Warning>
Only exit code `2` blocks. Exit code `1` (the conventional Unix failure
code) is treated as a non-blocking error. A hook intended to enforce a
policy must exit with `2`.
</Warning>

## Key Concepts

- Registration points: subscribe to events or attach pre/post hooks around LLM calls and tool execution
Expand Down Expand Up @@ -202,7 +223,7 @@
```bash
#!/bin/bash
# PreToolUse hook: Block dangerous rm -rf commands
# Uses jq for JSON parsing (needed for nested fields like tool_input.command)

Check warning on line 226 in sdk/guides/hooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/hooks.mdx#L226

Did you really mean 'jq'?

input=$(cat)
command=$(echo "$input" | jq -r '.tool_input.command // ""')
Expand All @@ -211,7 +232,7 @@
if [[ "$command" =~ "rm -rf" ]]; then
echo '{"decision": "deny", "reason": "rm -rf commands are blocked for safety"}'
exit 2 # Exit code 2 = block the operation
fi

Check warning on line 235 in sdk/guides/hooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/hooks.mdx#L235

Did you really mean 'fi'?

exit 0 # Exit code 0 = allow the operation
```
Expand All @@ -221,7 +242,7 @@
```bash
#!/bin/bash
# PostToolUse hook: Log all tool usage
# Uses OPENHANDS_TOOL_NAME env var (no jq/python needed!)

Check warning on line 245 in sdk/guides/hooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/hooks.mdx#L245

Did you really mean 'jq'?

# LOG_FILE should be set by the calling script
LOG_FILE="${LOG_FILE:-/tmp/tool_usage.log}"
Expand All @@ -245,10 +266,10 @@
status=$(git status --short 2>/dev/null | head -10)
if [ -n "$status" ]; then
# Escape for JSON
escaped=$(echo "$status" | sed 's/"/\\"/g' | tr '\n' ' ')

Check warning on line 269 in sdk/guides/hooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/hooks.mdx#L269

Did you really mean 'sed'?
echo "{\"additionalContext\": \"Current git status: $escaped\"}"
fi
fi

Check warning on line 272 in sdk/guides/hooks.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

sdk/guides/hooks.mdx#L272

'fi' is repeated!
fi
exit 0
```
Expand Down
Loading