Configuration Guide

Copy Markdown View Source

This guide provides comprehensive documentation for configuring the Claude Agent SDK for Elixir. It covers all available options, presets, environment variables, and authentication methods.

Table of Contents

  1. Options Struct Overview
  2. Complete Options Reference
  3. Output Formats
  4. Model Selection
  5. Tool Configuration
  6. Sandbox Settings
  7. OptionBuilder Presets
  8. Environment Variables
  9. Authentication Configuration

Options Struct Overview

The ClaudeAgentSDK.Options struct is the primary configuration mechanism for SDK requests. All fields are optional and will be omitted from the CLI command if not provided.

Creating Options

# Using struct syntax
options = %ClaudeAgentSDK.Options{
  max_turns: 5,
  output_format: :stream_json,
  verbose: true
}

# Using new/1 function
options = ClaudeAgentSDK.Options.new(
  max_turns: 5,
  output_format: :stream_json,
  verbose: true
)

# Using OptionBuilder presets
options = ClaudeAgentSDK.OptionBuilder.build_development_options()

Basic Example

options = %ClaudeAgentSDK.Options{
  system_prompt: "You are a helpful coding assistant",
  allowed_tools: ["Read", "Edit", "Bash"],
  permission_mode: :accept_edits,
  cwd: "/path/to/project",
  max_turns: 10
}

ClaudeAgentSDK.query("Refactor this code for better performance", options)
|> Enum.to_list()

Complete Options Reference

Core Options

FieldTypeDefaultDescription
max_turnsinteger()nilMaximum number of conversation turns
system_promptString.t() | map()nilCustom system prompt or preset configuration
append_system_promptString.t()nilAdditional prompt to append to system prompt
output_formatatom() | map()nilOutput format (see Output Formats)
verboseboolean()nilEnable verbose output
cwdString.t()nilWorking directory for CLI operations
timeout_msinteger()4,500,000Command timeout in milliseconds (75 minutes)

Model Options

FieldTypeDefaultDescription
modelString.t()nilModel selection ("opus", "sonnet", "haiku", or full model name)
fallback_modelString.t()nilFallback model when primary is busy
max_thinking_tokenspos_integer()nilMaximum tokens for model thinking

Tool Options

FieldTypeDefaultDescription
toolslist() | map()nilBase tools set selection
allowed_tools[String.t()]nilList of allowed tool names
disallowed_tools[String.t()]nilList of disallowed tool names

Permission Options

FieldTypeDefaultDescription
permission_modeatom()nilPermission handling mode (see Permission Modes)
permission_prompt_toolString.t()nilTool for permission prompts
can_use_toolfunction()nilPermission callback function

Note: when can_use_tool is set, the SDK enables include_partial_messages and sets permission_prompt_tool to "stdio" internally.

MCP Options

FieldTypeDefaultDescription
mcp_serversmap() or String.t()nilMCP server configurations or JSON/path string (alias for mcp_config)
mcp_configString.t()nilPath to MCP configuration file
strict_mcp_configboolean()nilOnly use MCP servers from config

Session Options

FieldTypeDefaultDescription
session_idString.t()nilExplicit session ID (UUID)
continue_conversationboolean()nilContinue most recent conversation
resumeString.t()nilResume specific session by ID
fork_sessionboolean()nilCreate new session when resuming
control_request_timeout_msinteger()nilPer-client timeout for control requests

SessionStore lifecycle note: persisted session cache is hydrated in a deferred startup step (handle_continue/2). load_session/1 always falls back to disk, but list/search can be briefly incomplete right after SessionStore boot.

Agent Options

FieldTypeDefaultDescription
agentsmap()nilCustom agent definitions
agentatom()nilActive agent name (key from agents map)

Advanced Options

FieldTypeDefaultDescription
hooksmap()nilHook configurations for lifecycle events
sandboxmap()nilSandbox settings merged into CLI settings
settingsString.t()nilSettings JSON string or file path
setting_sources[String.t()]nilSetting source locations
betas[String.t()][]SDK beta feature flags
plugins[map()][]Plugin configurations
add_dir[String.t()]nilAdditional directories for tool access
add_dirs[String.t()][]Additional directories (list form)
max_budget_usdnumber()nilMaximum budget in USD
enable_file_checkpointingboolean()nilEnable file checkpointing and rewind

Streaming Options (v0.8.0+)

FieldTypeDefaultDescription
include_partial_messagesboolean()nilEnable character-level streaming
preferred_transportatom()nilTransport selection (:auto, :cli, :control)

Internal/Advanced Options

FieldTypeDefaultDescription
executableString.t()nilCustom executable to run (CLI path override)
executable_args[String.t()]nilArguments for custom executable
path_to_claude_code_executableString.t()nilPath to Claude Code CLI (Python cli_path equivalent)
abort_refreference()nilReference for aborting requests
extra_argsmap()%{}Additional CLI arguments (boolean true/nil => flag only; false => omit)
envmap()%{}Environment variable overrides
stderrfunction()nilStderr callback function
userString.t()nilUser identifier
max_buffer_sizepos_integer()nilMaximum JSON buffer size (default: 1MB, overflow yields CLIJSONDecodeError)

If you omit max_buffer_size, the SDK enforces a 1MB default across Port, erlexec, and sync process parsing to match Python SDK limits.

The stderr callback is invoked for non-JSON stderr lines across query, client, and streaming session flows.

Output Formats

The SDK supports multiple output formats for different use cases.

Standard Formats

FormatDescriptionUse Case
:textPlain text outputSimple responses, human-readable output
:jsonJSON-formatted outputStructured data, parsing responses
:stream_jsonStreaming JSONReal-time updates, long-running tasks

Note: SDK query/streaming/client flows always use stream-json for transport parsing. If you set :text or :json, the SDK normalizes the CLI output to stream-json and only forwards --json-schema when provided.

Basic Usage

# Plain text (simplest)
%Options{output_format: :text}

# JSON (structured)
%Options{output_format: :json}

# Streaming JSON (real-time)
%Options{output_format: :stream_json}

JSON Schema (Structured Outputs)

Request validated JSON output by providing a schema:

# Tuple syntax
schema = %{
  "type" => "object",
  "properties" => %{
    "summary" => %{"type" => "string"},
    "score" => %{"type" => "number"}
  },
  "required" => ["summary", "score"]
}

options = %Options{output_format: {:json_schema, schema}}
# Map syntax with explicit type
options = %Options{
  output_format: %{
    type: :json_schema,
    schema: %{
      "type" => "object",
      "properties" => %{
        "title" => %{"type" => "string"},
        "tags" => %{"type" => "array", "items" => %{"type" => "string"}}
      },
      "required" => ["title"]
    },
    output_format: :stream_json  # Optional: base format for streaming
  }
}

Output Format Types

@type output_format :: :text | :json | :stream_json | structured_output_format()

@type structured_output_format ::
  {:json_schema, map()} |
  %{
    type: :json_schema | String.t(),
    schema: map(),
    output_format: :json | :stream_json | String.t()  # optional
  }

Model Selection

The SDK supports all Claude models with convenient shorthand names.

Available Models

ShorthandFull Model IDBest For
"haiku"Auto-selects latest HaikuFast responses, simple queries, cost-effective
"sonnet"Auto-selects latest SonnetBalanced performance, general tasks
"opus"Auto-selects latest OpusComplex reasoning, detailed code generation

Model Configuration

# Using shorthand
options = %Options{model: "sonnet"}

# Using full model name
options = %Options{model: "claude-sonnet-4-5-20250929"}

# With fallback model
options = %Options{
  model: "opus",
  fallback_model: "sonnet"
}

Using OptionBuilder

# Maximum capability
options = ClaudeAgentSDK.OptionBuilder.with_opus()

# Balanced performance
options = ClaudeAgentSDK.OptionBuilder.with_sonnet()

# Fast responses (default)
options = ClaudeAgentSDK.OptionBuilder.with_haiku()

# Add model to existing options
options = ClaudeAgentSDK.OptionBuilder.build_development_options()
|> ClaudeAgentSDK.OptionBuilder.with_model("opus", "sonnet")

Model Selection Comparison

ModelSpeedCostCapabilityRecommended For
HaikuFastestLowestGoodQuick queries, high volume
SonnetBalancedMediumGreatMost use cases
OpusSlowestHighestBestComplex tasks, detailed analysis

Tool Configuration

Control which tools Claude can use during execution.

Available Built-in Tools

ToolDescriptionRisk Level
"Read"Read file contentsLow
"Write"Create/overwrite filesMedium
"Edit"Modify existing filesMedium
"Bash"Execute shell commandsHigh
"Grep"Search file contentsLow
"Find"Find files by patternLow
"Glob"Pattern-based file matchingLow

Allowing Specific Tools

# Only allow read operations
options = %Options{
  allowed_tools: ["Read", "Grep", "Find"]
}

# Allow file modifications
options = %Options{
  allowed_tools: ["Read", "Write", "Edit"]
}

# Full access (development only)
options = %Options{
  allowed_tools: ["Bash", "Read", "Write", "Edit", "Grep", "Find"]
}

Disallowing Specific Tools

# Prevent dangerous operations
options = %Options{
  disallowed_tools: ["Bash", "Write", "Edit"]
}

# Combine allowed and disallowed
options = %Options{
  allowed_tools: ["Read", "Write", "Grep"],
  disallowed_tools: ["Bash"]
}

Tools Preset Configuration

# Use Claude Code default tools
options = %Options{
  tools: %{type: :preset, preset: :claude_code}
}

# Explicit tool list
options = %Options{
  tools: ["Read", "Edit"]
}

# Disable all built-in tools
options = %Options{
  tools: []
}

MCP Tool Configuration

# SDK MCP server (in-process)
server = ClaudeAgentSDK.create_sdk_mcp_server(
  name: "calculator",
  version: "1.0.0",
  tools: [MyTools.Add, MyTools.Multiply]
)

options = %Options{
  mcp_servers: %{"calc" => server},
  allowed_tools: ["mcp__calc__add", "mcp__calc__multiply"]
}

# External MCP server (subprocess)
external_server = %{
  type: :stdio,
  command: "npx",
  args: ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/files"]
}

options = %Options{
  mcp_servers: %{"filesystem" => external_server}
}

mcp_servers also accepts a JSON string or file path (alias for mcp_config):

options = %Options{mcp_servers: "/path/to/mcp.json"}

Sandbox Settings

Configure sandboxed execution for safe, isolated operations.

Basic Sandbox Configuration

options = %Options{
  sandbox: %{
    enabled: true,
    allowed_paths: ["/tmp/sandbox", "/home/user/safe"],
    denied_paths: ["/etc", "/root"],
    network_disabled: true
  }
}

Using OptionBuilder Sandbox Preset

# Create sandboxed environment
options = ClaudeAgentSDK.OptionBuilder.sandboxed("/tmp/sandbox")

# Sandbox with custom tools
options = ClaudeAgentSDK.OptionBuilder.sandboxed(
  "/tmp/safe",
  ["Read", "Write", "Grep"]
)

Sandbox with Bypass Permissions

# Safe within sandbox, all tools auto-allowed
options = %Options{
  cwd: "/tmp/isolated",
  permission_mode: :bypass_permissions,
  allowed_tools: ["Read", "Write"],
  disallowed_tools: ["Bash"],
  sandbox: %{
    enabled: true,
    root: "/tmp/isolated"
  }
}

OptionBuilder Presets

The ClaudeAgentSDK.OptionBuilder module provides pre-configured option sets for common scenarios.

Environment Presets

Development

Best for local development, debugging, and experimentation.

options = ClaudeAgentSDK.OptionBuilder.build_development_options()
SettingValue
max_turns10
verbosetrue
output_format:stream_json
allowed_tools["Bash", "Read", "Write", "Edit", "Grep", "Find"]
permission_mode:accept_edits

Staging

Best for CI/CD pipelines, automated testing, and code review.

options = ClaudeAgentSDK.OptionBuilder.build_staging_options()
SettingValue
max_turns5
verbosefalse
output_format:json
allowed_tools["Read"]
disallowed_tools["Bash", "Write", "Edit"]
permission_mode:plan

Production

Best for production monitoring, read-only analysis, and customer-facing features.

options = ClaudeAgentSDK.OptionBuilder.build_production_options()
SettingValue
max_turns3
verbosefalse
output_format:stream_json
allowed_tools["Read"]
disallowed_tools["Bash", "Write", "Edit", "Grep", "Find"]
permission_mode:plan

Auto-Select by Mix Environment

# Automatically selects based on Mix.env()
options = ClaudeAgentSDK.OptionBuilder.for_environment()
# :dev -> development options
# :test -> staging options
# :prod -> production options

Use-Case Presets

Analysis

Best for code reviews, security audits, and quality analysis.

options = ClaudeAgentSDK.OptionBuilder.build_analysis_options()
SettingValue
max_turns7
output_format:stream_json
allowed_tools["Read", "Grep", "Find"]
disallowed_tools["Write", "Edit", "Bash"]
permission_mode:plan

Documentation

Best for API docs, README generation, and code documentation.

options = ClaudeAgentSDK.OptionBuilder.build_documentation_options()
SettingValue
max_turns8
output_format:stream_json
allowed_tools["Read", "Write", "Grep"]
disallowed_tools["Bash", "Edit"]
permission_mode:accept_edits

Testing

Best for unit test creation, test analysis, and quality assurance.

options = ClaudeAgentSDK.OptionBuilder.build_testing_options()
SettingValue
max_turns6
output_format:stream_json
allowed_tools["Read", "Write", "Grep"]
disallowed_tools["Bash", "Edit"]
permission_mode:accept_edits

Chat

Best for help desk, documentation queries, and general assistance.

options = ClaudeAgentSDK.OptionBuilder.build_chat_options()
SettingValue
max_turns1
output_format:text
allowed_tools[]
disallowed_tools["Bash", "Read", "Write", "Edit", "Grep", "Find"]
permission_mode:plan

Quick

Best for simple questions, quick checks, and lightweight operations.

options = ClaudeAgentSDK.OptionBuilder.quick()
SettingValue
max_turns1
output_format:text
allowed_tools[]
permission_mode:plan

Preset Comparison Table

Presetmax_turnsToolsPermission ModeUse Case
Development10Allaccept_editsLocal dev
Staging5Read-onlyplanCI/CD
Production3Read-onlyplanProduction
Analysis7Read, SearchplanCode review
Documentation8Read, Writeaccept_editsDoc generation
Testing6Read, Writeaccept_editsTest generation
Chat1NoneplanSimple Q&A
Quick1NoneplanFast queries

Builder Utilities

Merging Options

# Merge with preset name
options = ClaudeAgentSDK.OptionBuilder.merge(:development, %{max_turns: 15})

# Merge with existing options
base = ClaudeAgentSDK.OptionBuilder.build_chat_options()
options = ClaudeAgentSDK.OptionBuilder.merge(base, %{max_turns: 3})

Chainable Builders

options = ClaudeAgentSDK.OptionBuilder.build_development_options()
|> ClaudeAgentSDK.OptionBuilder.with_working_directory("/project")
|> ClaudeAgentSDK.OptionBuilder.with_system_prompt("You are an expert")
|> ClaudeAgentSDK.OptionBuilder.with_additional_tools(["Grep"])
|> ClaudeAgentSDK.OptionBuilder.with_turn_limit(15)

Validation

options = ClaudeAgentSDK.OptionBuilder.build_development_options()

case ClaudeAgentSDK.OptionBuilder.validate(options) do
  {:ok, options} ->
    IO.puts("Options valid")

  {:warning, options, warnings} ->
    IO.puts("Warnings: #{inspect(warnings)}")

  {:error, reason} ->
    IO.puts("Invalid: #{reason}")
end

Available Presets

ClaudeAgentSDK.OptionBuilder.available_presets()
# => [:development, :staging, :production, :analysis, :chat, :documentation, :testing]

Environment Variables

Authentication Variables

VariableDescriptionPriority
ANTHROPIC_API_KEYAnthropic API keyPrimary
CLAUDE_AGENT_OAUTH_TOKENOAuth token from claude loginPrimary

Provider Selection

VariableValueDescription
CLAUDE_AGENT_USE_BEDROCK"1"Use AWS Bedrock
CLAUDE_AGENT_USE_VERTEX"1"Use Google Vertex AI

AWS Bedrock Credentials

VariableDescription
AWS_ACCESS_KEY_IDAWS access key ID
AWS_SECRET_ACCESS_KEYAWS secret access key
AWS_PROFILEAWS profile name
AWS_REGIONAWS region

Google Vertex AI Credentials

VariableDescription
GOOGLE_APPLICATION_CREDENTIALSPath to service account JSON
GOOGLE_CLOUD_PROJECTGCP project ID

SDK Internal Variables

VariableDescription
CLAUDE_CODE_ENTRYPOINTSet automatically to "sdk-elixir"
CLAUDE_AGENT_SDK_VERSIONCurrent SDK version

Setting Environment Variables in Options

options = %Options{
  env: %{
    "CUSTOM_VAR" => "value",
    "DEBUG" => "true"
  }
}

Authentication Configuration

Authentication Methods

The SDK supports three authentication methods:

  1. Anthropic API (default) - Direct API key or OAuth session
  2. AWS Bedrock - Using AWS credentials
  3. Google Vertex AI - Using GCP credentials

Quick Authentication Check

# Boolean check
if ClaudeAgentSDK.AuthChecker.authenticated?() do
  ClaudeAgentSDK.query("Hello!")
else
  IO.puts("Please authenticate first")
end

# Ensure ready (raises on failure)
ClaudeAgentSDK.AuthChecker.ensure_ready!()

Full Diagnostic Check

diagnosis = ClaudeAgentSDK.AuthChecker.diagnose()

IO.inspect(diagnosis)
# %{
#   cli_installed: true,
#   cli_version: "2.1.12",
#   authenticated: true,
#   auth_method: "Anthropic API",
#   api_key_source: "env",
#   status: :ready,
#   recommendations: ["Environment is ready for Claude queries"],
#   last_checked: ~U[2025-12-29 12:00:00Z]
# }

AuthManager for Token Management

# Start AuthManager (typically in application supervision tree)
{:ok, _pid} = ClaudeAgentSDK.AuthManager.start_link()

# Ensure authenticated
:ok = ClaudeAgentSDK.AuthManager.ensure_authenticated()

# Setup token (interactive, requires terminal)
{:ok, token} = ClaudeAgentSDK.AuthManager.setup_token()

# Get current token
{:ok, token} = ClaudeAgentSDK.AuthManager.get_token()

# Refresh token
{:ok, token} = ClaudeAgentSDK.AuthManager.refresh_token()

# Check status
status = ClaudeAgentSDK.AuthManager.status()
# %{
#   authenticated: true,
#   provider: :anthropic,
#   token_present: true,
#   expires_at: ~U[2025-11-07 00:00:00Z],
#   time_until_expiry_hours: 720
# }

# Clear authentication
case ClaudeAgentSDK.AuthManager.clear_auth() do
  :ok -> :ok
  {:error, reason} -> IO.puts("Failed to clear auth: #{inspect(reason)}")
end

setup_token/0 and refresh_token/0 run setup work in background tasks internally. Public calls still return the same result tuples, but the AuthManager process stays responsive while setup is in progress.

Application Configuration

# config/config.exs
config :claude_agent_sdk,
  auth_storage: :file,                    # :file | :application_env | :custom
  auth_file_path: "~/.claude_sdk/token.json",
  auto_refresh: true,
  refresh_before_expiry: 86_400_000,      # 1 day in ms
  tool_execution_timeout_ms: 30_000,      # Tool.Registry execution timeout
  cli_stream_module: ClaudeAgentSDK.Query.CLIStream,
  task_supervisor: ClaudeAgentSDK.TaskSupervisor,
  task_supervisor_strict: false,          # true => return {:error, {:task_supervisor_unavailable, sup}}
  check_inbound_size_invariant: false,
  log_level: :warning                     # :debug | :info | :warning | :error

process_module is still read as a fallback for query streaming but is deprecated. Prefer cli_stream_module.

Path defaults like auth_file_path and session_storage_dir are expanded at runtime. Using ~ stays portable across build/runtime users.

Authentication by Provider

Anthropic API (Default)

# Option 1: Environment variable
export ANTHROPIC_API_KEY=sk-ant-api03-...

# Option 2: CLI login
claude login
# Check Anthropic auth
ClaudeAgentSDK.AuthChecker.auth_method_available?(:anthropic)

AWS Bedrock

# Enable Bedrock
export CLAUDE_AGENT_USE_BEDROCK=1

# AWS credentials (one of these methods)
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
# OR
export AWS_PROFILE=my-profile
# OR
# Use ~/.aws/credentials file
# Check Bedrock auth
ClaudeAgentSDK.AuthChecker.auth_method_available?(:bedrock)

Google Vertex AI

# Enable Vertex AI
export CLAUDE_AGENT_USE_VERTEX=1

# GCP credentials (one of these methods)
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/credentials.json
# OR
export GOOGLE_CLOUD_PROJECT=my-project
# OR
# Use default application credentials
# Check Vertex auth
ClaudeAgentSDK.AuthChecker.auth_method_available?(:vertex)

Authentication Status Types

@type auth_status ::
  :ready |              # Fully configured and authenticated
  :cli_not_found |      # Claude CLI not installed
  :not_authenticated |  # CLI installed but not authenticated
  :invalid_credentials | # Authentication failed
  :unknown              # Unknown state

Troubleshooting Authentication

diagnosis = ClaudeAgentSDK.AuthChecker.diagnose()

case diagnosis.status do
  :ready ->
    IO.puts("Ready to use Claude")

  :cli_not_found ->
    IO.puts("Install CLI: npm install -g @anthropic-ai/claude-code")

  :not_authenticated ->
    IO.puts("Authenticate: claude login")
    IO.puts("Or set: ANTHROPIC_API_KEY=...")

  :invalid_credentials ->
    IO.puts("Check credentials and try re-authenticating")

  _ ->
    IO.puts("Recommendations:")
    Enum.each(diagnosis.recommendations, &IO.puts("  - #{&1}"))
end

Permission Modes

Control how tool permissions are handled.

ModeDescription
:defaultCLI default permission flow
:delegateDelegate tool execution to SDK
:accept_editsEdit operations auto-allowed
:planCreates plan, shows to user, executes after approval
:bypass_permissionsAll tools allowed without callback
:dont_askNo permission prompts; tools proceed
# Default - CLI handles permissions
%Options{permission_mode: :default}

# Delegate - SDK callback controls permissions
%Options{permission_mode: :delegate}

# Accept edits - auto-approve file modifications
%Options{permission_mode: :accept_edits}

# Plan mode - review before execution
%Options{permission_mode: :plan}

# Bypass - no permissions (use with caution)
%Options{permission_mode: :bypass_permissions}

# Dont ask - no permission prompts
%Options{permission_mode: :dont_ask}

Custom Permission Callback

alias ClaudeAgentSDK.Permission.{Context, Result}

callback = fn context ->
  case context.tool_name do
    "Bash" ->
      if String.contains?(context.tool_input["command"], "rm -rf") do
        Result.deny("Dangerous command")
      else
        Result.allow()
      end

    "Write" ->
      if String.starts_with?(context.tool_input["file_path"], "/etc/") do
        Result.deny("Cannot write to /etc")
      else
        Result.allow()
      end

    _ ->
      Result.allow()
  end
end

options = %Options{
  can_use_tool: callback,
  permission_mode: :default
}

Note: can_use_tool enables include_partial_messages and sets permission_prompt_tool to "stdio" internally. Hook fallback only applies in non-:delegate modes and ignores updated_permissions.


Transport Configuration (v0.8.0+)

The SDK automatically selects the appropriate transport based on configured features.

Transport Types

TransportDescriptionWhen Used
:cliSimple CLI streamingNo hooks, MCP, or permissions
:controlControl protocol clientHooks, MCP servers, or permission callbacks
:autoAutomatic selectionDefault

Override Transport Selection

# Force CLI-only mode (ignores control features)
%Options{preferred_transport: :cli}

# Force control client (even without features)
%Options{preferred_transport: :control}

# Automatic selection (default)
%Options{preferred_transport: :auto}

Transport Startup Mode

Transport.Port, Transport.Erlexec, and Streaming.Session support startup_mode: :eager | :lazy in their start options.

  • :eager (default): subprocess startup happens in init/1
  • :lazy: subprocess startup is deferred to handle_continue/2
ClaudeAgentSDK.query(
  "Hello",
  %Options{},
  {ClaudeAgentSDK.Transport.Port, [startup_mode: :lazy]}
)
|> Enum.to_list()

In lazy mode, start_link can return {:ok, pid} before subprocess creation. If startup later fails (for example invalid cwd/command), the process exits with the startup reason.

Enable Character-Level Streaming

options = %Options{
  include_partial_messages: true,
  hooks: %{pre_tool_use: [...]},
  mcp_servers: %{"math" => sdk_server}
}
# Automatically selects control client with streaming enabled

Complete Configuration Examples

Development Setup

options = %ClaudeAgentSDK.Options{
  model: "sonnet",
  max_turns: 10,
  verbose: true,
  output_format: :stream_json,
  cwd: "/path/to/project",
  allowed_tools: ["Bash", "Read", "Write", "Edit", "Grep", "Find"],
  permission_mode: :accept_edits,
  system_prompt: "You are a helpful Elixir development assistant."
}

Production Read-Only Analysis

options = %ClaudeAgentSDK.Options{
  model: "haiku",
  max_turns: 3,
  verbose: false,
  output_format: :stream_json,
  allowed_tools: ["Read"],
  disallowed_tools: ["Bash", "Write", "Edit"],
  permission_mode: :plan,
  max_budget_usd: 0.50,
  system_prompt: "Provide concise, accurate analysis."
}

Sandboxed Execution

options = %ClaudeAgentSDK.Options{
  cwd: "/tmp/sandbox",
  permission_mode: :bypass_permissions,
  allowed_tools: ["Read", "Write"],
  disallowed_tools: ["Bash"],
  max_turns: 5,
  output_format: :stream_json,
  sandbox: %{
    enabled: true,
    root: "/tmp/sandbox"
  }
}

With MCP Tools

# Create SDK MCP server
server = ClaudeAgentSDK.create_sdk_mcp_server(
  name: "calculator",
  version: "1.0.0",
  tools: [Calculator.Add, Calculator.Multiply]
)

# Optional: place each SDK MCP registry under your own DynamicSupervisor
{:ok, sup} = DynamicSupervisor.start_link(strategy: :one_for_one)

server = ClaudeAgentSDK.create_sdk_mcp_server(
  name: "calculator",
  version: "1.0.0",
  tools: [Calculator.Add, Calculator.Multiply],
  supervisor: sup
)

options = %ClaudeAgentSDK.Options{
  mcp_servers: %{"calc" => server},
  allowed_tools: ["mcp__calc__add", "mcp__calc__multiply"],
  include_partial_messages: true,
  output_format: :stream_json
}

With Custom Hooks

alias ClaudeAgentSDK.Hooks.{Matcher, Output}

check_bash = fn input, _id, _ctx ->
  cmd = get_in(input, ["tool_input", "command"]) || ""
  if String.contains?(cmd, "rm -rf") do
    Output.deny("Dangerous command blocked")
  else
    Output.allow()
  end
end

options = %ClaudeAgentSDK.Options{
  hooks: %{
    pre_tool_use: [%Matcher{matcher: "Bash", hooks: [check_bash]}]
  },
  allowed_tools: ["Bash", "Read"],
  include_partial_messages: true
}

Further Reading