An idiomatic Elixir SDK for embedding OpenAI's Codex agent in your workflows and applications. This SDK wraps the codex-rs
executable, providing a complete, production-ready interface with streaming support, comprehensive event handling, and robust testing utilities.
- Complete Codex Integration: Full-featured wrapper around the
codex-rs
CLI - Streaming & Non-Streaming: Support for both real-time event streaming and buffered responses
- Type Safety: Comprehensive structs for all events, items, and options
- OTP Native: Built on GenServer for robust process management
- Structured Output: JSON schema support with automatic temporary file handling
- Thread Management: Create new conversations or resume existing sessions
- Battle-Tested: Comprehensive test suite using Supertester for deterministic OTP testing
- Production Ready: Robust error handling, supervision, and telemetry integration
- Working Directory Controls: Flexible sandbox modes and path management
Add codex_sdk
to your list of dependencies in mix.exs
:
def deps do
[
{:codex_sdk, "~> 0.1.0"}
]
end
You must have the codex
CLI installed. Install it via npm or Homebrew:
# Using npm
npm install -g @openai/codex
# Using Homebrew
brew install codex
For authentication, sign in with your ChatGPT account:
codex
# Select "Sign in with ChatGPT"
See the OpenAI Codex documentation for more authentication options.
# Start a new conversation
{:ok, thread} = Codex.start_thread()
# Run a turn and get results
{:ok, result} = Codex.Thread.run(thread, "Explain the purpose of GenServers in Elixir")
# Access the final response
IO.puts(result.final_response)
# Inspect all items (messages, reasoning, commands, file changes, etc.)
IO.inspect(result.items)
# Continue the conversation
{:ok, next_result} = Codex.Thread.run(thread, "Give me an example")
For real-time processing of events as they occur:
{:ok, thread} = Codex.start_thread()
{:ok, stream} = Codex.Thread.run_streamed(
thread,
"Analyze this codebase and suggest improvements"
)
# Process events as they arrive
for event <- stream do
case event do
%Codex.Events.ItemStarted{item: item} ->
IO.puts("New item: #{item.type}")
%Codex.Events.ItemCompleted{item: %{type: "agent_message", text: text}} ->
IO.puts("Response: #{text}")
%Codex.Events.TurnCompleted{usage: usage} ->
IO.puts("Tokens used: #{usage.input_tokens + usage.output_tokens}")
_ ->
:ok
end
end
Request JSON responses conforming to a specific schema:
schema = %{
"type" => "object",
"properties" => %{
"summary" => %{"type" => "string"},
"issues" => %{
"type" => "array",
"items" => %{
"type" => "object",
"properties" => %{
"severity" => %{"type" => "string", "enum" => ["low", "medium", "high"]},
"description" => %{"type" => "string"},
"file" => %{"type" => "string"}
},
"required" => ["severity", "description"]
}
}
},
"required" => ["summary", "issues"]
}
{:ok, thread} = Codex.start_thread()
{:ok, result} = Codex.Thread.run(
thread,
"Analyze the code quality of this project",
output_schema: schema
)
# Parse the JSON response
{:ok, data} = Jason.decode(result.final_response)
IO.inspect(data["issues"])
Threads are persisted in ~/.codex/sessions
. Resume previous conversations:
thread_id = "thread_abc123"
{:ok, thread} = Codex.resume_thread(thread_id)
{:ok, result} = Codex.Thread.run(thread, "Continue from where we left off")
# Codex-level options
codex_options = %Codex.Options{
codex_path_override: "/custom/path/to/codex",
base_url: "https://api.openai.com",
api_key: System.get_env("OPENAI_API_KEY")
}
# Thread-level options
thread_options = %Codex.Thread.Options{
model: "o1",
sandbox_mode: true,
working_directory: "/path/to/project",
skip_git_repo_check: false
}
{:ok, thread} = Codex.start_thread(codex_options, thread_options)
# Turn-level options
turn_options = %Codex.Turn.Options{
output_schema: my_json_schema
}
{:ok, result} = Codex.Thread.run(thread, "Your prompt", turn_options)
The SDK follows a layered architecture built on OTP principles:
Codex
: Main entry point for starting and resuming threadsCodex.Thread
: Manages individual conversation threads and turn executionCodex.Exec
: GenServer that manages thecodex-rs
OS process via PortCodex.Events
: Comprehensive event type definitionsCodex.Items
: Thread item structs (messages, commands, file changes, etc.)Codex.Options
: Configuration structs for all levelsCodex.OutputSchemaFile
: Helper for managing JSON schema temporary files
┌─────────────┐
│ Client │
└──────┬──────┘
│
▼
┌─────────────────┐
│ Codex.Thread │ (manages turn state)
└────────┬────────┘
│
▼
┌──────────────────┐
│ Codex.Exec │ (GenServer - manages codex-rs process)
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Port (stdin/ │ (IPC with codex-rs via JSONL)
│ stdout) │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ codex-rs │ (OpenAI's Codex CLI)
└──────────────────┘
The SDK provides structured events for all Codex operations:
ThreadStarted
- New thread initialized with thread_idTurnStarted
- Agent begins processing a promptTurnCompleted
- Turn finished with usage statisticsTurnFailed
- Turn encountered an error
ItemStarted
- New item added to threadItemUpdated
- Item state changedItemCompleted
- Item reached terminal state
AgentMessage
- Text or JSON response from the agentReasoning
- Agent's reasoning summaryCommandExecution
- Shell command execution with outputFileChange
- File modifications (add, update, delete)McpToolCall
- Model Context Protocol tool invocationsWebSearch
- Web search queries and resultsTodoList
- Agent's running task listError
- Non-fatal error items
The SDK uses Supertester for robust, deterministic OTP testing:
# Run all tests
mix test
# Run with coverage
mix test --cover
# Run integration tests (requires codex CLI)
CODEX_TEST_LIVE=true mix test --include integration
- Zero
Process.sleep
: All tests use proper OTP synchronization - Fully Async: All tests run with
async: true
- Mock Support: Tests work with mocked
codex-rs
output - Live Testing: Optional integration tests with real CLI
- Chaos Engineering: Resilience testing for process crashes
- Performance Assertions: SLA verification and leak detection
See the examples/
directory for comprehensive demonstrations:
basic.exs
- Simple conversation and streamingstructured_output.exs
- JSON schema usagemulti_turn.exs
- Extended conversations with contextfile_operations.exs
- Watching file changes and commandserror_handling.exs
- Robust error recovery patterns
Run examples with:
mix run examples/basic.exs
Comprehensive documentation is available:
- API Reference - Complete module and function docs
- Architecture Guide - System design and components
- Implementation Plan - Development roadmap
- Testing Strategy - TDD approach and patterns
- API Reference Doc - Detailed API specifications
- Examples Guide - Usage patterns and recipes
Current Version: 0.1.0 (In Development)
- Project setup and structure
- Documentation and design
- Core module implementation
- Event and item type definitions
- Exec GenServer with Port management
- Thread management and turn execution
- Streaming support
- Test suite with Supertester
- Examples and documentation
- CI/CD pipeline
See docs/03-implementation-plan.md for detailed progress.
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature
) - Write tests for your changes
- Ensure all tests pass (
mix test
) - Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- OpenAI team for the Codex CLI and agent technology
- Elixir community for excellent OTP tooling and libraries
- Gemini Ex for SDK inspiration
- Supertester for robust testing utilities
- OpenAI Codex - The official Codex CLI
- Codex TypeScript SDK - Official TypeScript SDK
- Gemini Ex - Elixir client for Google's Gemini AI
Made with ❤️ and Elixir