ClaudeCode.Options (ClaudeCode v0.21.0)

View Source

Option validation, CLI flag conversion, and configuration guide.

This module is the single source of truth for all ClaudeCode options. It provides validation for session and query options using NimbleOptions, converts Elixir options to CLI flags, and manages option precedence.

Option Precedence

Options are resolved in this order (highest to lowest priority):

  1. Query-level options — passed to query/3 or stream/3

  2. Session-level options — passed to start_link/1

  3. Application config — set in config/config.exs

  4. Default values — built-in defaults

    # Application config (lowest priority) config :claude_code, timeout: 300_000

    # Session-level overrides app config {:ok, session} = ClaudeCode.start_link(timeout: 120_000)

    # Query-level overrides session ClaudeCode.stream(session, "Hello", timeout: 60_000)

Session Options

All options for ClaudeCode.start_link/1:

Authentication

OptionTypeDefaultDescription
api_keystringANTHROPIC_API_KEY envAnthropic API key
nameatom-Register session with a name

Model Configuration

OptionTypeDefaultDescription
modelstring"sonnet"Claude model to use
fallback_modelstring-Fallback if primary model fails
system_promptstring-Override system prompt
append_system_promptstring-Append to default system prompt
max_turnsinteger-Limit conversation turns
max_budget_usdnumber-Maximum dollar amount to spend on API calls
agentstring-Agent name for the session
betaslist-Beta headers for API requests
max_thinking_tokensinteger-Deprecated: use thinking instead
thinkingatom/tuple-Thinking config: :adaptive, :disabled, {:enabled, budget_tokens: N}
effortatom-Effort level: :low, :medium, :high

Timeouts

OptionTypeDefaultDescription
timeoutinteger300_000Query timeout in milliseconds

Tool Control

OptionTypeDefaultDescription
toolsatom/list-Available tools: :default, [], or list of names
allowed_toolslist-Tools Claude can use
disallowed_toolslist-Tools Claude cannot use
add_dirlist-Additional accessible directories
permission_modeatom:defaultPermission handling mode

Advanced

OptionTypeDefaultDescription
adaptertupleCLI adapterBackend adapter as {Module, config} tuple
resumestring-Session ID to resume
fork_sessionbooleanfalseCreate new session ID when resuming
continuebooleanfalseContinue most recent conversation in current directory
mcp_configstring-Path to MCP config file
strict_mcp_configbooleanfalseOnly use MCP servers from explicit config
agentslist/map-Custom agent configurations (list of Agent structs or map)
settingsmap/string-Team settings
setting_sourceslist-Setting source priority
include_partial_messagesbooleanfalseEnable character-level streaming
output_formatmap-Structured output format (see Structured Outputs section)
pluginslist-Plugin configurations to load (paths or maps with type: :local)

Query Options

Options that can be passed to stream/3:

OptionTypeDescription
timeoutintegerOverride session timeout
system_promptstringOverride system prompt for this query
append_system_promptstringAppend to system prompt
max_turnsintegerLimit turns for this query
max_budget_usdnumberMaximum dollar amount for this query
agentstringAgent to use for this query
betaslistBeta headers for this query
max_thinking_tokensintegerDeprecated: use thinking instead
thinkingatom/tupleOverride thinking config for this query
effortatomOverride effort level for this query
toolslistAvailable tools for this query
allowed_toolslistAllowed tools for this query
disallowed_toolslistDisallowed tools for this query
output_formatmapStructured output format for this query
pluginslistPlugin configurations for this query
include_partial_messagesbooleanEnable deltas for this query

Note: api_key and name cannot be overridden at query time.

Application Configuration

Set defaults in config/config.exs:

config :claude_code,
  api_key: System.get_env("ANTHROPIC_API_KEY"),
  model: "sonnet",
  timeout: 180_000,
  system_prompt: "You are a helpful assistant",
  allowed_tools: ["View"]

CLI Configuration

The SDK manages the Claude CLI binary via the :cli_path option:

config :claude_code,
  cli_path: :bundled,               # :bundled (default), :global, or "/path/to/claude"
  cli_version: "x.y.z",            # Version to install (default: SDK's tested version)
  cli_dir: nil                      # Directory for downloaded binary (default: priv/bin/)

Resolution modes:

ModeValueBehavior
Bundled:bundled (default)Uses priv/bin/ binary. Auto-installs if missing. Verifies version matches SDK.
Global:globalFinds existing system install via PATH or common locations. No auto-install.
Explicit"/path/to/claude"Uses that exact binary. Error if not found.

Mix tasks:

mix claude_code.install              # Install or update to SDK's tested version
mix claude_code.install --version x.y.z   # Install specific version
mix claude_code.install --force      # Force reinstall even if version matches
mix claude_code.uninstall            # Remove the bundled CLI binary
mix claude_code.path                 # Print the resolved CLI binary path

For releases:

# Option 1: Pre-install during release build (recommended)
# (Run mix claude_code.install before building the release)

# Option 2: Configure writable directory for runtime download
config :claude_code, cli_dir: "/var/lib/claude_code"

# Option 3: Use system-installed CLI
config :claude_code, cli_path: :global

Environment-Specific Configuration

# config/dev.exs
config :claude_code,
  timeout: 60_000,
  permission_mode: :accept_edits

# config/prod.exs
config :claude_code,
  timeout: 300_000,
  permission_mode: :default

# config/test.exs
config :claude_code,
  api_key: "test-key",
  timeout: 5_000

Model Selection

# Use a specific model
{:ok, session} = ClaudeCode.start_link(model: "opus")

# With fallback
{:ok, session} = ClaudeCode.start_link(
  model: "opus",
  fallback_model: "sonnet"
)

Available models: "sonnet", "opus", "haiku", or full model IDs.

System Prompts

# Override completely
{:ok, session} = ClaudeCode.start_link(
  system_prompt: "You are an Elixir expert. Only discuss Elixir."
)

# Append to default
{:ok, session} = ClaudeCode.start_link(
  append_system_prompt: "Always format code with proper indentation."
)

Cost Control

# Limit spending per query
session
|> ClaudeCode.stream("Complex analysis task", max_budget_usd: 5.00)
|> Stream.run()

# Set a session-wide budget limit
{:ok, session} = ClaudeCode.start_link(
  max_budget_usd: 25.00
)

Structured Outputs

Use the :output_format option with a JSON Schema to get validated structured responses:

schema = %{
  "type" => "object",
  "properties" => %{
    "name" => %{"type" => "string"},
    "age" => %{"type" => "integer"},
    "skills" => %{"type" => "array", "items" => %{"type" => "string"}}
  },
  "required" => ["name", "age"]
}

session
|> ClaudeCode.stream("Extract person info from: John is 30 and knows Elixir",
     output_format: %{type: :json_schema, schema: schema})
|> ClaudeCode.Stream.text_content()
|> Enum.join()

The :output_format option accepts a map with:

  • :type — currently only :json_schema is supported
  • :schema — a JSON Schema map defining the expected structure

Tool Configuration

# Use all default tools
{:ok, session} = ClaudeCode.start_link(tools: :default)

# Specify available tools (subset of built-in)
{:ok, session} = ClaudeCode.start_link(
  tools: ["Bash", "Edit", "Read"]
)

# Disable all tools
{:ok, session} = ClaudeCode.start_link(tools: [])

# Allow specific tools with patterns
{:ok, session} = ClaudeCode.start_link(
  allowed_tools: ["View", "Edit", "Bash(git:*)"]
)

# Disallow specific tools
{:ok, session} = ClaudeCode.start_link(
  disallowed_tools: ["Bash", "Write"]
)

# Additional directories
{:ok, session} = ClaudeCode.start_link(
  add_dir: ["/app/lib", "/app/test"]
)

MCP Server Control

Claude Code can connect to MCP (Model Context Protocol) servers for additional tools. By default, it uses globally configured MCP servers. Use strict_mcp_config to control this:

# No tools at all (no built-in tools, no MCP servers)
{:ok, session} = ClaudeCode.start_link(
  tools: [],
  strict_mcp_config: true
)

# Built-in tools only (ignore global MCP servers)
{:ok, session} = ClaudeCode.start_link(
  tools: :default,
  strict_mcp_config: true
)

# Default behavior (built-in tools + global MCP servers)
{:ok, session} = ClaudeCode.start_link()

# Specific MCP servers only (no global config)
{:ok, session} = ClaudeCode.start_link(
  strict_mcp_config: true,
  mcp_servers: %{
    "my-tools" => %{command: "npx", args: ["my-mcp-server"]}
  }
)

Using Hermes MCP Modules

You can use Elixir-based MCP servers built with Hermes MCP:

{:ok, session} = ClaudeCode.start_link(
  strict_mcp_config: true,
  mcp_servers: %{
    "my-tools" => MyApp.MCPServer,
    "custom" => %{module: MyApp.MCPServer, env: %{"DEBUG" => "1"}}
  }
)

Custom Agents

Configure custom agents with ClaudeCode.Agent structs:

alias ClaudeCode.Agent

agents = [
  Agent.new(
    name: "code-reviewer",
    description: "Expert code reviewer",
    prompt: "You review code for quality and best practices.",
    tools: ["View", "Grep", "Glob"],
    model: "sonnet"
  )
]

{:ok, session} = ClaudeCode.start_link(agents: agents)

Raw maps are also accepted for backwards compatibility:

{:ok, session} = ClaudeCode.start_link(agents: %{
  "code-reviewer" => %{
    "description" => "Expert code reviewer",
    "prompt" => "You review code for quality and best practices."
  }
})

See the Subagents Guide for more details.

Team Settings

# From file path
{:ok, session} = ClaudeCode.start_link(
  settings: "/path/to/settings.json"
)

# From map (auto-encoded to JSON)
{:ok, session} = ClaudeCode.start_link(
  settings: %{
    "team_name" => "My Team",
    "preferences" => %{"theme" => "dark"}
  }
)

# Control setting sources
{:ok, session} = ClaudeCode.start_link(
  setting_sources: ["user", "project", "local"]
)

Plugins

Load custom plugins to extend Claude's capabilities:

# From a directory path
{:ok, session} = ClaudeCode.start_link(
  plugins: ["./my-plugin"]
)

# With explicit type (currently only :local is supported)
{:ok, session} = ClaudeCode.start_link(
  plugins: [
    %{type: :local, path: "./my-plugin"},
    "./another-plugin"
  ]
)

Runtime Control

Some settings can be changed mid-conversation without restarting the session, using the bidirectional control protocol:

# Switch model on the fly
{:ok, _} = ClaudeCode.set_model(session, "opus")

# Change permission mode
{:ok, _} = ClaudeCode.set_permission_mode(session, :bypass_permissions)

# Query MCP server status
{:ok, status} = ClaudeCode.get_mcp_status(session)

See the Sessions guide for more details.

Validation Errors

Invalid options raise descriptive errors:

{:ok, session} = ClaudeCode.start_link(timeout: "not a number")
# => ** (NimbleOptions.ValidationError) invalid value for :timeout option:
#       expected positive integer, got: "not a number"

Security Considerations

  • :permission_mode — controls permission handling behavior. Use :bypass_permissions only in development environments.
  • :add_dir — grants tool access to additional directories. Only include safe directories.
  • :allowed_tools — use tool restrictions to limit Claude's capabilities. Example: ["View", "Bash(git:*)"] allows read-only operations and git commands.

Summary

Functions

Applies application config defaults to session options.

Gets application configuration for claude_code.

Merges session and query options with query taking precedence.

Returns the query options schema.

Returns the session options schema.

Validates query options using NimbleOptions.

Validates session options using NimbleOptions.

Functions

apply_app_config_defaults(session_opts)

Applies application config defaults to session options.

Session options take precedence over app config.

get_app_config()

Gets application configuration for claude_code.

Returns only valid option keys from the session schema.

merge_options(session_opts, query_opts)

Merges session and query options with query taking precedence.

Examples

iex> session_opts = [timeout: 60_000, model: "sonnet"]
iex> query_opts = [timeout: 120_000]
iex> ClaudeCode.Options.merge_options(session_opts, query_opts)
[model: "sonnet", timeout: 120_000]

query_schema()

Returns the query options schema.

session_schema()

Returns the session options schema.

validate_query_options(opts)

Validates query options using NimbleOptions.

Examples

iex> ClaudeCode.Options.validate_query_options([timeout: 60_000])
{:ok, [timeout: 60_000]}

iex> ClaudeCode.Options.validate_query_options([invalid: "option"])
{:error, %NimbleOptions.ValidationError{}}

validate_session_options(opts)

Validates session options using NimbleOptions.

The CLI will handle API key resolution from the environment if not provided.

Examples

iex> ClaudeCode.Options.validate_session_options([api_key: "sk-test"])
{:ok, [api_key: "sk-test", timeout: 300_000]}

iex> ClaudeCode.Options.validate_session_options([])
{:ok, [timeout: 300_000]}