ClaudeCode (ClaudeCode v0.16.0)

View Source

Elixir SDK for Claude Code CLI.

This module provides the main interface for interacting with Claude Code through the command-line interface. It manages sessions as GenServer processes that maintain persistent CLI subprocesses for efficient bidirectional communication.

API Overview

FunctionPurpose
start_link/1Start a session (with optional resume: id)
stop/1Stop a session
stream/3Send prompt to session, get message stream
query/2One-off query (auto start/stop)

Quick Start

# Multi-turn conversation (primary API)
{:ok, session} = ClaudeCode.start_link(api_key: "sk-ant-...")

ClaudeCode.stream(session, "What is 5 + 3?")
|> Enum.each(&IO.inspect/1)

ClaudeCode.stream(session, "Multiply that by 2")
|> Enum.each(&IO.inspect/1)

ClaudeCode.stop(session)

# One-off query (convenience)
{:ok, result} = ClaudeCode.query("What is 2 + 2?", api_key: "sk-ant-...")
IO.puts(result)

Session Lifecycle

Sessions automatically connect to the Claude CLI on startup and disconnect on stop. The persistent connection enables:

  • Efficient multi-turn conversations without CLI restart overhead
  • Automatic session continuity via session IDs
  • Real-time streaming of responses

Supervision for Production

For production applications, use the supervisor for fault tolerance and automatic restart capabilities:

# In your application supervision tree
children = [
  {ClaudeCode.Supervisor, [
    [name: :code_reviewer, api_key: api_key, system_prompt: "You review Elixir code"],
    [name: :test_writer, api_key: api_key, system_prompt: "You write ExUnit tests"]
  ]}
]

Supervisor.start_link(children, strategy: :one_for_one)

# Access supervised sessions from anywhere
:code_reviewer
|> ClaudeCode.stream("Review this function")
|> ClaudeCode.Stream.text_content()
|> Enum.join()

Resume Previous Conversations

# Get session ID from a previous interaction
session_id = ClaudeCode.get_session_id(session)

# Later: resume the conversation
{:ok, new_session} = ClaudeCode.start_link(
  api_key: "sk-ant-...",
  resume: session_id
)

ClaudeCode.stream(new_session, "Continue where we left off")
|> Enum.each(&IO.inspect/1)

# Or fork to create a branch with a new session ID
{:ok, forked} = ClaudeCode.start_link(
  resume: session_id,
  fork_session: true
)

See ClaudeCode.Supervisor for advanced supervision patterns.

Summary

Functions

Checks if a session is alive.

Clears the current session ID to start a fresh conversation.

Reads conversation history from a session's JSONL file.

Gets the current session ID for conversation continuity.

Sends a one-off query to Claude and returns the result.

Starts a new Claude Code session.

Stops a Claude Code session.

Sends a query to a session and returns a stream of messages.

Returns the SDK version string.

Types

message_stream()

@type message_stream() :: Enumerable.t(ClaudeCode.Message.t())

query_response()

@type query_response() ::
  {:ok, ClaudeCode.Message.ResultMessage.t()}
  | {:error, ClaudeCode.Message.ResultMessage.t() | term()}

session()

@type session() :: pid() | atom() | {:via, module(), any()}

Functions

alive?(session)

@spec alive?(session()) :: boolean()

Checks if a session is alive.

Examples

true = ClaudeCode.alive?(session)

clear(session)

@spec clear(session()) :: :ok

Clears the current session ID to start a fresh conversation.

This will cause the next query to start a new conversation context rather than continuing the existing one. Useful when you want to reset the conversation history.

Examples

:ok = ClaudeCode.clear(session)

# Next stream will start fresh
ClaudeCode.stream(session, "Hello!")
|> Enum.each(&IO.inspect/1)

conversation(session_or_id, opts \\ [])

@spec conversation(
  session() | String.t(),
  keyword()
) ::
  {:ok,
   [
     ClaudeCode.Message.AssistantMessage.t()
     | ClaudeCode.Message.UserMessage.t()
   ]}
  | {:error, term()}

Reads conversation history from a session's JSONL file.

Accepts either a session ID string or a running session reference. Returns user and assistant messages parsed into SDK message structs.

Options

  • :project_path - Specific project path to search in (optional)
  • :claude_dir - Override the Claude directory (default: ~/.claude)

Examples

# Read conversation history by session ID
{:ok, messages} = ClaudeCode.conversation("abc123-def456")

# Or from a running session
{:ok, session} = ClaudeCode.start_link()
ClaudeCode.query(session, "Hello!")
{:ok, messages} = ClaudeCode.conversation(session)

Enum.each(messages, fn
  %ClaudeCode.Message.UserMessage{message: %{content: content}} ->
    IO.puts("User: #{inspect(content)}")
  %ClaudeCode.Message.AssistantMessage{message: %{content: blocks}} ->
    text = Enum.map_join(blocks, "", fn
      %ClaudeCode.Content.TextBlock{text: t} -> t
      _ -> ""
    end)
    IO.puts("Assistant: #{text}")
end)

See ClaudeCode.History for more options.

get_session_id(session)

@spec get_session_id(session()) :: String.t() | nil

Gets the current session ID for conversation continuity.

Returns the session ID that Claude CLI is using to maintain conversation context. This ID is automatically captured from CLI responses and used for subsequent queries to continue the conversation.

You can use this session ID with the :resume option when starting a new session to continue the conversation later, or with :fork_session to create a branch.

Examples

session_id = ClaudeCode.get_session_id(session)
# => "abc123-session-id"

# For a new session with no queries yet
nil = ClaudeCode.get_session_id(session)

# Resume later
{:ok, new_session} = ClaudeCode.start_link(resume: session_id)

# Or fork the conversation
{:ok, forked} = ClaudeCode.start_link(resume: session_id, fork_session: true)

query(prompt, opts \\ [])

@spec query(
  String.t(),
  keyword()
) :: query_response()

Sends a one-off query to Claude and returns the result.

This is a convenience function that automatically manages a temporary session. For multi-turn conversations, use start_link/1 and stream/3 instead.

Options

See ClaudeCode.Options.session_schema/0 for all available options.

Examples

# Simple one-off query
{:ok, result} = ClaudeCode.query("What is 2 + 2?", api_key: "sk-ant-...")
IO.puts(result)  # Result implements String.Chars
# => "4"

# With options
{:ok, result} = ClaudeCode.query("Complex query",
  api_key: "sk-ant-...",
  model: "opus",
  system_prompt: "Focus on performance optimization"
)

# Handle errors
case ClaudeCode.query("Do something risky", api_key: "sk-ant-...") do
  {:ok, result} -> IO.puts(result.result)
  {:error, %ClaudeCode.Message.ResultMessage{is_error: true} = result} ->
    IO.puts("Claude error: #{result.result}")
  {:error, reason} -> IO.puts("Error: #{inspect(reason)}")
end

start_link(opts \\ [])

@spec start_link(keyword()) :: GenServer.on_start()

Starts a new Claude Code session.

The session automatically connects to a persistent CLI subprocess on startup. This enables efficient multi-turn conversations without CLI restart overhead.

Options

For complete option documentation including types, validation rules, and examples, see ClaudeCode.Options.session_schema/0 and the ClaudeCode.Options module.

Key options:

  • :api_key - Anthropic API key (or set ANTHROPIC_API_KEY env var)
  • :resume - Session ID to resume a previous conversation
  • :model - Claude model to use
  • :system_prompt - Custom system prompt

Examples

# Start a basic session
{:ok, session} = ClaudeCode.start_link(api_key: "sk-ant-...")

# Start with application config (if api_key is configured)
{:ok, session} = ClaudeCode.start_link()

# Resume a previous conversation
{:ok, session} = ClaudeCode.start_link(
  api_key: "sk-ant-...",
  resume: "previous-session-id"
)

# Start with custom options
{:ok, session} = ClaudeCode.start_link(
  api_key: "sk-ant-...",
  model: "opus",
  system_prompt: "You are an Elixir expert",
  allowed_tools: ["View", "Edit", "Bash(git:*)"],
  add_dir: ["/tmp", "/var/log"],
  max_turns: 20,
  timeout: 180_000,
  name: :my_session
)

stop(session)

@spec stop(session()) :: :ok

Stops a Claude Code session.

This closes the CLI subprocess and cleans up resources.

Examples

:ok = ClaudeCode.stop(session)

stream(session, prompt, opts \\ [])

@spec stream(session(), String.t(), keyword()) :: message_stream()

Sends a query to a session and returns a stream of messages.

This is the primary API for interacting with Claude. The stream emits messages as they arrive and automatically completes when Claude finishes responding.

Options

Query-level options override session-level options. See ClaudeCode.Options.query_schema/0 for all available query options.

Examples

# Stream all messages
session
|> ClaudeCode.stream("Write a hello world program")
|> Enum.each(&IO.inspect/1)

# Stream with option overrides
session
|> ClaudeCode.stream("Explain quantum computing",
     system_prompt: "Focus on practical applications",
     allowed_tools: ["View"])
|> ClaudeCode.Stream.text_content()
|> Enum.each(&IO.write/1)

# Collect all text content
text =
  session
  |> ClaudeCode.stream("Tell me a story")
  |> ClaudeCode.Stream.text_content()
  |> Enum.join()

# Multi-turn conversation
{:ok, session} = ClaudeCode.start_link(api_key: "sk-ant-...")

ClaudeCode.stream(session, "What is 5 + 3?")
|> Enum.each(&IO.inspect/1)

ClaudeCode.stream(session, "Multiply that by 2")
|> Enum.each(&IO.inspect/1)

version()

@spec version() :: String.t()

Returns the SDK version string.

Used internally for environment variables passed to the CLI subprocess.

Examples

iex> ClaudeCode.version()
"0.16.0"