ClaudeAgentSDK.Hooks.Output (claude_agent_sdk v0.5.3)

View Source

Hook output structure and helpers.

Represents the return value from hook callbacks. Hook output controls:

  • Permission decisions (PreToolUse): allow, deny, or ask
  • Additional context (PostToolUse, UserPromptSubmit): inject information for Claude
  • Execution control: continue or stop the agent
  • User feedback: system messages and reasons

Output Fields

  • continue - Whether to continue execution (boolean)
  • stopReason - Message when stopping (string)
  • suppressOutput - Hide from transcript (boolean)
  • systemMessage - User-visible message (string)
  • reason - Claude-visible feedback (string)
  • decision - "block" for some events (string)
  • hookSpecificOutput - Event-specific control (map)

Examples

# Allow a tool
Output.allow("Security check passed")

# Deny a tool
Output.deny("Dangerous command detected")

# Add context after tool execution
Output.add_context("PostToolUse", "Command completed in 2.3s")

# Stop execution
Output.stop("Critical error occurred")

# Combine helpers
Output.deny("Invalid file path")
|> Output.with_system_message("File access restricted")
|> Output.with_reason("Path outside allowed directory")

See: https://docs.anthropic.com/en/docs/claude-code/hooks#hook-output

Summary

Types

Hook-specific output for different event types.

Permission decision for PreToolUse hooks.

PostToolUse hook-specific output.

PreToolUse hook-specific output.

SessionStart hook-specific output.

t()

Complete hook output map.

UserPromptSubmit hook-specific output.

Functions

Creates hook output to add context.

Creates hook output to allow a PreToolUse.

Creates hook output to ask the user for permission.

Creates hook output to block with decision field.

Creates hook output to continue execution.

Creates hook output to deny a PreToolUse.

Creates hook output to stop execution.

Marks output to be suppressed from transcript.

Converts Elixir output to JSON-compatible map for CLI.

Validates hook output structure.

Adds a reason to hook output.

Adds a system message to hook output.

Types

hook_specific_output()

Hook-specific output for different event types.

permission_decision()

@type permission_decision() :: :allow | :deny | :ask

Permission decision for PreToolUse hooks.

post_tool_use_output()

@type post_tool_use_output() :: %{
  hookEventName: String.t(),
  additionalContext: String.t()
}

PostToolUse hook-specific output.

Adds context for Claude to consider:

  • hookEventName - Must be "PostToolUse"
  • additionalContext - Information about tool execution

pre_tool_use_output()

@type pre_tool_use_output() :: %{
  hookEventName: String.t(),
  permissionDecision: String.t(),
  permissionDecisionReason: String.t()
}

PreToolUse hook-specific output.

Controls whether a tool call proceeds:

  • hookEventName - Must be "PreToolUse"
  • permissionDecision - "allow", "deny", or "ask"
  • permissionDecisionReason - Explanation for the decision

session_start_output()

@type session_start_output() :: %{
  hookEventName: String.t(),
  additionalContext: String.t()
}

SessionStart hook-specific output.

Adds context when session starts:

  • hookEventName - Must be "SessionStart"
  • additionalContext - Initial context for session

t()

@type t() :: %{
  optional(:continue) => boolean(),
  optional(:stopReason) => String.t(),
  optional(:suppressOutput) => boolean(),
  optional(:systemMessage) => String.t(),
  optional(:reason) => String.t(),
  optional(:decision) => String.t(),
  optional(:hookSpecificOutput) => hook_specific_output(),
  optional(atom()) => term()
}

Complete hook output map.

All fields are optional. The CLI processes these fields to control behavior.

user_prompt_submit_output()

@type user_prompt_submit_output() :: %{
  hookEventName: String.t(),
  additionalContext: String.t()
}

UserPromptSubmit hook-specific output.

Adds context before processing prompt:

  • hookEventName - Must be "UserPromptSubmit"
  • additionalContext - Contextual information to inject

Functions

add_context(event_name, context)

@spec add_context(String.t(), String.t()) :: t()

Creates hook output to add context.

Used with PostToolUse, UserPromptSubmit, or SessionStart hooks.

Parameters

  • event_name - Hook event name ("PostToolUse", "UserPromptSubmit", etc.)
  • context - Contextual information to inject

Examples

Output.add_context("PostToolUse", "Command took 2.3 seconds")
Output.add_context("UserPromptSubmit", "Current time: 10:00 AM")
Output.add_context("SessionStart", "Recent issues: #123, #124")

allow(reason \\ "Approved")

@spec allow(String.t()) :: t()

Creates hook output to allow a PreToolUse.

Parameters

  • reason - Explanation for allowing (default: "Approved")

Examples

Output.allow()
# => %{hookSpecificOutput: %{hookEventName: "PreToolUse", permissionDecision: "allow", ...}}

Output.allow("Security scan passed")

ask(reason)

@spec ask(String.t()) :: t()

Creates hook output to ask the user for permission.

The CLI will prompt the user to confirm the tool use.

Parameters

  • reason - Explanation for asking user (required)

Examples

Output.ask("Confirm deletion of 100 files")
Output.ask("Review this API call before executing")

block(reason)

@spec block(String.t()) :: t()

Creates hook output to block with decision field.

Used for certain hooks to provide feedback to Claude.

Parameters

  • reason - Explanation for blocking

Examples

Output.block("Tool execution failed validation")

continue()

@spec continue() :: t()

Creates hook output to continue execution.

Examples

Output.continue()
# => %{continue: true}

deny(reason)

@spec deny(String.t()) :: t()

Creates hook output to deny a PreToolUse.

Parameters

  • reason - Explanation for denying (required)

Examples

Output.deny("Dangerous command detected")
Output.deny("File path not allowed")

stop(reason)

@spec stop(String.t()) :: t()

Creates hook output to stop execution.

Parameters

  • reason - Explanation for stopping

Examples

Output.stop("Critical error detected")
Output.stop("Resource limit exceeded")

suppress_output(output)

@spec suppress_output(t()) :: t()

Marks output to be suppressed from transcript.

Parameters

  • output - Existing hook output

Examples

Output.allow()
|> Output.suppress_output()

to_json_map(output)

@spec to_json_map(t()) :: map()

Converts Elixir output to JSON-compatible map for CLI.

Converts atom keys to strings recursively.

Examples

iex> Output.to_json_map(%{continue: false, stopReason: "Error"})
%{"continue" => false, "stopReason" => "Error"}

iex> Output.to_json_map(%{hookSpecificOutput: %{hookEventName: "PreToolUse"}})
%{"hookSpecificOutput" => %{"hookEventName" => "PreToolUse"}}

validate(output)

@spec validate(t()) :: :ok | {:error, String.t()}

Validates hook output structure.

Returns :ok if valid, {:error, reason} otherwise.

Examples

iex> Output.validate(%{continue: true})
:ok

iex> Output.validate("not a map")
{:error, "Hook output must be a map"}

with_reason(output, reason)

@spec with_reason(t(), String.t()) :: t()

Adds a reason to hook output.

Reasons are shown to Claude to help it understand what happened.

Parameters

  • output - Existing hook output
  • reason - Claude-visible explanation

Examples

Output.deny("Invalid path")
|> Output.with_reason("Path must be within /allowed directory")

with_system_message(output, message)

@spec with_system_message(t(), String.t()) :: t()

Adds a system message to hook output.

System messages are shown to the user but not to Claude.

Parameters

  • output - Existing hook output
  • message - User-visible message

Examples

Output.deny("Command blocked")
|> Output.with_system_message("Security policy violation")