<div align="center">
<img src="assets/claude_agent_sdk.svg" alt="Claude Agent SDK Logo" width="200"/>
</div>
# Claude Agent SDK for Elixir
[](https://hex.pm/packages/claude_agent_sdk)
[](https://hexdocs.pm/claude_agent_sdk/)
[](https://hex.pm/packages/claude_agent_sdk)
[](https://github.com/nshkrdotcom/claude_agent_sdk/blob/main/LICENSE)
[](https://github.com/nshkrdotcom/claude_agent_sdk/actions/workflows/elixir.yaml)
[](https://github.com/nshkrdotcom/claude_agent_sdk/commits/main)
An Elixir SDK aiming for feature-complete parity with the official [claude-agent-sdk-python](https://github.com/anthropics/claude-agent-sdk-python). Build AI-powered applications with Claude using a production-ready interface for the [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code/sdk), featuring streaming responses, lifecycle hooks, permission controls, and in-process tool execution via MCP.
> **Note:** This SDK does not bundle the Claude Code CLI. You must install it separately (see [Prerequisites](#prerequisites)).
---
## What You Can Build
- **AI coding assistants** with real-time streaming output
- **Automated code review** pipelines with custom permission policies
- **Multi-agent workflows** with specialized personas
- **Tool-augmented applications** using the Model Context Protocol (MCP)
- **Interactive chat interfaces** with typewriter-style output
---
## Installation
Add to your `mix.exs`:
```elixir
def deps do
[
{:claude_agent_sdk, "~> 0.7.0"}
]
end
```
Then fetch dependencies:
```bash
mix deps.get
```
### Prerequisites
Install the Claude Code CLI (requires Node.js):
```bash
npm install -g @anthropic-ai/claude-code
```
Verify installation:
```bash
claude --version
```
---
## Quick Start
### 1. Authenticate
Choose one method:
```bash
# Option A: Environment variable (recommended for CI/CD)
export ANTHROPIC_API_KEY="sk-ant-api03-..."
# Option B: OAuth token
export CLAUDE_AGENT_OAUTH_TOKEN="sk-ant-oat01-..."
# Option C: Interactive login
claude login
```
### 2. Run Your First Query
```elixir
alias ClaudeAgentSDK.{ContentExtractor, Options}
# Simple query with streaming collection
ClaudeAgentSDK.query("Write a function that calculates factorial in Elixir")
|> Enum.each(fn msg ->
case msg.type do
:assistant -> IO.puts(ContentExtractor.extract_text(msg) || "")
:result -> IO.puts("Done! Cost: $#{msg.data.total_cost_usd}")
_ -> :ok
end
end)
```
### 3. Real-Time Streaming
```elixir
alias ClaudeAgentSDK.Streaming
{:ok, session} = Streaming.start_session()
Streaming.send_message(session, "Explain GenServers in one paragraph")
|> Stream.each(fn
%{type: :text_delta, text: chunk} -> IO.write(chunk)
%{type: :message_stop} -> IO.puts("")
_ -> :ok
end)
|> Stream.run()
Streaming.close_session(session)
```
---
## Authentication
The SDK supports three authentication methods, checked in this order:
| Method | Environment Variable | Best For |
|--------|---------------------|----------|
| OAuth Token | `CLAUDE_AGENT_OAUTH_TOKEN` | Production / CI |
| API Key | `ANTHROPIC_API_KEY` | Development |
| CLI Login | (uses `claude login` session) | Local development |
### Cloud Providers
**AWS Bedrock:**
```bash
export CLAUDE_AGENT_USE_BEDROCK=1
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
export AWS_REGION=us-west-2
```
**Google Vertex AI:**
```bash
export CLAUDE_AGENT_USE_VERTEX=1
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json
export GOOGLE_CLOUD_PROJECT=your-project-id
```
### Token Setup (Local Development)
For persistent authentication without re-login:
```bash
mix claude.setup_token
```
Check authentication status:
```elixir
alias ClaudeAgentSDK.AuthChecker
diagnosis = AuthChecker.diagnose()
# => %{authenticated: true, auth_method: "Anthropic API", ...}
```
---
## Core Concepts
### Choosing the Right API
| API | Use Case | When to Use |
|-----|----------|-------------|
| `query/2` | Simple queries | Batch processing, scripts |
| `Streaming` | Typewriter UX | Chat interfaces, real-time output |
| `Client` | Full control | Multi-turn agents, tools, hooks |
### Query API
The simplest way to interact with Claude:
```elixir
# Basic query
messages = ClaudeAgentSDK.query("What is recursion?") |> Enum.to_list()
# With options
opts = %ClaudeAgentSDK.Options{
model: "sonnet",
max_turns: 5,
output_format: :stream_json
}
messages = ClaudeAgentSDK.query("Explain OTP", opts) |> Enum.to_list()
# Continue a conversation
ClaudeAgentSDK.continue("Can you give an example?") |> Enum.to_list()
# Resume a specific session
ClaudeAgentSDK.resume("session-id", "What about supervision trees?") |> Enum.to_list()
```
### Streaming API
For real-time, character-by-character output:
```elixir
alias ClaudeAgentSDK.{Options, Streaming}
{:ok, session} = Streaming.start_session(%Options{model: "haiku"})
# Send messages and stream responses
Streaming.send_message(session, "Write a haiku about Elixir")
|> Enum.each(fn
%{type: :text_delta, text: t} -> IO.write(t)
%{type: :tool_use_start, name: n} -> IO.puts("\nUsing tool: #{n}")
%{type: :message_stop} -> IO.puts("\n---")
_ -> :ok
end)
# Multi-turn conversation (context preserved)
Streaming.send_message(session, "Now write one about Phoenix")
|> Enum.to_list()
Streaming.close_session(session)
```
### Hooks System
Intercept and control agent behavior at key lifecycle points:
```elixir
alias ClaudeAgentSDK.{Client, Options}
alias ClaudeAgentSDK.Hooks.{Matcher, Output}
# Block dangerous commands
check_bash = fn input, _id, _ctx ->
case input do
%{"tool_name" => "Bash", "tool_input" => %{"command" => cmd}} ->
if String.contains?(cmd, "rm -rf") do
Output.deny("Dangerous command blocked")
else
Output.allow()
end
_ -> %{}
end
end
opts = %Options{
hooks: %{
pre_tool_use: [Matcher.new("Bash", [check_bash])]
}
}
{:ok, client} = Client.start_link(opts)
```
**Available Hook Events:**
- `pre_tool_use` / `post_tool_use` - Before/after tool execution
- `user_prompt_submit` - Before sending user messages
- `session_start` / `session_end` - Session lifecycle
- `stop` / `subagent_stop` - Completion events
See the [Hooks Guide](guides/hooks.md) for comprehensive documentation.
### Permission System
Fine-grained control over tool execution:
```elixir
alias ClaudeAgentSDK.{Options, Permission.Result}
permission_callback = fn ctx ->
case ctx.tool_name do
"Write" ->
# Redirect system file writes to safe location
if String.starts_with?(ctx.tool_input["file_path"], "/etc/") do
safe_path = "/tmp/sandbox/" <> Path.basename(ctx.tool_input["file_path"])
Result.allow(updated_input: %{ctx.tool_input | "file_path" => safe_path})
else
Result.allow()
end
_ ->
Result.allow()
end
end
opts = %Options{
can_use_tool: permission_callback,
permission_mode: :default # :default | :accept_edits | :plan | :bypass_permissions
}
```
### MCP Tools (In-Process)
Define custom tools that Claude can call directly in your application:
```elixir
defmodule MyTools do
use ClaudeAgentSDK.Tool
deftool :calculate, "Perform a calculation", %{
type: "object",
properties: %{
expression: %{type: "string", description: "Math expression to evaluate"}
},
required: ["expression"]
} do
def execute(%{"expression" => expr}) do
# Your logic here
result = eval_expression(expr)
{:ok, %{"content" => [%{"type" => "text", "text" => "Result: #{result}"}]}}
end
end
end
# Create an MCP server with your tools
server = ClaudeAgentSDK.create_sdk_mcp_server(
name: "calculator",
version: "1.0.0",
tools: [MyTools.Calculate]
)
opts = %ClaudeAgentSDK.Options{
mcp_servers: %{"calc" => server},
allowed_tools: ["mcp__calc__calculate"]
}
```
---
## Configuration Options
Key options for `ClaudeAgentSDK.Options`:
| Option | Type | Description |
|--------|------|-------------|
| `model` | string | `"sonnet"`, `"opus"`, `"haiku"` |
| `max_turns` | integer | Maximum conversation turns |
| `system_prompt` | string | Custom system instructions |
| `output_format` | atom/map | `:text`, `:json`, `:stream_json`, or JSON schema |
| `allowed_tools` | list | Tools Claude can use |
| `permission_mode` | atom | `:default`, `:accept_edits`, `:plan`, `:bypass_permissions` |
| `hooks` | map | Lifecycle hook callbacks |
| `mcp_servers` | map | MCP server configurations |
| `cwd` | string | Working directory for file operations |
| `timeout_ms` | integer | Command timeout (default: 75 minutes) |
### Option Presets
```elixir
alias ClaudeAgentSDK.OptionBuilder
# Environment-based presets
OptionBuilder.build_development_options() # Permissive, verbose
OptionBuilder.build_production_options() # Restrictive, safe
OptionBuilder.for_environment() # Auto-detect from Mix.env()
# Use-case presets
OptionBuilder.build_analysis_options() # Read-only code analysis
OptionBuilder.build_chat_options() # Simple chat, no tools
OptionBuilder.quick() # Fast one-off queries
```
---
## Examples
The `examples/` directory contains runnable demonstrations:
```bash
# Run all examples
bash examples/run_all.sh
# Run a specific example
mix run examples/basic_example.exs
mix run examples/streaming_tools/quick_demo.exs
mix run examples/hooks/basic_bash_blocking.exs
```
**Key Examples:**
- `basic_example.exs` - Minimal SDK usage
- `streaming_tools/quick_demo.exs` - Real-time streaming
- `hooks/complete_workflow.exs` - Full hooks integration
- `sdk_mcp_tools_live.exs` - Custom MCP tools
- `advanced_features/agents_live.exs` - Multi-agent workflows
- `advanced_features/subagent_spawning_live.exs` - Parallel subagent coordination
- `advanced_features/web_tools_live.exs` - WebSearch and WebFetch
---
## Guides
| Guide | Description |
|-------|-------------|
| [Getting Started](guides/getting-started.md) | Installation, authentication, and first query |
| [Streaming](guides/streaming.md) | Real-time streaming and typewriter effects |
| [Hooks](guides/hooks.md) | Lifecycle hooks for tool control |
| [MCP Tools](guides/mcp-tools.md) | In-process tool definitions with MCP |
| [Permissions](guides/permissions.md) | Fine-grained permission controls |
| [Configuration](guides/configuration.md) | Complete options reference |
| [Agents](guides/agents.md) | Custom agent personas |
| [Sessions](guides/sessions.md) | Session management and persistence |
| [Testing](guides/testing.md) | Mock system and testing patterns |
| [Error Handling](guides/error-handling.md) | Error types and recovery |
**Additional Resources:**
- [CHANGELOG.md](CHANGELOG.md) - Version history and release notes
- [HexDocs](https://hexdocs.pm/claude_agent_sdk/) - API documentation
- [Claude Code SDK](https://docs.anthropic.com/en/docs/claude-code/sdk) - Upstream documentation
---
## License
MIT License - see [LICENSE](LICENSE) for details.
---
<div align="center">
<sub>Built with Elixir and Claude</sub>
</div>