🤖 Claude Code SDK for Elixir
The idiomatic way to integrate Claude AI into your Elixir applications.
- 🔄 Native Streaming: Built on Elixir Streams for real-time responses
- 💬 Conversation Continuity: Automatic context retention across queries
- 🔁 Bidirectional Streaming: Multi-turn conversations over a single connection
- 🏭 Production-Ready Supervision: Fault-tolerant GenServers with automatic restarts
- 🛠️ Built-in File Operations: Read, edit, and analyze files with zero configuration
- ⚡ High-Performance Concurrency: Multiple concurrent sessions with Elixir's actor model
- 🔧 Zero-Config Phoenix Integration: Drop-in support for LiveView and Phoenix apps
🎯 30-Second Demo
# Start a session and query Claude (uses ANTHROPIC_API_KEY from env)
{:ok, session} = ClaudeCode.start_link()
{:ok, response} = ClaudeCode.query(session, "Explain Elixir GenServers in one sentence")
IO.puts(response)
# Conversation continuity - Claude remembers context
ClaudeCode.query(session, "My favorite language is Elixir")
{:ok, answer} = ClaudeCode.query(session, "What's my favorite language?")
IO.puts(answer) # => "Your favorite language is Elixir!"
📦 Installation
Step 1: Add to your mix.exs
def deps do
[{:claude_code, "~> 0.8.0"}]
end
Step 2: Install dependencies
mix deps.get
Step 3: Get the Claude CLI
# Install the Claude Code CLI: https://docs.anthropic.com/en/docs/claude-code
claude --version # Verify installation
Step 4: Set your API key
# The SDK uses ANTHROPIC_API_KEY from your environment
export ANTHROPIC_API_KEY="sk-ant-your-api-key-here"
# Or configure in config/config.exs (optional)
config :claude_code, api_key: System.get_env("ANTHROPIC_API_KEY")
🎉 Ready to go! Try the quick demo above.
⚡ Quick Examples
# Basic usage (uses ANTHROPIC_API_KEY from environment)
{:ok, session} = ClaudeCode.start_link()
{:ok, response} = ClaudeCode.query(session, "Hello, Claude!")
# File operations
ClaudeCode.query(session, "Review my mix.exs file",
allowed_tools: ["View", "Edit"])
# Custom agents
agents = %{
"code-reviewer" => %{
"description" => "Expert code reviewer. Use proactively after code changes.",
"prompt" => "You are a senior code reviewer. Focus on quality and best practices.",
"tools" => ["Read", "Grep", "Glob"],
"model" => "sonnet"
}
}
{:ok, session} = ClaudeCode.start_link(agents: agents)
# Production with supervision
{:ok, _} = ClaudeCode.Supervisor.start_link(name: :assistant)
ClaudeCode.query(:assistant, "Help with this task")
📖 Complete Getting Started Guide →
🏭 Production Usage
Supervised Sessions
# In your application.ex
def start(_type, _args) do
children = [
MyAppWeb.Endpoint,
{ClaudeCode.Supervisor, [
[name: :code_reviewer, system_prompt: "You review code"],
[name: :general_assistant]
]}
]
Supervisor.start_link(children, strategy: :one_for_one)
end
# Use from anywhere in your app
{:ok, review} = ClaudeCode.query(:code_reviewer, "Review this code")
Benefits:
- ✅ Fault tolerance - Sessions restart automatically on crashes
- ✅ Zero downtime - Hot code reloading preserves session state
- ✅ Global access - Named sessions work from anywhere in your app
- ✅ Distributed support - Sessions work across Elixir clusters
Phoenix Integration
# Simple controller usage
def ask(conn, %{"prompt" => prompt}) do
case ClaudeCode.query(:assistant, prompt) do
{:ok, response} -> json(conn, %{response: response})
{:error, _} -> json(conn, %{error: "Claude unavailable"})
end
end
For LiveView with real-time streaming, use query_stream/3 with a Task:
# LiveView with streaming responses
def handle_event("send", %{"message" => msg}, socket) do
parent = self()
Task.start(fn ->
:assistant
|> ClaudeCode.query_stream(msg, include_partial_messages: true)
|> ClaudeCode.Stream.text_deltas()
|> Enum.each(&send(parent, {:chunk, &1}))
send(parent, :complete)
end)
{:noreply, assign(socket, streaming: true)}
end
def handle_info({:chunk, chunk}, socket) do
{:noreply, assign(socket, response: socket.assigns.response <> chunk)}
end
def handle_info(:complete, socket) do
{:noreply, assign(socket, streaming: false)}
end
📖 Full Phoenix Integration Guide →
Error Handling
case ClaudeCode.query(session, "Hello") do
{:ok, response} -> IO.puts(response)
{:error, :timeout} -> IO.puts("Request timed out")
{:error, {:cli_not_found, msg}} -> IO.puts("CLI error: #{msg}")
{:error, {:claude_error, msg}} -> IO.puts("Claude error: #{msg}")
end
Multi-turn Conversations
Sessions automatically maintain context across queries:
{:ok, session} = ClaudeCode.start_link()
# First turn
{:ok, response1} = ClaudeCode.query(session, "What's the capital of France?")
IO.puts(response1) # Paris
# Second turn - context is preserved automatically
{:ok, response2} = ClaudeCode.query(session, "What about Germany?")
IO.puts(response2) # Berlin
# Get session ID for later resume
{:ok, session_id} = ClaudeCode.get_session_id(session)
ClaudeCode.stop(session)
# Resume later with the same context
{:ok, new_session} = ClaudeCode.start_link(resume: session_id)
{:ok, response3} = ClaudeCode.query(new_session, "What was the first capital I asked about?")
IO.puts(response3) # Paris
Benefits:
- ✅ Persistent connection - Single CLI process handles all queries
- ✅ Auto-connect/disconnect - No manual lifecycle management
- ✅ Resume support - Continue previous conversations with
resume: session_id - ✅ Lower latency - No startup overhead between turns
Tool Callbacks
Monitor tool executions for logging, auditing, or analytics:
callback = fn event ->
Logger.info("Tool #{event.name} executed",
input: event.input,
result: event.result,
is_error: event.is_error
)
end
{:ok, session} = ClaudeCode.start_link(tool_callback: callback)
MCP Integration (Optional)
Expose Elixir tools to Claude using Hermes MCP:
# Add {:hermes_mcp, "~> 0.14"} to your deps
# Start MCP server with your tools
{:ok, config_path} = ClaudeCode.MCP.Server.start_link(
server: MyApp.MCPServer,
port: 9001
)
# Connect ClaudeCode to MCP server
{:ok, session} = ClaudeCode.start_link(mcp_config: config_path)
# Claude can now use your custom tools!
📚 Documentation
- 🚀 Getting Started - Step-by-step tutorial for new users
- 📖 Documentation Hub - All guides and references
- 🏭 Production Guide - Fault-tolerant production deployments
- 💻 Examples - Real-world usage patterns and code samples
- 📖 API Reference - Complete API documentation
- 🔧 Troubleshooting - Common issues and solutions
🤝 Contributing
We ❤️ contributions! Whether it's:
- 🐛 Bug reports - Found an issue? Let us know!
- 💡 Feature requests - Have an idea? We'd love to hear it!
- 📝 Documentation - Help make our docs even better
- 🔧 Code contributions - PRs welcome!
See our Contributing Guide to get started.
🛠️ Development
# Clone and setup
git clone https://github.com/guess/claude_code.git
cd claude_code
mix deps.get
# Run tests and quality checks
mix test
mix quality # format, credo, dialyzer
📜 License
MIT License - see LICENSE for details.
Built for Elixir developers on top of the Claude Code CLI.