Changelog
View SourceAll notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
[0.16.0] - 2026-01-27
Added
:envoption - Pass custom environment variables to the CLI subprocess ([aa2d3eb])- Merge precedence: system env → user
:env→ SDK vars →:api_key - Useful for MCP tools that need specific env vars or custom PATH configurations
- Aligns with Python SDK's environment handling
- Merge precedence: system env → user
[0.15.0] - 2026-01-26
Added
- Session history reading - Read and parse conversation history from session files ([ad737ea])
ClaudeCode.conversation/2- Read conversation (user/assistant messages) by session IDClaudeCode.History.list_projects/1- List all projects with session historyClaudeCode.History.list_sessions/2- List all sessions for a projectClaudeCode.History.read_session/2- Read all raw entries from a session (low-level)
- JSON encoding for all structs - Implement
Jason.EncoderandJSON.Encoderprotocols ([a511d5c])- All message types: SystemMessage, AssistantMessage, UserMessage, ResultMessage, PartialAssistantMessage, CompactBoundaryMessage
- All content blocks: TextBlock, ThinkingBlock, ToolUseBlock, ToolResultBlock
- Nil values are automatically excluded from encoded output
- String.Chars for messages and content blocks - Use
to_string/1or string interpolation ([b3a9571])TextBlock- returns the text contentThinkingBlock- returns the thinking contentAssistantMessage- concatenates all text blocks from the messagePartialAssistantMessage- returns delta text (empty string for non-text deltas)
Changed
- Conversation message parsing refactored - Extracted to dedicated module with improved error logging ([22c381c])
[0.14.0] - 2026-01-15
Added
:session_idoption - Specify a custom UUID as the session ID for conversations ([2f2c919]):disable_slash_commandsoption - Disable all skills/slash commands ([16f96b4]):no_session_persistenceoption - Disable session persistence so sessions are not saved to disk ([16f96b4])- New permission modes -
:delegate,:dont_ask, and:planadded to:permission_modeoption ([16f96b4]) - New usage tracking fields -
cache_creation,service_tier,web_fetch_requests,cost_usd,context_window,max_output_tokensin result and assistant message usage ([bed060b]) - New system message fields -
claude_code_version,agents,skills,pluginsfor enhanced session metadata ([bed060b])
Fixed
- SystemMessage
slash_commandsandoutput_styleparsing - Fields were always empty/default ([bed060b]) - ResultMessage
model_usageparsing - Per-model token counts and costs were always 0/nil ([bed060b])
[0.13.3] - 2026-01-14
Changed
ResultMessageoptional fields use sensible defaults -model_usagedefaults to%{}andpermission_denialsdefaults to[]instead ofnil([cda582b])
Fixed
ResultMessage.resultis now optional - Error messages from the CLI may contain anerrorsarray instead of aresultfield. The field no longer crashes when nil and displays errors appropriately ([c06e825])
[0.13.2] - 2026-01-08
Fixed
ToolResultBlockcontent parsing - When CLI returns content as a list of text blocks, they are now parsed intoTextBlockstructs instead of raw maps ([5361e2d])
[0.13.1] - 2026-01-07
Changed
- Simplified test stub naming - Default stub name changed from
ClaudeCode.SessiontoClaudeCode([2fd244f])- Config:
adapter: {ClaudeCode.Test, ClaudeCode}instead of{ClaudeCode.Test, ClaudeCode.Session} - Stubs:
ClaudeCode.Test.stub(ClaudeCode, fn ...)instead ofstub(ClaudeCode.Session, fn ...) - Custom names still supported for multiple stub behaviors in same test
- Config:
Added
tool_result/2accepts maps - Maps are automatically JSON-encoded ([6d9fca6])- Example:
ClaudeCode.Test.tool_result(%{status: "success", data: [1, 2, 3]})
- Example:
Fixed
tool_resultcontent format - Content is now[TextBlock.t()]instead of plain string ([dfba539])- Matches MCP
CallToolResultformat where content is an array of content blocks - Fixes compatibility with code expecting
content: [%{"type" => "text", "text" => ...}]
- Matches MCP
[0.13.0] - 2026-01-07
Added
ClaudeCode.Testmodule - Req.Test-style test helpers for mocking Claude responses ([9f78103])stub/2- Register function or static message stubs for test isolationallow/3- Share stubs with spawned processes for async testsset_mode_to_shared/0- Enable shared mode for integration tests- Message helpers:
text/2,tool_use/3,tool_result/2,thinking/2,result/2,system/1 - Auto-generates system/result messages, links tool IDs, unifies session IDs
- Uses
NimbleOwnershipfor process-based isolation withasync: truesupport
ClaudeCode.Test.Factorymodule - Test data generation for all message and content types ([54dcfd7])- Struct factories:
assistant_message/1,user_message/1,result_message/1,system_message/1 - Content block factories:
text_block/1,tool_use_block/1,tool_result_block/1,thinking_block/1 - Stream event factories for partial message testing
- Convenience functions with positional arguments for common cases
- Struct factories:
- Testing guide - Comprehensive documentation for testing ClaudeCode integrations ([7dfe509])
[0.12.0] - 2026-01-07
Added
- New stream helpers for common use cases ([0775bd4])
final_text/1- Returns only the final result text, simplest way to get Claude's answercollect/1- Returns structured summary with text, thinking, tool_calls, and resulttap/2- Side-effect function for logging/monitoring without filtering the streamon_tool_use/2- Callback invoked for each tool use, useful for progress indicators
Changed
collect/1returnstool_callsinstead oftool_uses([7eebfeb])- Now returns
{tool_use, tool_result}tuples pairing each tool invocation with its result - If a tool use has no matching result, the result will be
nil - Migration: Change
summary.tool_usestosummary.tool_callsand update iteration to handle tuples
- Now returns
Removed
buffered_text/1stream helper - Usefinal_text/1orcollect/1instead ([4a1ee97])
[0.11.0] - 2026-01-07
Changed
- Renamed
StreamEventMessagetoPartialAssistantMessage- Aligns with TypeScript SDK naming (SDKPartialAssistantMessage)ClaudeCode.Message.StreamEventMessage→ClaudeCode.Message.PartialAssistantMessage- The struct still uses
type: :stream_eventto match the wire format - Helper function renamed:
stream_event?/1→partial_assistant_message?/1
Added
:fork_sessionoption - Create a new session ID when resuming a conversation- Use with
:resumeto branch a conversation:start_link(resume: session_id, fork_session: true) - Original session continues unchanged, fork gets its own session ID after first query
- Use with
[0.9.0] - 2026-01-06
Changed
- BREAKING: Simplified public API - Renamed and reorganized query functions ([e7ca31a])
query_stream/3→stream/3- Primary API for session-based streaming queriesquery/3(session-based sync) → Removed - Usestream/3insteadquery/2(new) - One-off convenience function with auto session management- Migration: Replace
ClaudeCode.query(session, prompt)withClaudeCode.stream(session, prompt) |> Enum.to_list() - Migration: Replace
ClaudeCode.query_stream(session, prompt)withClaudeCode.stream(session, prompt)
Added
- Concurrent request queuing - Multiple concurrent streams on same session are now properly queued and executed sequentially ([e7ca31a])
Fixed
- Named process handling - Stream cleanup now properly handles named processes (atoms,
:via,:globaltuples) ([e7ca31a])
[0.8.1] - 2026-01-06
Fixed
- Process cleanup on stop - Claude subprocess now properly terminates when calling
ClaudeCode.stop/1([a560ff1])
[0.8.0] - 2026-01-06
Changed
- BREAKING: Renamed message type modules - Added "Message" suffix for clarity
ClaudeCode.Message.Assistant→ClaudeCode.Message.AssistantMessageClaudeCode.Message.User→ClaudeCode.Message.UserMessageClaudeCode.Message.Result→ClaudeCode.Message.ResultMessageClaudeCode.Message.StreamEvent→ClaudeCode.Message.PartialAssistantMessage- New
ClaudeCode.Message.SystemMessageandClaudeCode.Message.CompactBoundaryMessagemessage types
- BREAKING: Renamed content block modules - Added "Block" suffix for consistency
ClaudeCode.Content.Text→ClaudeCode.Content.TextBlockClaudeCode.Content.ToolUse→ClaudeCode.Content.ToolUseBlockClaudeCode.Content.ToolResult→ClaudeCode.Content.ToolResultBlockClaudeCode.Content.Thinking→ClaudeCode.Content.ThinkingBlock
Added
- New system message fields - Support for additional Claude Code features
:output_style- Claude's configured output style:slash_commands- Available slash commands:uuid- Session UUID
- Extended message type fields - Better access to API response metadata
AssistantMessage::priority,:sequence_id,:finalize_stackResultMessage::session_id,:duration_ms,:usage,:parent_message_id,:sequence_idUserMessage::priority,:sequence_id,:finalize_stack
Fixed
:mcp_serversoption validation - Fixed handling of MCP server configurations ([0c7e849])
[0.7.0] - 2026-01-02
Added
:strict_mcp_configoption - Control MCP server loading behavior ([a095516])- When
true, ignores global MCP server configurations - Useful for disabling all MCP tools:
tools: [], strict_mcp_config: true - Or using only built-in tools:
tools: :default, strict_mcp_config: true
- When
Changed
- BREAKING:
ClaudeCode.querynow returns full%Result{}struct instead of just text- Before:
{:ok, "response text"}or{:error, {:claude_error, "message"}} - After:
{:ok, %ClaudeCode.Message.Result{result: "response text", ...}}or{:error, %ClaudeCode.Message.Result{is_error: true, ...}} - Provides access to metadata:
session_id,is_error,subtype,duration_ms,usage, etc. - Migration: Change
{:ok, text}to{:ok, result}and useresult.resultto access the response text ResultimplementsString.Chars, soIO.puts(result)prints just the text
- Before:
Removed
:input_formatoption - No longer exposed in public API ([c7ebab2]):output_formatoption - No longer exposed in public API ([c7ebab2])
[0.6.0] - 2025-12-31
Added
:mcp_serversmodule map format - Pass Hermes modules with custom environment variables ([63d4b72])- Simple form:
%{"tools" => MyApp.MCPServer} - Extended form with env:
%{"tools" => %{module: MyApp.MCPServer, env: %{"DEBUG" => "1"}}} - Custom env is merged with defaults (
MIX_ENV: "prod"), can override MIX_ENV - Updated MCP docs to recommend
mcp_serversas the primary configuration method
- Simple form:
:json_schemaoption - JSON Schema for structured output validation ([485513f])- Accepts a map (auto-encoded to JSON) or pre-encoded JSON string
- Maps to
--json-schemaCLI flag
:max_budget_usdoption - Maximum dollar amount to spend on API calls ([5bf996a])- Accepts float or integer values
- Maps to
--max-budget-usdCLI flag
:toolsoption - Specify available tools from the built-in set ([5bf996a])- Use
:defaultfor all tools,[]to disable all, or a list of tool names - Maps to
--toolsCLI flag
- Use
:agentoption - Agent name for the session ([5bf996a])- Different from
:agentswhich defines custom agent configurations - Maps to
--agentCLI flag
- Different from
:betasoption - Beta headers to include in API requests ([5bf996a])- Accepts a list of beta feature names
- Maps to
--betasCLI flag
Removed
query_async/3- Removed push-based async API in favor ofquery_stream/3query_stream/3provides a more idiomatic Elixir Stream-based API- For push-based messaging (LiveView, GenServers), wrap
query_stream/3in a Task - See Phoenix integration guide for migration examples
- Advanced Streaming API - Removed low-level streaming functions
receive_messages/2- Usequery_stream/3insteadreceive_response/2- Usequery_stream/3 |> ClaudeCode.Stream.until_result()insteadinterrupt/2- To cancel, useTask.shutdown/2on the consuming task
Changed
ClaudeCode.Stream- Now uses pull-based messaging internally instead of process mailbox
[0.5.0] - 2025-12-30
Removed
:permission_handleroption - Removed unimplemented option from session schema
Added
- Persistent streaming mode - Sessions use bidirectional stdin/stdout communication
- Auto-connect on first query, auto-disconnect on session stop
- Multi-turn conversations without subprocess restarts
- New
:resumeoption instart_link/1for resuming sessions - New
ClaudeCode.get_session_id/1andClaudeCode.Inputmodule
- Extended thinking support -
ClaudeCode.Content.Thinkingfor reasoning blocks- Stream utilities:
ClaudeCode.Stream.thinking_content/1,ClaudeCode.Stream.thinking_deltas/1 StreamEventhelpers:thinking_delta?/1,get_thinking/1
- Stream utilities:
- MCP servers map option -
:mcp_serversaccepts inline server configurations- Supports
stdio,sse, andhttptransport types
- Supports
- Character-level streaming -
include_partial_messages: trueoption- Stream utilities:
ClaudeCode.Stream.text_deltas/1,ClaudeCode.Stream.content_deltas/1 - Enables real-time streaming for LiveView applications
- Stream utilities:
- Tool callback -
:tool_callbackoption for logging/auditing tool usageClaudeCode.ToolCallbackmodule for correlating tool use and results
- Hermes MCP integration - Expose Elixir tools to Claude via MCP
- Optional dependency:
{:hermes_mcp, "~> 0.14", optional: true} ClaudeCode.MCP.Configfor generating MCP configurationClaudeCode.MCP.Serverfor starting Hermes MCP servers
- Optional dependency:
Changed
- Minimum Elixir version raised to 1.18
ClaudeCode.Stream.filter_type/2now supports:stream_eventand:text_delta
[0.4.0] - 2025-10-02
Added
- Custom agents support -
:agentsoption for defining agent configurations - Settings options -
:settingsand:setting_sourcesfor team settings
Changed
:api_keynow optional - CLI handlesANTHROPIC_API_KEYfallback
Fixed
- CLI streaming with explicit output-format support
[0.3.0] - 2025-06-16
Added
ClaudeCode.Supervisor- Production supervision for multiple Claude sessions- Static named sessions and dynamic session management
- Global, local, and registry-based naming
- OTP supervision with automatic restarts
[0.2.0] - 2025-06-16
Added
ANTHROPIC_API_KEYenvironment variable fallback
Changed
- BREAKING: Renamed API functions:
query_sync/3→query/3query/3→query_stream/3
start_link/1options now optional (defaults to[])
[0.1.0] - 2025-06-16
Added
Complete SDK Implementation (Phases 1-4):
- Session management with GenServer-based architecture
- Synchronous queries with
query_sync/3(renamed toquery/3in later version) - Streaming queries with native Elixir streams via
query/3(renamed toquery_stream/3in later version) - Async queries with
query_async/3for manual message handling - Complete message type parsing (system, assistant, user, result)
- Content block handling (text, tool use, tool result) with proper struct types
- Flattened options API with NimbleOptions validation
- Option precedence system: query > session > app config > defaults
- Application configuration support via
config :claude_code - Comprehensive CLI flag mapping for all Claude Code options
Core Modules:
ClaudeCode- Main interface with session managementClaudeCode.Session- GenServer for CLI subprocess managementClaudeCode.CLI- Binary detection and command buildingClaudeCode.Options- Options validation and CLI conversionClaudeCode.Stream- Stream utilities for real-time processingClaudeCode.Message- Unified message parsingClaudeCode.Content- Content block parsingClaudeCode.Types- Type definitions matching SDK schema
Message Type Support:
- System messages with session initialization
- Assistant messages with nested content structure
- User messages with proper content blocks
- Result messages with error subtypes
- Tool use and tool result content blocks
Streaming Features:
- Native Elixir Stream integration with backpressure handling
- Stream utilities:
text_content/1,tool_uses/1,filter_type/2 - Buffered text streaming with
buffered_text/1 - Concurrent streaming request support
- Proper stream cleanup and error handling
Configuration System:
- 15+ configuration options with full validation
- Support for API key, model, system prompt, allowed tools
- Permission mode options:
:default,:accept_edits,:bypass_permissions - Timeout, max turns, working directory configuration
- Custom permission handler support
- Query-level option overrides
Implementation Details
- Flattened options API for intuitive configuration
- Updated CLI flag mappings to match latest Claude Code CLI
- Enhanced error handling with proper message subtypes
- Shell wrapper implementation to prevent CLI hanging
- Proper JSON parsing for all message types
- Concurrent query isolation with dedicated ports
- Memory management for long-running sessions
- Session continuity across multiple queries
Security
- API keys passed via environment variables only
- Shell command injection prevention with proper escaping
- Subprocess isolation with dedicated ports per query
- No sensitive data in command arguments or logs
Documentation
- Complete module documentation with doctests
- Comprehensive README with installation and usage examples
- Architecture documentation explaining CLI integration
- Streamlined roadmap focusing on current status and future enhancements
Testing
- 146+ comprehensive tests covering all functionality
- Unit tests for all modules with mock CLI support
- Integration tests with real CLI when available
- Property-based testing for message parsing
- Stream testing with concurrent scenarios
- Coverage reporting with ExCoveralls