From 396f9c1b44fad8463c3512943ab8561e3e36ac19 Mon Sep 17 00:00:00 2001 From: openhands Date: Thu, 7 May 2026 11:19:29 +0000 Subject: [PATCH] docs(sdk-hooks): add explicit Exit Codes section to SDK hooks guide The companion 'Hooks' page under openhands/usage/customization/ already spells out the 0 / 2 / other exit-code semantics, but the SDK guide (sdk/guides/hooks.mdx) only mentions 'Yes (exit 2)' in the can-block column of the Hook Types table. That leaves SDK developers reading this guide to assume the conventional Unix 'non-zero = failure = block' behavior, which does not match how the SDK (or Claude Code) actually treat hook exit codes. Add an explicit 'Exit Codes' section, mirroring the wording used in the customization docs and Claude Code's own hooks reference, including a Warning that only exit code 2 blocks. Companion to OpenHands/software-agent-sdk PR that updates the SDK HookResult docstring and 33_hooks example README with the same clarification. Co-authored-by: openhands --- sdk/guides/hooks.mdx | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/sdk/guides/hooks.mdx b/sdk/guides/hooks.mdx index 72ec3f262..2ceefb871 100644 --- a/sdk/guides/hooks.mdx +++ b/sdk/guides/hooks.mdx @@ -25,6 +25,27 @@ Hooks let you observe and customize key lifecycle moments in the SDK without for | 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. + + +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`. + + ## Key Concepts - Registration points: subscribe to events or attach pre/post hooks around LLM calls and tool execution