ClaudeAgentSDK.ControlProtocol.Protocol (claude_agent_sdk v0.6.9)

View Source

Control protocol message encoding and decoding.

Handles bidirectional communication with Claude CLI via control messages:

  • Initialize requests with hooks configuration
  • Hook callback requests/responses
  • Control requests/responses

Messages are exchanged as JSON over stdin/stdout.

Message Types

SDK → CLI

  • control_request with initialize subtype
  • control_response for hook callbacks

CLI → SDK

  • control_request with hook_callback subtype
  • control_response for initialize

See: https://docs.anthropic.com/en/docs/claude-code/sdk

Summary

Types

Message type classifier.

Request ID for tracking control protocol requests.

Functions

Checks if a message is a control protocol message.

Decodes a message from CLI.

Decodes a set_model control response.

Encodes a hook callback response.

Encodes an initialize request with hooks configuration and SDK MCP servers.

Encodes an interrupt control request.

Encodes a rewind_files control request.

Encodes a set_model control request.

Encodes a set_permission_mode control request.

Generates a unique request ID.

Types

message_type()

@type message_type() ::
  :control_request
  | :control_response
  | :control_cancel_request
  | :sdk_message
  | :stream_event

Message type classifier.

request_id()

@type request_id() :: String.t()

Request ID for tracking control protocol requests.

Functions

control_message?(arg1)

@spec control_message?(map()) :: boolean()

Checks if a message is a control protocol message.

Parameters

  • message - Decoded message map

Returns

true if control message, false otherwise

Examples

iex> Protocol.control_message?(%{"type" => "control_request"})
true

iex> Protocol.control_message?(%{"type" => "assistant"})
false

decode_message(json_string)

@spec decode_message(String.t()) :: {:ok, {message_type(), map()}} | {:error, term()}

Decodes a message from CLI.

Parses JSON and classifies message type.

Parameters

  • json_string - JSON message from CLI

Returns

  • {:ok, {message_type, data}} - Successfully decoded
  • {:error, reason} - Failed to decode

Examples

iex> json = ~s({"type":"control_request","request_id":"req_1","request":{}})
iex> {:ok, {type, _data}} = Protocol.decode_message(json)
iex> type
:control_request

decode_set_model_response(arg1)

@spec decode_set_model_response(map()) :: {:ok, String.t()} | {:error, term()}

Decodes a set_model control response.

encode_hook_response(request_id, output, atom)

@spec encode_hook_response(request_id(), map() | String.t(), :success | :error) ::
  String.t()

Encodes a hook callback response.

Sends the result of a hook callback execution back to CLI.

Parameters

  • request_id - Request ID from CLI's hook_callback request
  • output_or_error - Hook output map or error string
  • status - :success or :error

Returns

JSON string ready to send to CLI

Examples

# Success
output = %{hookSpecificOutput: %{permissionDecision: "allow"}}
json = Protocol.encode_hook_response("req_123", output, :success)

# Error
json = Protocol.encode_hook_response("req_456", "Timeout", :error)

encode_initialize_request(hooks_config, sdk_mcp_servers \\ nil, request_id \\ nil)

@spec encode_initialize_request(map() | nil, map() | nil, request_id() | nil) ::
  {request_id(), String.t()}

Encodes an initialize request with hooks configuration and SDK MCP servers.

Sends hooks configuration and SDK MCP server info to CLI during initialization so it knows which callbacks to invoke and which SDK servers are available.

Parameters

  • hooks_config - Hooks configuration map (from build_hooks_config)
  • sdk_mcp_servers - Map of server_name => server_info for SDK servers (optional)
  • request_id - Optional request ID (generated if nil)

Returns

{request_id, json_string} tuple

Examples

hooks = %{
  "PreToolUse" => [
    %{"matcher" => "Bash", "hookCallbackIds" => ["hook_0"]}
  ]
}

sdk_servers = %{
  "math-tools" => %{"name" => "math-tools", "version" => "1.0.0"}
}

{id, json} = Protocol.encode_initialize_request(hooks, sdk_servers, nil)

encode_interrupt_request(request_id \\ nil)

@spec encode_interrupt_request(request_id() | nil) :: {request_id(), String.t()}

Encodes an interrupt control request.

encode_rewind_files_request(user_message_id, request_id \\ nil)

@spec encode_rewind_files_request(String.t(), request_id() | nil) ::
  {request_id(), String.t()}

Encodes a rewind_files control request.

Returns {request_id, json}.

encode_set_model_request(model, request_id \\ nil)

@spec encode_set_model_request(String.t(), request_id() | nil) ::
  {request_id(), String.t()}

Encodes a set_model control request.

Returns {request_id, json}.

encode_set_permission_mode_request(mode, request_id \\ nil)

@spec encode_set_permission_mode_request(String.t(), request_id() | nil) ::
  {request_id(), String.t()}

Encodes a set_permission_mode control request.

Returns {request_id, json}.

generate_request_id()

@spec generate_request_id() :: request_id()

Generates a unique request ID.

Format: req_{counter}_{random_hex}

Examples

iex> id = Protocol.generate_request_id()
iex> String.starts_with?(id, "req_")
true