stdin, and can return JSON on stdout to do the following:
- Add context to the chat
- Prevent prompts from being sent
- Automatically approve or deny tools
- Modify tool call input before tools are executed
- Force the model to continue iterating when it stops
if conditions, CLAUDE_ENV_FILE, transcript files, and async hooks are not supported, and statusMessage and suppressOutput are ignored.
We also don’t support the following Claude Code hook types, which don’t have dirrect equivalents in Piebald: SessionEnd, Notification, ConfigChange, CwdChanged, FileChanged, InstructionsLoaded, WorktreeCreate, WorktreeRemove, Elicitation, ElicitationResult, TaskCreated, TaskCompleted, TeammateIdle, and PermissionRequest.
If you need any of those features, let us know.
Quick Start
Piebald uses Claude Code’s hook format. We don’t have a custom hooks format, so all of your Claude Code hooks should work without modification in Piebald (except such as make use of functionality we don’t yet support). To get started with Claude Code hooks, create a.claude/settings.json file in your project:
.claude/settings.json, you’ll need to create a new chat in that project. After changing global hooks in ~/.claude/settings.json, restart Piebald to reload the global hooks cache.
Configuration Files
Hooks are loaded from Claude Code-compatible settings files:
Later configs append hook handlers. For example, if both global and project files define
PreToolUse, both sets of handlers can run.
A hook group has a matcher and a list of hook handlers:
Matchers are case-sensitive regexes. Invalid regexes won’t match.
Supported Events
SessionEnd isn’t supported because Piebald sessions don’t necessarily ever end like they do in Claude Code.
Hook Execution
Hook commands run through the platform shell:
Hook input JSON is sent to the command’s
stdin and reads stdout and stderr.
Hook commands receive these environment variables:
Matched hook handlers run in parallel. If multiple hooks return decisions, Piebald resolves the decision according to the event rules below.
Common Input
Every hook receives a JSON object with common fields:Output Format
Hooks can print JSON tostdout:
stdout for successful hooks. If a hook exits with code 0 and stdout isn’t valid JSON, the text is treated as additionalContext.
Exit Codes
UserPromptSubmit
UserPromptSubmit runs after you press Enter but before the message is actually sent.
Matcher value: submit
Input includes:
2; stderr will be used as the block reason.
To add context to the message, return additionalContext:
PreToolUse
PreToolUse runs after a tool call is generated but before it’s executed. It can override approval decision that would usually be applied by the selected permission mode.
Matcher value: the Claude Code tool name, such as Bash, Read, Edit, or mcp__github__create_issue.
Input includes:
If multiple hooks return conflicting decisions, the most restrictive decision wins, so deny > ask > allow.
A
PreToolUse hook can also modify tool input with updatedInput:
ask, and the user manually approves the tool later, PreToolUse isn’t run again for that approval.
PostToolUse
PostToolUse runs after a tool completes successfully.
Matcher value: the Claude Code tool name.
Input includes:
PostToolUse can’t prevent a tool that already ran. If it returns decision: "block", the reason is queued as context for the model’s next turn:
additionalContext to add information for the next model turn.
PostToolUseFailure
PostToolUseFailure runs when a tool fails.
Matcher value: the Claude Code tool name.
Input includes:
additionalContext is queued for the model.
Stop and SubagentStop
Stop runs when a normal chat generation would finish. SubagentStop uses the same behavior for subagent chats.
Matcher value:
Input includes:
SubagentStop, input also includes:
decision: "block" with a reason:
continue: false:
continue: false takes precedence over decision: "block".
continue: true doesn’t mean “keep generating”. It’s treated as no opinion. Use decision: "block" or exit code 2 to request continuation.SessionStart
SessionStart runs when a chat starts.
Matcher value:
Input includes:
additionalContext to queue context for the chat.
Compaction Hooks
PreCompact runs before compaction, and PostCompact runs after compaction.
Matcher value: manual or auto
PreCompact input includes:
PostCompact input includes:
StopFailure
StopFailure runs when generation fails.
Matcher value: the classified error type, such as rate_limit, authentication_failed, timeout, network_error, cancelled, or unknown.
Input includes:
SubagentStart
SubagentStart runs after a subagent chat is created and before its first message.
Matcher value: default
Input includes:
additionalContext to inject context into the subagent’s first message.
Tool Name Mapping
Tool names are automatically mapped to Claude Code tool names:Task is accepted as an alias for Agent in matchers.
Tool Input Reshaping
Before tool input is sent to hooks, it’s somewhat reshaped to match Claude Code’s field names:
When
PreToolUse returns updatedInput, Piebald converts the Claude Code-shaped input back into Piebald’s internal shape before executing the tool.