ClaudeAgentSDK.Client (claude_agent_sdk v0.6.9)
View SourceBidirectional client for Claude Code with hooks support.
This GenServer maintains a persistent connection to the Claude CLI process, handles control protocol messages, and invokes hook callbacks.
The Client enables:
- Bidirectional streaming communication
- Runtime hook callback invocation
- Control protocol request/response handling
- Message queueing and delivery
Usage
# Define hook callbacks
def check_bash(input, _tool_use_id, _context) do
if dangerous?(input), do: Output.deny("Blocked"), else: Output.allow()
end
# Configure options with hooks
options = %Options{
allowed_tools: ["Bash", "Write"],
hooks: %{
pre_tool_use: [
Matcher.new("Bash", [&check_bash/3])
]
}
}
# Start client
{:ok, pid} = Client.start_link(options)
# Send query
Client.send_message(pid, "Run: echo 'Hello'")
# Receive messages
stream = Client.stream_messages(pid)
Enum.each(stream, &IO.inspect/1)
# Stop client
Client.stop(pid)With Streaming
{:ok, pid} = Client.start_link(options)
# Start listening in separate process
task = Task.async(fn ->
Client.stream_messages(pid)
|> Enum.take_while(&(&1.type != :result))
|> Enum.to_list()
end)
# Send message
Client.send_message(pid, "Write a function")
# Wait for completion
messages = Task.await(task, :infinity)
Summary
Functions
Returns a specification to start this module under a supervisor.
Gets the currently active agent.
Gets the list of available agent names.
Retrieves the currently active model name.
Returns the server initialization info provided by the CLI.
Sends an interrupt control request to the CLI.
Sends a request in streaming mode, injecting session_id when missing.
Collects messages until a result frame is received.
Rewinds tracked files to their state at a specific user message.
Sends a message to Claude.
Switches to a different agent configuration.
Requests a runtime model switch.
Sets the permission mode at runtime.
Starts the client GenServer.
Stops the client.
Returns a stream of messages from Claude.
Subscribes to the client's message stream and returns a subscription reference.
Types
@type state() :: %{ port: port() | nil, transport: pid() | nil, transport_module: module() | nil, transport_opts: keyword(), options: ClaudeAgentSDK.Options.t(), registry: ClaudeAgentSDK.Hooks.Registry.t(), hook_callback_timeouts: %{required(String.t()) => pos_integer()}, subscribers: %{required(reference()) => pid()} | [pid()], pending_requests: %{required(String.t()) => {GenServer.from(), reference()}}, pending_callbacks: %{ required(String.t()) => %{ pid: pid(), signal: ClaudeAgentSDK.AbortSignal.t(), type: :hook | :permission } }, initialized: boolean(), buffer: String.t(), sdk_mcp_servers: %{required(String.t()) => pid()}, current_model: String.t() | nil, pending_model_change: {GenServer.from(), reference()} | nil, current_permission_mode: ClaudeAgentSDK.Permission.permission_mode() | nil, pending_permission_change: {GenServer.from(), reference()} | nil, accumulated_text: String.t(), active_subscriber: reference() | nil, subscriber_queue: [{reference(), String.t()}], server_info: map() | nil, init_request_id: String.t() | nil, init_timeout_ref: reference() | nil, init_timeout_ms: pos_integer() | nil }
Client state.
Fields:
port- Port to Claude CLI processoptions- Configuration optionsregistry- Hook callback registryhook_callback_timeouts- Map of callback_id => timeout_mssubscribers- Map of ref => pid for streaming subscriptions, or list of pids for legacypending_requests- Map of request_id => {from, ref}pending_callbacks- Map of request_id => %{pid, signal, type} for in-flight control callbacksinitialized- Whether initialization handshake completedbuffer- Incomplete JSON buffersdk_mcp_servers- Map of server_name => registry_pid for SDK MCP serversaccumulated_text- Buffer for partial text (streaming, v0.6.0)active_subscriber- Current streaming consumer reference (v0.6.0)subscriber_queue- Pending message queue (v0.6.0)
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
Gets the currently active agent.
Parameters
client- The client PID
Returns
{:ok, agent_name} or {:error, reason}
Examples
{:ok, :coder} = Client.get_agent(client)
Gets the list of available agent names.
Parameters
client- The client PID
Returns
{:ok, [agent_name]} or {:error, reason}
Examples
{:ok, [:coder, :researcher]} = Client.get_available_agents(client)
Retrieves the currently active model name.
Returns the server initialization info provided by the CLI.
Sends an interrupt control request to the CLI.
@spec query(pid(), String.t() | Enumerable.t(), String.t()) :: :ok | {:error, term()}
Sends a request in streaming mode, injecting session_id when missing.
Matches Python SDK behavior:
- String prompts are wrapped as a
"user"message withparent_tool_use_id: nil - Map prompts (or enumerables of maps) get
session_idinjected if absent
@spec receive_response(pid()) :: {:ok, [ClaudeAgentSDK.Message.t()]} | {:error, term()}
Collects messages until a result frame is received.
Useful for workflows that only care about a single response and want to avoid managing streaming state manually.
Rewinds tracked files to their state at a specific user message.
Requires Options.enable_file_checkpointing to be enabled when starting the client.
Sends a message to Claude.
In streaming mode, this queues the message for sending.
Parameters
client- Client PIDmessage- Message string or map
Returns
:ok or {:error, reason}
Examples
Client.send_message(pid, "Write a hello world function")
Switches to a different agent configuration.
Parameters
client- The client PIDagent_name- The name of the agent to switch to (atom)
Returns
:ok or {:error, reason}
Examples
Client.set_agent(client, :researcher)
Requests a runtime model switch.
Returns :ok when the CLI confirms the change or {:error, reason}
when validation fails or the CLI rejects the request.
@spec set_permission_mode(pid(), ClaudeAgentSDK.Permission.permission_mode()) :: :ok | {:error, :invalid_permission_mode}
Sets the permission mode at runtime.
Changes how tool permissions are handled for subsequent tool uses.
Parameters
client- Client PIDmode- Permission mode atom (:default,:accept_edits,:plan,:bypass_permissions)
Returns
:ok- Successfully changed mode{:error, :invalid_permission_mode}- Invalid mode provided
Examples
Client.set_permission_mode(pid, :plan)
Client.set_permission_mode(pid, :accept_edits)
Client.set_permission_mode(pid, :bypass_permissions)
@spec start_link( ClaudeAgentSDK.Options.t(), keyword() ) :: GenServer.on_start()
Starts the client GenServer.
Validates hooks configuration, starts Claude CLI process, and performs initialization handshake.
Parameters
options- ClaudeAgentSDK.Options struct with hooks configuration
Returns
{:ok, pid}- Successfully started{:error, reason}- Failed to start
Examples
options = %Options{
hooks: %{
pre_tool_use: [Matcher.new("Bash", [&my_hook/3])]
}
}
{:ok, pid} = Client.start_link(options)
@spec stop(pid()) :: :ok
Stops the client.
Terminates the CLI process and cleans up resources.
Parameters
client- Client PID
Returns
:ok
Examples
Client.stop(pid)
@spec stream_messages(pid()) :: Enumerable.t(ClaudeAgentSDK.Message.t())
Returns a stream of messages from Claude.
Subscribes to the client and yields messages as they arrive.
Parameters
client- Client PID
Returns
Enumerable stream of Message structs
Examples
Client.stream_messages(pid)
|> Stream.filter(&(&1.type == :assistant))
|> Enum.to_list()
Subscribes to the client's message stream and returns a subscription reference.