Complete API documentation for all modules in the Elixir Codex SDK.
Module Overview
| Module | Purpose |
|---|---|
Codex | Main entry point for starting and resuming threads |
Codex.Thread | Manages conversation threads and turn execution |
Codex.Transport | Transport behaviour for turn execution |
Codex.AppServer | Stateful app-server JSON-RPC connection + v2 request APIs |
Codex.AppServer.V1 | Legacy app-server compatibility helpers for v1 conversation APIs |
Codex.Agent | Reusable agent definition (instructions, tools, hooks) |
Codex.RunConfig | Per-run overrides (max_turns, history behavior, hooks) |
Codex.AgentRunner | Multi-turn runner coordinating threads and tool invocations |
Codex.Exec | Exec JSONL subprocess wrapper (codex exec --json) |
Codex.Sessions | Session file utilities plus apply/undo helpers |
Codex.Events | Event type definitions |
Codex.Items | Thread item type definitions |
Codex.Options | Configuration structs |
Codex.Protocol.* | Protocol enums and payload helpers (collaboration modes, request_user_input, rate limits) |
Codex.Config.Overrides | Config override serialization, nested map flattening, and TOML value validation |
Codex.Runtime.Erlexec | Unified erlexec startup shared across subprocess modules |
Codex.Runtime.Env | Subprocess environment construction (originator override, API key forwarding) |
Codex.Config.BaseURL | Base URL resolution with option → env → default precedence |
Codex.Config.OptionNormalizers | Shared validation for reasoning summary, verbosity, history persistence |
Codex.Realtime | Bidirectional voice via OpenAI Realtime API (WebSocket) |
Codex.Voice | Non-realtime STT → Workflow → TTS pipeline |
Codex.OutputSchemaFile | JSON schema file management |
Transports
The SDK supports both upstream external transports:
- Exec JSONL (default):
codex exec --json - App-server JSON-RPC (optional):
codex app-server(newline-delimited JSON over stdio)
Select transport per-thread via Codex.Thread.Options.transport:
{:ok, conn} = Codex.AppServer.connect(codex_opts)
{:ok, thread} = Codex.start_thread(codex_opts, %{transport: {:app_server, conn}})For legacy v1 app-server deployments, use Codex.AppServer.V1 request helpers for
conversation APIs.
Codex
Main entry point for the Codex SDK. Use this module to create new threads or resume existing ones.
Functions
start_thread/2
Creates a new conversation thread with the Codex agent.
Signature:
@spec start_thread(Codex.Options.t(), Codex.Thread.Options.t()) ::
{:ok, Codex.Thread.t()} | {:error, term()}Parameters:
codex_opts(optional): Global Codex options. Defaults to%Codex.Options{}thread_opts(optional): Thread-specific options. Defaults to%Codex.Thread.Options{}
Returns:
{:ok, thread}: New thread struct ready for turn execution{:error, reason}: Configuration error
Examples:
# Start with defaults
{:ok, thread} = Codex.start_thread()
# Start with custom API key
codex_opts = %Codex.Options{api_key: "sk-..."}
{:ok, thread} = Codex.start_thread(codex_opts)
# Start with thread options
thread_opts = %Codex.Thread.Options{
sandbox: :read_only,
working_directory: "/path/to/project"
}
{:ok, thread} = Codex.start_thread(%Codex.Options{}, thread_opts)resume_thread/3
Resumes an existing conversation thread from its persisted session.
Signature:
@spec resume_thread(String.t() | :last, Codex.Options.t(), Codex.Thread.Options.t()) ::
{:ok, Codex.Thread.t()} | {:error, term()}Parameters:
thread_id: ID of the thread to resume (from~/.codex/sessions) or:lastfor the most recent sessioncodex_opts(optional): Global Codex optionsthread_opts(optional): Thread-specific options
Returns:
{:ok, thread}: Thread struct with existing thread_id{:error, reason}: Thread not found or configuration error
Examples:
# Resume with thread ID
{:ok, thread} = Codex.resume_thread("thread_abc123")
# Resume the most recent session
{:ok, thread} = Codex.resume_thread(:last)
# Resume with custom options
codex_opts = %Codex.Options{base_url: "https://custom.api"}
{:ok, thread} = Codex.resume_thread("thread_abc123", codex_opts)Notes:
- Threads are persisted in
~/.codex/sessionsby codex-rs - Thread history and context are automatically restored
- The thread_id is available after the first turn completes
Agents and Runner
Codex.Thread.run/3 delegates to a multi-turn runner that can be configured with reusable agents and per-run settings.
Codex.Agent
Represents a reusable agent definition with fields for instructions or prompt, optional handoffs, tools, guardrail lists, hooks, and optional model or model_settings overrides. New fields mirror the agent runner ADRs:
handoff_descriptionandhandoffs(lists of downstreamCodex.AgentorCodex.Handoff.wrap/2structs) describe delegation targetstool_use_behaviorcontrols when tool outputs end a run (:run_llm_againdefault,:stop_on_first_tool,%{stop_at_tool_names: [...]}, or a callback)reset_tool_choiceresets tool choice hints after a tool call (default: true)
Build via Codex.Agent.new/1 with maps, keyword lists, or an existing struct.
Codex.Handoff.wrap/2 turns an agent into a handoff tool with optional input filters and history nesting controls; Codex.AgentRunner.get_handoffs/2 filters enabled handoffs using the provided context. Guardrails can be created with Codex.Guardrail.new/1 and Codex.ToolGuardrail.new/1; when supplied on the agent/run config they run before turns, after final outputs, and around tool calls, raising Codex.GuardrailError on rejections/tripwires.
Codex.RunConfig
Per-run overrides built with Codex.RunConfig.new/1. Defaults: max_turns: 10, nest_handoff_history: true, auto_previous_response_id: false, optional model override, tracing metadata (workflow, group, trace_id, trace_include_sensitive_data, tracing_disabled), guardrail placeholders, and a call_model_input_filter hook slot (not yet wired). Validation ensures max_turns is a positive integer. The optional file_search field seeds hosted file search calls with vector_store_ids, filters, ranking_options, and include_search_results (run-level values override thread defaults). conversation_id and previous_response_id are recorded on thread metadata and used for future chaining; when auto_previous_response_id is enabled and a backend emits response_id, the runner updates previous_response_id automatically (currently nil on codex exec --json).
Codex.AgentRunner
Low-level entry point for multi-turn execution. Accepts a thread, input, and options that may include :agent, :run_config, :max_turns, and per-turn flags (e.g., output_schema). Codex.Thread.run/3 and Codex.Thread.run_streamed/3 are facades over this runner.
Example:
{:ok, thread} = Codex.start_thread()
{:ok, result} =
Codex.AgentRunner.run(thread, "Summarize docs",
run_config: %{max_turns: 5},
agent: %{instructions: "Be concise"}
)Codex.Thread
Manages individual conversation threads and turn execution. Threads maintain state across multiple turns.
Type: t()
@type t() :: %Codex.Thread{
thread_id: String.t() | nil,
codex_opts: Codex.Options.t(),
thread_opts: Codex.Thread.Options.t()
}Fields:
thread_id: Unique thread identifier (nil until first turn completes)codex_opts: Global Codex configurationthread_opts: Thread-specific configuration
Functions
run/3
Executes a multi-turn run and returns the complete result (blocking mode). Internally uses the agent runner and will follow continuation tokens until completion or max_turns is reached.
Signature:
@spec run(t(), String.t() | [map()], map() | keyword()) ::
{:ok, Codex.Turn.Result.t()} | {:error, term()}Parameters:
thread: Thread struct fromCodex.start_thread/2orCodex.resume_thread/3input: Prompt text or app-serverUserInputblocks (text/image/localImage)opts(optional): Per-turn options (e.g.,output_schema,env,attachments) plus runner settings (:agent,:run_config, or:max_turns)
Returns:
{:ok, result}: Complete turn result with items, response, and usage{:error, {:max_turns_exceeded, max_turns, context}}: Run exceeded the allowed turn count{:error, {:turn_failed, error}}: Agent encountered an error{:error, reason}: Other error (process, configuration, etc.)
Examples:
# Basic usage
{:ok, thread} = Codex.start_thread()
{:ok, result} = Codex.Thread.run(thread, "Explain GenServers")
IO.puts(result.final_response)
# => "GenServers are..."
# With structured output
schema = %{
"type" => "object",
"properties" => %{
"summary" => %{"type" => "string"},
"key_points" => %{
"type" => "array",
"items" => %{"type" => "string"}
}
}
}
turn_opts = %{output_schema: schema}
{:ok, result} = Codex.Thread.run(thread, "Summarize GenServers", turn_opts)
{:ok, data} = Jason.decode(result.final_response)
IO.inspect(data["key_points"])
# Continue conversation
{:ok, result2} = Codex.Thread.run(thread, "Give me an example")
# Override turn limit
{:ok, result} = Codex.Thread.run(thread, "Try multiple steps", %{max_turns: 5})Behavior:
- Blocks until the run completes or
max_turnsis hit (default: 10) - Accumulates events and usage across turns
- Invokes registered tools automatically when codex requests them
- Thread struct is updated with thread_id after first turn; subsequent calls reuse it for context
- App-server transport accepts
UserInputblock lists; exec JSONL requires text input
run_streamed/3
Executes a turn and returns a streaming result wrapper. Semantic events are exposed via
Codex.RunResultStreaming.events/1 and raw Codex events via raw_events/1.
Signature:
@spec run_streamed(t(), String.t() | [map()], map() | keyword()) ::
{:ok, Codex.RunResultStreaming.t()} | {:error, term()}Parameters:
thread: Thread structinput: Prompt text or app-serverUserInputblocksopts(optional): Turn-specific options plus optional runner settings (:agent,:run_config)
Returns:
{:ok, result}:Codex.RunResultStreamingwith semantic and raw event streams plus cancellation controls{:error, reason}: Configuration or process error
Examples:
# Basic streaming
{:ok, thread} = Codex.start_thread()
{:ok, result} = Codex.Thread.run_streamed(thread, "Analyze this codebase")
for event <- Codex.RunResultStreaming.raw_events(result) do
case event do
%Codex.Events.ItemStarted{item: item} ->
IO.puts("Started: #{item.type}")
%Codex.Events.ItemCompleted{item: %{type: :agent_message, text: text}} ->
IO.puts("Response: #{text}")
%Codex.Events.ItemCompleted{item: %{type: :command_execution} = cmd} ->
IO.puts("Command: #{cmd.command} (exit: #{cmd.exit_code})")
%Codex.Events.TurnCompleted{usage: usage} ->
IO.puts("Tokens: #{usage.input_tokens + usage.output_tokens}")
_ ->
:ok
end
end
# Process first N events
{:ok, stream_result} = Codex.Thread.run_streamed(thread, "Generate 100 files")
first_10 = stream_result |> Codex.RunResultStreaming.raw_events() |> Enum.take(10)
# Filter specific events
{:ok, stream_result} = Codex.Thread.run_streamed(thread, "Fix bugs")
commands =
stream_result
|> Codex.RunResultStreaming.raw_events()
|> Stream.filter(fn
%Codex.Events.ItemCompleted{item: %{type: :command_execution}} -> true
_ -> false
end)
|> Enum.to_list()Behavior:
- Returns immediately with stream
- Events yielded as they arrive from codex-rs
- Stream is lazy (events fetched on demand)
- Automatic cleanup when stream completes or is halted
- Thread struct must be updated with thread_id from
ThreadStartedevent
run_auto/3
Executes an auto-run loop, retrying turn execution while the Codex engine exposes a continuation token.
Signature:
@spec run_auto(t(), String.t(), keyword()) ::
{:ok, Codex.Turn.Result.t()} | {:error, term()}Parameters:
thread: Thread struct fromCodex.start_thread/2input: Prompt or instruction for the agentopts(keyword)::max_attempts(default:3) — maximum auto-run attempts:backoff(default: exponential backoff) — unary function invoked before each retry:turn_opts(default:%{}) — forwarded to eachrun/3attempt
Returns:
{:ok, result}: Completed turn with aggregated events, usage, andattemptscount{:error, {:max_attempts_reached, max, context}}: Continuation persisted after exhausting attempts{:error, reason}: Underlying execution failure
Examples:
{:ok, thread} = Codex.start_thread()
# Automatically resolve continuation tokens until completion
{:ok, result} = Codex.Thread.run_auto(thread, "Generate release notes")
result.attempts
# => 2
result.thread.usage
# => %{"input_tokens" => 42, "output_tokens" => 35, ...}
# Custom retry policy (no sleep) with explicit max attempts
opts = [max_attempts: 5, backoff: fn _ -> :ok end]
case Codex.Thread.run_auto(thread, "Execute plan", opts) do
{:ok, result} -> IO.inspect(result.final_response)
{:error, {:max_attempts_reached, _, %{continuation: token}}} ->
Logger.warn("manual follow-up required: #{token}")
endBehavior:
- Invokes
run/3sequentially while continuation tokens are present - Applies backoff between attempts; default uses exponential sleep
- Aggregates usage metrics and events across attempts
- Returns updated thread with continuation token cleared on success
Codex.Exec
GenServer that manages the codex-rs process lifecycle. This module is typically used internally by Codex.Thread, but can be used directly for advanced use cases.
Additional exec helpers:
Codex.Exec.review/2andCodex.Exec.review_stream/2runcodex exec reviewwith a review target (uncommitted, base branch, commit, or custom prompt).- Thread/turn options like
profile,oss,local_provider,full_auto,dangerously_bypass_approvals_and_sandbox,output_last_message, andcolorare forwarded as CLI flags. config_overridesmaps to-c key=valueoverrides (TOML parsing on the codex side), with runtime validation for TOML-compatible values.Codex.resume_thread(:last)maps tocodex exec resume --last.
Example:
{:ok, result} =
Codex.Exec.review({:base_branch, "main"}, %{
codex_opts: codex_opts,
timeout_ms: 300_000
})Codex.Sessions
Utilities for inspecting CLI session files and replaying Codex diffs locally.
list_sessions/1
Lists session entries from ~/.codex/sessions (or a custom :sessions_dir). Each entry includes
metadata for unrecognized fields so new upstream metadata is preserved.
{:ok, sessions} = Codex.Sessions.list_sessions()apply/2
Applies a unified diff string or a list of file change items using git apply.
{:ok, result} = Codex.Sessions.apply(diff, cwd: "/path/to/repo")Options:
:cwd— repository root (defaults to current directory):timeout_ms— command timeout (default: 60s):preflight/:dry_run— validate without applying changes
undo/2
Restores a ghost snapshot using a %Codex.Items.GhostSnapshot{} or raw ghost commit map:
{:ok, result} = Codex.Sessions.undo(ghost_snapshot, cwd: "/path/to/repo")The helper restores tracked files and removes untracked files created after the snapshot, while preserving preexisting untracked paths recorded in the snapshot metadata.
Codex.Tools
The tool registry supports a Python-style, decorator-inspired tooling API. Tools can be registered dynamically and invoked automatically during auto-run cycles when the agent requests an external capability.
register/2
Registers a tool module that implements Codex.Tool.
@spec register(module(), keyword()) :: {:ok, Codex.Tools.Handle.t()} | {:error, term()}:name— identifier used by Codex events (defaults to module metadata or underscored module name):description,:schema— optional metadata merged with tool-provided metadata
invoke/3
Invokes a registered tool with decoded arguments and contextual data.
@spec invoke(String.t(), map(), map()) :: {:ok, map()} | {:error, term()}Context includes the current thread struct, event metadata, and any custom entries stored under Thread.Options.metadata (mirroring Python's tool context).
deregister/1
Removes a registered tool.
metrics/0
Returns an in-memory snapshot of invocation counters per tool.
@spec metrics() :: %{optional(String.t()) => %{success: non_neg_integer(), failure: non_neg_integer(), last_latency_ms: non_neg_integer(), total_latency_ms: non_neg_integer(), last_error: term() | nil}}Useful for lightweight observability without relying on external telemetry backends.
reset_metrics/0
Clears all accumulated metrics.
@spec reset_metrics() :: :okClears accumulated metrics for fresh tracking.
Telemetry
Every invocation emits :telemetry events using the following namespaces:
[:codex, :tool, :start]— dispatched prior to executing a tool, with metadata including:tool,:call_id,:attempt, and:retry?[:codex, :tool, :success]— emitted on success with the same metadata plus the returned:output; measurements include:durationin native units[:codex, :tool, :failure]— emitted on failures with the same measurements and an:errorentry describing the failure
Codex.FunctionTool
Function-backed tools can be defined with use Codex.FunctionTool, which generates a JSON schema from the supplied parameter definitions and handles enablement/error hooks:
defmodule Math.Add do
use Codex.FunctionTool,
name: "add_numbers",
description: "Adds two numbers",
parameters: %{left: :number, right: :number},
enabled?: fn _ctx -> true end,
on_error: fn reason, _ctx -> {:ok, %{message: inspect(reason)}} end,
handler: fn %{"left" => left, "right" => right}, _ctx ->
{:ok, %{"sum" => left + right}}
end
endSchemas are strict by default ("additionalProperties": false) and can be overridden via the :schema option. :enabled? gates invocation, while :on_error can turn failures into usable outputs.
Codex.ToolOutput
Tools may return structured outputs using %Codex.ToolOutput.Text{}, %Codex.ToolOutput.Image{}, or %Codex.ToolOutput.FileContent{} (or the text/1, image/1, and file/1 helpers). Outputs are normalized to codex-friendly input items (input_text, input_image, input_file) by the runner before being forwarded back to the model. File payloads support file_id, file_url, inline data, filename, and mime_type; image payloads support url/file_id plus detail. Lists of outputs are flattened and deduplicated to avoid resending the same file/image inputs across continuations. Passing a %Codex.Files.Attachment{} automatically produces an input_file item with the staged file encoded as base64 alongside the attachment checksum id.
Hosted tools
Hosted capabilities mirror the Python SDK wrappers and are exposed as tool modules:
Codex.Tools.ShellTool— runs argv-style shell commands (command: ["bash", "-lc", "..."]), supportsworkdir,timeout_ms,max_output_bytes, and optional:approvalhooks (legacy string commands are still accepted)Codex.Tools.ShellCommandTool— runs string shell scripts (command: "ls -la"), supportslogin,workdir, andtimeout_msunder theshell_commandtool nameCodex.Tools.WriteStdinTool— writes to unified exec sessions (app-server transport only), requiressession_idCodex.Tools.ApplyPatchTool— applies*** Begin Patchedits viainputand preserves unified diff fallback viapatch(add/delete/update/move + dry-run)Codex.Tools.ViewImageTool— attaches local images asinput_imageoutputs, gated byfeatures.view_image_toolorThread.Options.view_image_tool_enabledCodex.Tools.ComputerTool— performs computer actions guarded by a:safetycallback and optional approval hook, delegated to an:executorCodex.Tools.FileSearchTool— searches local files by glob pattern and content, with case-insensitive and max results optionsCodex.Tools.VectorStoreSearchTool/Codex.Tools.WebSearchTool— dispatch search calls through a:searchercallback while carrying configured filters/vector store IDs (plus ranking options andinclude_search_resultspulled from thread/runfile_searchconfig);web_searchrequests are gated byfeatures.web_search_requestCodex.Tools.ImageGenerationTool/Codex.Tools.CodeInterpreterTool— call provided:generator/:runnercallbacks
Defaults for hosted file search can be set on Thread.Options.file_search or RunConfig.file_search; request arguments supplied by the model still win.
SDK-only extensions (not present in the upstream codex CLI): ComputerTool, VectorStoreSearchTool, ImageGenerationTool, and CodeInterpreterTool.
Register them like any other tool, passing callbacks in registration metadata:
{:ok, _} =
Codex.Tools.register(Codex.Tools.ShellTool,
executor: &MyShell.exec/3,
timeout_ms: 1_000
)Codex.Files
Staging and attachment helpers that keep file workflows deterministic.
stage/2— copies a source file into the staging directory, returning%Codex.Files.Attachment{}with checksum, size, and persistence metadata.attach/2— appends a staged attachment toCodex.Thread.Options, deduplicating by checksum.list_staged_result/0— explicit{:ok, [attachment]} | {:error, reason}listing API.list_staged/0/cleanup!/0/reset!/0— compatibility helpers to inspect and manage staged files.
Staged files are scoped to the current runtime; the registry clears the staging directory on startup, so re-stage attachments after restarts.
On the exec JSONL transport (codex exec --json), attachments are forwarded as images via repeated --image <path> flags. The upstream exec CLI does not currently support arbitrary non-image file attachments.
Returning a %Codex.Files.Attachment{} from a tool (or passing one to Codex.ToolOutput.normalize/1) yields an input_file payload with the checksum as file_id and the staged contents base64-encoded.
Realtime and Voice
The SDK provides full Realtime API and Voice Pipeline support ported from the OpenAI Agents Python SDK. These modules make direct API calls to OpenAI rather than wrapping the codex CLI.
Codex.Realtime
Main module with agent builder and convenience functions for bidirectional voice interactions via WebSocket.
agent/1— builds aCodex.Realtime.Agentstruct with instructions, tools, and handoffsstart_session/2— starts aCodex.Realtime.SessionWebSocket GenServersubscribe/2/unsubscribe/2— idempotent PubSub event subscriptionsend_audio/2/commit_audio/1— send PCM16 audio data and commit the buffersend_tool_result/3— return tool call results to the sessionadd_handoff/3— configure agent-to-agent handoffsstop_session/1— stop the session and close the WebSocket
Codex.Realtime.Session
WebSocket-based GenServer using WebSockex for real-time bidirectional streaming. Traps linked WebSocket exits and runs tool calls outside the callback path so the session stays responsive.
Codex.Realtime.Runner
High-level orchestrator for agent sessions with automatic tool call handling, handoff execution, and guardrail integration.
Codex.Realtime.Config
Configuration structs for session and model settings:
RunConfig— top-level session run configurationSessionModelSettings— model, voice, turn detection, temperatureTurnDetectionConfig— semantic VAD or server VAD with eagerness (:low,:medium,:high),silence_duration_ms, andprefix_padding_msInputAudioTranscription— transcription model and settings
Codex.Voice.Pipeline
Orchestrates STT -> Workflow -> TTS processing for single-turn and multi-turn voice flows. Uses Task-based async execution via ephemeral TaskSupervisor.
Codex.Voice.Workflow
Behaviour for custom processing logic. Implementations:
Codex.Voice.SimpleWorkflow— function-based workflows with optional greetingCodex.Voice.AgentWorkflow— workflows backed byCodex.Agentwith multi-turn conversation history
Codex.Voice.Model.*
Behaviours and implementations for speech models:
Codex.Voice.Model.STTModel— speech-to-text behaviour;OpenAISTTimplementation usinggpt-4o-transcribeCodex.Voice.Model.TTSModel— text-to-speech behaviour;OpenAITTSimplementation usinggpt-4o-mini-ttsCodex.Voice.Model.ModelProvider— model factory behaviour;OpenAIProviderimplementation
Voice types
Codex.Voice.Input.AudioInput— single audio buffer inputCodex.Voice.Input.StreamedAudioInput— streaming audio input withStreamQueuebackpressureCodex.Voice.Result— streamed audio outputCodex.Voice.Events— voice stream events (audio, lifecycle, error)Codex.Voice.Config— pipeline configuration with STT/TTS settings
Auth precedence for Realtime/Voice: CODEX_API_KEY → auth.json OPENAI_API_KEY → OPENAI_API_KEY.
See guides/06-realtime-and-voice.md for the complete guide.
Codex.Approvals.StaticPolicy
Provides a lightweight approval policy used to gate tool invocations or sandbox-sensitive operations.
allow/1— always approves (StaticPolicy.allow(reason: "optional")).deny/1— always denies with a custom reason.review_tool/3— invoked byCodex.Thread.run_auto/3to determine whether a requested tool may execute.
Codex.MCP.Client
JSON-RPC client for MCP-compatible servers (stdio or streamable HTTP).
initialize/2— sendsinitialize, records advertised capabilities, then emitsnotifications/initialized.handshake/2— backwards-compatible alias forinitialize/2.capabilities/1— returns the negotiated capability list used to seed the tool registry.list_tools/2— fetches tool metadata viatools/list, caches responses by default, and supportsallow/deny/filteroptions pluscache?: falseto bypass cached entries.list_resources/2— fetches resources viaresources/list.list_prompts/2— fetches prompts viaprompts/list.call_tool/4— invokes a tool viatools/callwithretries/backoffand optionalapprovalcallback.
MCP transports
Codex.MCP.Transport.Stdio— launches stdio MCP servers with the same default env whitelist as upstream Codex.Codex.MCP.Transport.StreamableHTTP— JSON-RPC over streamable HTTP with optional bearer/OAuth auth.
Codex.MCP.Config
Helpers for managing MCP server configuration via app-server config APIs.
list_servers/2— readsmcp_serversentries fromconfig/read.add_server/4— writesmcp_servers.<name>entries viaconfig/value/write.remove_server/3— clearsmcp_servers.<name>entries viaconfig/value/write.
Codex.Skills
Skill discovery and loading helpers gated by features.skills.
list/2— callsskills/listwhen enabled.load/2— loads skill file contents from thepathfield.
Codex.Prompts
Custom prompt discovery and expansion helpers for $CODEX_HOME/prompts.
list/1— discovers prompt files, parses frontmatter, and returns prompt metadata + content.expand/2— expands$1..$9,$ARGUMENTS, and$KEYplaceholders with positional orKEY=valueargs.
Hosted MCP tool
Codex.Tools.HostedMcpTool wraps an MCP client for use inside the tool registry. Register it with a :client and :tool plus optional :retries, :backoff, or :approval fields to mirror Python's hosted MCP wrapper.
Codex.Session
Behaviour for persisting conversation history between runs. The built-in Codex.Session.Memory adapter stores entries in an Agent for short-lived runs.
session/session_input_callback— configure onRunConfigto load history before a run and optionally transform the input. Callbacks receive the input and loaded history.conversation_id/previous_response_id— optional identifiers stored on thread metadata and persisted alongside session entries (optionally updated byauto_previous_response_idwhen the backend provides aresponse_id).
Codex.Telemetry
Helper module for emitting telemetry and wiring default logging.
emit/3— dispatches telemetry events (:telemetry.execute).attach_default_logger/1— logs thread start/stop/exception events with configurable log level.
Error Types
Codex.Error— normalized error struct for exec and turn failures (returned as{:exec_failed, %Codex.Error{}}or{:turn_failed, %Codex.Error{}}).Codex.TransportError— low-level exec errors fromCodex.Execstreams; includesexit_statusand optionalstderr.Codex.ApprovalError— returned when an approval policy denies a tool invocation, exposingtoolandreasonfields.
Functions
start_link/1
Starts an Exec GenServer and spawns the codex-rs process.
Signature:
@spec start_link(keyword()) :: GenServer.on_start()Options:
:input(required): Input prompt for the turn:codex_path(optional): Path to codex binary:thread_id(optional): Existing thread ID to resume:base_url(optional): OpenAI API base URL:api_key(optional): OpenAI API key:model(optional): Model name:sandbox_mode(optional): Sandbox mode (:read_only,:workspace_write,:danger_full_access):working_directory(optional): Working directory for agent:skip_git_repo_check(optional): Skip Git repository check:output_schema_file(optional): Path to JSON schema file
Returns:
{:ok, pid}: GenServer process ID{:error, reason}: Spawn or configuration error
Examples:
# Basic usage
{:ok, pid} = Codex.Exec.start_link(
input: "Hello, Codex",
codex_path: "/usr/local/bin/codex"
)
# With all options
{:ok, pid} = Codex.Exec.start_link(
input: "Analyze code",
codex_path: "/usr/local/bin/codex",
thread_id: "thread_abc123",
api_key: "sk-...",
model: "o1",
sandbox_mode: :read_only,
working_directory: "/path/to/project",
output_schema_file: "/tmp/schema.json"
)run_turn/2
Starts turn execution and returns a reference for event tracking.
Signature:
@spec run_turn(pid()) :: reference()Parameters:
pid: Exec GenServer process ID
Returns:
reference(): Unique reference for this turn
Usage:
{:ok, pid} = Codex.Exec.start_link(input: "example input")
ref = Codex.Exec.run_turn(pid)
# Receive events
receive do
{:event, ^ref, event} ->
IO.inspect(event)
{:done, ^ref} ->
IO.puts("Turn complete")
{:error, ^ref, error} ->
IO.puts("Error: #{inspect(error)}")
endCodex.Events
Event type definitions for all events emitted during turn execution.
Event Types
ThreadStarted
Emitted when a new thread is started.
Type:
@type t() :: %Codex.Events.ThreadStarted{
type: :thread_started,
thread_id: String.t()
}Fields:
type: Always:thread_startedthread_id: Unique identifier for the thread (format:"thread_*")
Example:
%Codex.Events.ThreadStarted{
type: :thread_started,
thread_id: "thread_abc123xyz"
}TurnStarted
Emitted when a turn begins processing.
Type:
@type t() :: %Codex.Events.TurnStarted{
type: :turn_started
}TurnCompleted
Emitted when a turn completes successfully.
Type:
@type t() :: %Codex.Events.TurnCompleted{
type: :turn_completed,
usage: Codex.Events.Usage.t()
}Fields:
type: Always:turn_completedusage: Token usage statistics
App-server turn/completed notifications also carry status and error; the SDK exposes them on
Codex.Events.TurnCompleted.
Usage Type:
@type usage() :: %Codex.Events.Usage{
input_tokens: non_neg_integer(),
cached_input_tokens: non_neg_integer(),
output_tokens: non_neg_integer()
}Example:
%Codex.Events.TurnCompleted{
type: :turn_completed,
usage: %Codex.Events.Usage{
input_tokens: 1500,
cached_input_tokens: 500,
output_tokens: 800
}
}TurnFailed
Emitted when a turn fails with an error.
Type:
@type t() :: %Codex.Events.TurnFailed{
type: :turn_failed,
error: Codex.Events.ThreadError.t()
}Error Type:
@type thread_error() :: %Codex.Events.ThreadError{
message: String.t()
}ThreadTokenUsageUpdated
Emitted when the app server publishes in-flight token usage totals.
Type:
@type t() :: %Codex.Events.ThreadTokenUsageUpdated{
thread_id: String.t() | nil,
turn_id: String.t() | nil,
usage: map(),
delta: map() | nil
}Fields:
thread_id: Explicit thread identifier provided by Codexturn_id: Turn identifier when availableusage: Cumulative token usage so fardelta: Optional incremental token counts
TurnDiffUpdated
Diff metadata streamed alongside turn progress.
Type:
@type t() :: %Codex.Events.TurnDiffUpdated{
thread_id: String.t() | nil,
turn_id: String.t() | nil,
diff: map() | String.t()
}TurnPlanUpdated
Plan metadata streamed from the app-server.
Type:
@type t() :: %Codex.Events.TurnPlanUpdated{
thread_id: String.t() | nil,
turn_id: String.t() | nil,
explanation: String.t() | nil,
plan: [%{step: String.t(), status: :pending | :in_progress | :completed}]
}TurnCompaction
Signals that Codex compacted a turn's history, often to trim token usage.
Type:
@type t() :: %Codex.Events.TurnCompaction{
thread_id: String.t() | nil,
turn_id: String.t() | nil,
compaction: map(),
stage: :started | :completed | :failed | :unknown | String.t()
}App-server delta events
The app-server transport emits additional typed deltas:
Codex.Events.CommandOutputDeltaandCodex.Events.FileChangeOutputDeltafor streaming tool outputCodex.Events.TerminalInteractionfor interactive stdin writesCodex.Events.ReasoningSummaryDelta,Codex.Events.ReasoningSummaryPartAdded, andCodex.Events.ReasoningDeltafor reasoning streamsCodex.Events.McpToolCallProgressfor MCP tool progress messagesCodex.Events.AccountUpdated,Codex.Events.AccountRateLimitsUpdated,Codex.Events.AccountLoginCompleted,Codex.Events.McpServerOauthLoginCompleted, andCodex.Events.WindowsWorldWritableWarningfor account/system updatesCodex.Events.RawResponseItemCompletedfor raw response items (ghost snapshots, compaction, etc.)Codex.Events.DeprecationNoticefor deprecation warnings
Error
General error notification emitted by Codex.
Type:
@type t() :: %Codex.Events.Error{
message: String.t(),
thread_id: String.t() | nil,
turn_id: String.t() | nil
}ItemStarted
Emitted when a new item is added to the thread.
Type:
@type t() :: %Codex.Events.ItemStarted{
type: :item_started,
item: Codex.Items.t(),
thread_id: String.t() | nil,
turn_id: String.t() | nil
}ItemUpdated
Emitted when an item's state changes.
Type:
@type t() :: %Codex.Events.ItemUpdated{
type: :item_updated,
item: Codex.Items.t(),
thread_id: String.t() | nil,
turn_id: String.t() | nil
}ItemCompleted
Emitted when an item reaches a terminal state.
Type:
@type t() :: %Codex.Events.ItemCompleted{
type: :item_completed,
item: Codex.Items.t(),
thread_id: String.t() | nil,
turn_id: String.t() | nil
}Codex.Items
Thread item type definitions representing different actions and artifacts.
Item Types
AgentMessage
Text or JSON response from the agent.
Type:
@type t() :: %Codex.Items.AgentMessage{
id: String.t(),
type: :agent_message,
text: String.t(),
parsed: map() | list() | nil
}Fields:
id: Unique item identifiertype: Always:agent_messagetext: Response text (natural language or JSON when using output schema)parsed: Decoded payload when an output schema is supplied (otherwisenil)
Example:
%Codex.Items.AgentMessage{
id: "msg_abc123",
type: :agent_message,
text: "GenServers are process abstractions in Elixir...",
parsed: nil
}Reasoning
Agent's reasoning summary.
Type:
@type t() :: %Codex.Items.Reasoning{
id: String.t(),
type: :reasoning,
text: String.t(),
summary: [String.t()],
content: [String.t()]
}summary captures structured reasoning summaries; content holds raw reasoning blocks when available.
Example:
%Codex.Items.Reasoning{
id: "reasoning_1",
type: :reasoning,
text: "To fix this issue, I need to first understand the error, then locate the relevant code...",
summary: ["Understand the error", "Locate the code"],
content: ["Raw reasoning chunk"]
}CommandExecution
Shell command executed by the agent.
Type:
@type t() :: %Codex.Items.CommandExecution{
id: String.t(),
type: :command_execution,
command: String.t(),
aggregated_output: String.t(),
exit_code: integer() | nil,
status: :in_progress | :completed | :failed | :declined
}Fields:
command: Command line that was executedaggregated_output: Combined stdout and stderrexit_code: Exit status (nil while running, integer when complete)status: Current status of execution
Example:
%Codex.Items.CommandExecution{
id: "cmd_1",
type: :command_execution,
command: "ls -la",
aggregated_output: "...\nREADME.md\nlib\n",
exit_code: 0,
status: :completed
}FileChange
File modifications made by the agent.
Type:
@type t() :: %Codex.Items.FileChange{
id: String.t(),
type: :file_change,
changes: [file_update_change()],
status: :in_progress | :completed | :failed | :declined
}Change Type:
@type file_update_change() :: %{
path: String.t(),
kind: :add | :delete | :update
}Example:
%Codex.Items.FileChange{
id: "patch_1",
type: :file_change,
changes: [
%{path: "lib/my_app.ex", kind: :update},
%{path: "lib/new_module.ex", kind: :add}
],
status: :completed
}McpToolCall
Model Context Protocol tool invocation.
Type:
@type t() :: %Codex.Items.McpToolCall{
id: String.t(),
type: :mcp_tool_call,
server: String.t(),
tool: String.t(),
arguments: map() | list() | nil,
result: map() | nil,
error: map() | nil,
status: :in_progress | :completed | :failed
}Example:
%Codex.Items.McpToolCall{
id: "mcp_1",
type: :mcp_tool_call,
server: "database_server",
tool: "query_records",
arguments: %{"query" => "SELECT * FROM users"},
result: %{"content" => [%{"type" => "text", "text" => "ok"}]},
status: :completed
}WebSearch
Web search query and results.
Type:
@type t() :: %Codex.Items.WebSearch{
id: String.t(),
type: :web_search,
query: String.t()
}TodoList
Agent's running task list.
Type:
@type t() :: %Codex.Items.TodoList{
id: String.t(),
type: :todo_list,
items: [todo_item()]
}Todo Item Type:
@type todo_item() :: %{
text: String.t(),
completed: boolean()
}Example:
%Codex.Items.TodoList{
id: "todo_1",
type: :todo_list,
items: [
%{text: "Analyze codebase", completed: true},
%{text: "Identify issues", completed: true},
%{text: "Propose fixes", completed: false}
]
}Error
Non-fatal error item.
Type:
@type t() :: %Codex.Items.Error{
id: String.t(),
type: :error,
message: String.t()
}Codex.Options
Configuration structs for different levels of the SDK.
Codex.Options
Global Codex configuration.
Type:
@type t() :: %Codex.Options{
codex_path_override: String.t() | nil,
base_url: String.t() | nil,
api_key: String.t() | nil,
telemetry_prefix: [atom()],
model: String.t() | nil,
reasoning_effort: Codex.Models.reasoning_effort() | nil,
model_personality: :friendly | :pragmatic | :none | nil,
model_reasoning_summary: String.t() | nil,
model_verbosity: String.t() | nil,
model_context_window: pos_integer() | nil,
model_supports_reasoning_summaries: boolean() | nil,
model_auto_compact_token_limit: pos_integer() | nil,
review_model: String.t() | nil,
history_persistence: String.t() | nil,
history_max_bytes: non_neg_integer() | nil,
hide_agent_reasoning: boolean(),
tool_output_token_limit: pos_integer() | nil,
agent_max_threads: pos_integer() | nil,
config_overrides: [
String.t()
| {String.t(), String.t() | boolean() | integer() | float() | list() | map()}
]
}Fields:
codex_path_override: Custom path to codex binary (defaults to system PATH)base_url: OpenAI API base URL (precedence: explicit option, thenOPENAI_BASE_URL, then official default)api_key: OpenAI API key (overridesCODEX_API_KEY; optional if CLI login is present)telemetry_prefix: Telemetry prefix for metrics/events (defaults to[:codex])model: Model override (defaults toCodex.Models.default_model/0)reasoning_effort: Reasoning effort override (:none,:minimal,:low,:medium,:high, or:xhigh; defaults toCodex.Models.default_reasoning_effort/1)model_personality: Personality preference (:friendly,:pragmatic, or:none)model_reasoning_summary: Reasoning summary setting (auto,concise,detailed,none)model_verbosity: Response verbosity (low,medium,high)model_context_window: Context window size override, in tokensmodel_supports_reasoning_summaries: Force-enable reasoning summaries for non-default modelsmodel_auto_compact_token_limit: Auto-compaction token thresholdreview_model: Model override for review mode runshistory_persistence: History persistence mode override (mirrorshistory.persistence)history_max_bytes: History size cap in bytes (mirrorshistory.max_bytes)hide_agent_reasoning: Hide reasoning summaries even when supportedtool_output_token_limit: Token cap for tool outputs (per turn)agent_max_threads: Limit for max concurrent agent threadsconfig_overrides/config: Global config override bag flattened into--configflags before derived/thread/turn overrides; use TOML-compatible values only (strings, booleans, numbers, arrays, nested maps)
Example:
%Codex.Options{
codex_path_override: "/custom/path/to/codex",
base_url: "https://api.openai.com",
api_key: System.get_env("CODEX_API_KEY"),
config_overrides: [{"model_reasoning_summary", "concise"}]
}Codex.Thread.Options
Thread-specific configuration.
Type:
@type t() :: %Codex.Thread.Options{
metadata: map(),
labels: map(),
auto_run: boolean(),
transport: :exec | {:app_server, pid()},
approval_policy: module() | nil,
approval_hook: module() | nil,
approval_timeout_ms: pos_integer(),
sandbox:
:default
| :strict
| :permissive
| :read_only
| :workspace_write
| :danger_full_access
| :external_sandbox
| {:external_sandbox, :enabled | :restricted}
| String.t(),
sandbox_policy: map() | atom() | nil,
working_directory: String.t() | nil,
additional_directories: [String.t()],
skip_git_repo_check: boolean(),
network_access_enabled: boolean() | nil,
web_search_enabled: boolean(),
web_search_mode: :disabled | :cached | :live,
personality: :friendly | :pragmatic | :none | nil,
collaboration_mode: Codex.Protocol.CollaborationMode.t() | nil,
compact_prompt: String.t() | nil,
show_raw_agent_reasoning: boolean(),
output_schema: map() | nil,
apply_patch_freeform_enabled: boolean() | nil,
view_image_tool_enabled: boolean() | nil,
unified_exec_enabled: boolean() | nil,
skills_enabled: boolean() | nil,
ask_for_approval: atom() | String.t() | nil,
attachments: [map()],
file_search: Codex.FileSearch.t() | nil,
profile: String.t() | nil,
oss: boolean(),
local_provider: String.t() | nil,
full_auto: boolean(),
dangerously_bypass_approvals_and_sandbox: boolean(),
output_last_message: String.t() | nil,
color: :auto | :always | :never | String.t() | nil,
config_overrides: [
String.t()
| {String.t() | atom(), String.t() | boolean() | integer() | float() | list() | map()}
],
history_persistence: String.t() | nil,
history_max_bytes: non_neg_integer() | nil,
model: String.t() | nil,
model_provider: String.t() | nil,
model_reasoning_summary: String.t() | nil,
model_verbosity: String.t() | nil,
model_context_window: pos_integer() | nil,
model_supports_reasoning_summaries: boolean() | nil,
request_max_retries: pos_integer() | nil,
stream_max_retries: pos_integer() | nil,
stream_idle_timeout_ms: pos_integer() | nil,
config: map() | nil,
base_instructions: String.t() | nil,
developer_instructions: String.t() | nil,
shell_environment_policy: map() | nil,
retry: boolean() | nil,
retry_opts: keyword() | nil,
rate_limit: boolean() | nil,
rate_limit_opts: keyword() | nil,
experimental_raw_events: boolean()
}Fields:
metadata: Arbitrary per-thread metadata stored on the thread and passed to tool contexts (commonly includes:tool_contextor approval hints)labels: Optional label map merged with server metadataauto_run: Enable CLI-driven auto-run (default: false)transport::execor{:app_server, pid()}for JSON-RPC transportapproval_policy/approval_hook/approval_timeout_ms: Approval gating for tool callssandbox: Exec CLI sandbox mode (e.g.:strict,:workspace_write,:external_sandbox)sandbox_policy: App-server sandbox policy override (type,writable_roots,network_access)working_directory: Working directory passed to codex (--cd/cwd)additional_directories: Extra writable roots (--add-dir)skip_git_repo_check: Allow running outside a Git reponetwork_access_enabled: Workspace-write network access override for exec (--config sandbox_workspace_write.network_access=...)web_search_enabled: Legacy web search toggle (deprecated; useweb_search_mode); explicitfalseemitsweb_search="disabled"web_search_mode: Web search mode override (:disabled,:cached,:live); explicit:disabledemitsweb_search="disabled"while untouched defaults emit nothingpersonality: Thread-level personality override (:friendly,:pragmatic,:none), serialized consistently across exec and app-server transportscollaboration_mode: Collaboration mode preset for app-server turns (:plan,:pair_programming,:execute, or:custom)compact_prompt: Override prompt used for context compactionshow_raw_agent_reasoning: Emit raw reasoning content in reasoning itemsoutput_schema: Default JSON schema for structured outputs (turn options override)apply_patch_freeform_enabled: Enable the freeform apply_patch tool (features.apply_patch_freeform)view_image_tool_enabled: Enable the view_image tool (features.view_image_tool)unified_exec_enabled: Enable unified exec tool (features.unified_exec)skills_enabled: Enable skills discovery/injection (features.skills)ask_for_approval: Approval policy hint for app-server turnsattachments: List of%Codex.Files.Attachment{}forwarded to the codex binaryfile_search: Default file search config (vector_store_ids,filters,ranking_options,include_search_results) merged with per-run overridesprofile: Config profile name (--profile)oss/local_provider: OSS provider flags (--oss,--local-provider)full_auto/dangerously_bypass_approvals_and_sandbox: Execution-mode shortcuts (mutually exclusive)output_last_message: File path for--output-last-messagecolor: Output color mode (--color)config_overrides: Generic-c key=valueoverrides (strings,{key, value}pairs, or nested maps that are auto-flattened to dotted paths)config_overridesvalue validation: only TOML-compatible values are accepted (niland unsupported terms error early)history_persistence/history_max_bytes: History persistence configuration forwarded via config overridesmodel/model_provider: App-server thread model overridesmodel_reasoning_summary/model_verbosity: Reasoning summary + verbosity settings forwarded via config overridesmodel_context_window: Context window override (tokens)model_supports_reasoning_summaries: Force reasoning summary support for non-default modelsrequest_max_retries/stream_max_retries/stream_idle_timeout_ms: Per-provider network tuning overrides (config)config: App-server config override mapbase_instructions/developer_instructions: App-server instruction overridesshell_environment_policy: CLI shell env policy overrides (shell_environment_policy.*)retry/retry_opts: Enable transport retries (usesCodex.Retry)rate_limit/rate_limit_opts: Enable rate-limit handling (usesCodex.RateLimit)experimental_raw_events: App-server raw response item toggle
Example:
%Codex.Thread.Options{
metadata: %{tool_context: %{project: "docs"}},
attachments: [%Codex.Files.Attachment{...}],
file_search: %{vector_store_ids: ["vs_default"], include_search_results: true},
config_overrides: ["features.web_search_request=true"]
}Turn options
Turn-specific configuration passed as a map or keyword list.
Type:
@type t() :: %{
optional(:output_schema) => map() | nil,
optional(:config_overrides) => map() | keyword() | [String.t()] | nil,
optional(:sandbox_policy) => map() | atom() | nil,
optional(:model) => String.t() | nil,
optional(:approval_policy) => atom() | String.t() | nil,
optional(:cwd) => String.t() | nil,
optional(:effort) => atom() | String.t() | nil,
optional(:summary) => atom() | String.t() | nil,
optional(:env) => map() | keyword() | nil,
optional(:clear_env?) => boolean() | nil,
optional(:cancellation_token) => String.t() | nil,
optional(:timeout_ms) => pos_integer() | nil,
optional(:stream_idle_timeout_ms) => pos_integer() | nil,
optional(:retry) => boolean() | nil,
optional(:retry_opts) => keyword() | map() | nil,
optional(:rate_limit) => boolean() | nil,
optional(:rate_limit_opts) => keyword() | map() | nil
}Fields:
output_schema: JSON schema for structured output (nil for natural language)config_overrides: Exec-c key=valueoverrides (strings or key/value pairs)config_overridesvalue validation: only TOML-compatible values are accepted (niland unsupported terms error early)sandbox_policy: App-server sandbox policy overridemodel/approval_policy/cwd: App-server per-turn overrideseffort/summary: App-server reasoning overridesenv/clear_env?: Exec env overrides and optional env clearing; SDK setsCODEX_INTERNAL_ORIGINATOR_OVERRIDE=codex_sdk_elixirunless overridden inenvcancellation_token: Exec cancellation tokentimeout_ms: Exec overall timeout (blocking)stream_idle_timeout_ms: Exec stream idle timeoutretry/retry_opts: Opt-in retry handling for transportsrate_limit/rate_limit_opts: Opt-in rate limit handling for transports
Example:
turn_opts = %{
output_schema: %{
"type" => "object",
"properties" => %{
"summary" => %{"type" => "string"},
"status" => %{"type" => "string", "enum" => ["ok", "error"]}
},
"required" => ["summary", "status"]
}
}Codex.OutputSchemaFile
Utility for managing JSON schema temporary files.
Functions
create/1
Creates a temporary file with the JSON schema.
Signature:
@spec create(map() | nil) :: {:ok, {String.t() | nil, function()}} | {:error, term()}Parameters:
schema: JSON schema map or nil
Returns:
{:ok, {path, cleanup}}: Path to temp file and cleanup function{:error, reason}: Error creating file
Examples:
# With schema
schema = %{"type" => "object", "properties" => %{}}
{:ok, {path, cleanup}} = Codex.OutputSchemaFile.create(schema)
# Use path...
# Clean up
cleanup.()
# Without schema
{:ok, {nil, cleanup}} = Codex.OutputSchemaFile.create(nil)
cleanup.() # No-opNotes:
- Creates temp directory in system tmp folder
- Writes JSON to
schema.jsonin that directory - Cleanup function removes entire directory
- Cleanup is idempotent (safe to call multiple times)
- Used internally by
Codex.Thread
Type Aliases
Codex.Turn.Result
Result of a completed turn (from run/3).
Type:
@type t() :: %Codex.Turn.Result{
thread: Codex.Thread.t(),
events: [Codex.Events.t()],
final_response: Codex.Items.AgentMessage.t() | map() | nil,
usage: map() | nil,
raw: map(),
attempts: non_neg_integer(),
last_response_id: String.t() | nil
}Fields:
thread: Updated thread struct containing continuation & metadataevents: Events emitted during the turnfinal_response: Last agent message (typed struct with optionalparsedpayload)usage: Token usage statistics (nil if turn failed before completion)raw: Underlying exec metadata (events, CLI flags, etc.)attempts: Number of attempts performed (useful for auto-run)last_response_id: Last backend response identifier when surfaced (currentlyniloncodex exec --json)
Helpers:
Codex.Turn.Result.json/1— returns{:ok, map()}when structured output was decoded, or an error tuple ({:error, :not_structured}/{:error, {:invalid_json, reason}}).
Common Patterns
Error Handling
case Codex.Thread.run(thread, input) do
{:ok, result} ->
process_result(result)
{:error, {:turn_failed, error}} ->
Logger.error("Turn failed: #{error.message}")
{:error, :turn_failed}
{:error, {:process, reason}} ->
Logger.error("Process error: #{inspect(reason)}")
{:error, :process_error}
{:error, reason} ->
Logger.error("Unknown error: #{inspect(reason)}")
{:error, :unknown}
endStreaming with Pattern Matching
{:ok, stream} = Codex.Thread.run_streamed(thread, input)
Enum.reduce(stream, %{commands: [], files: []}, fn
%ItemCompleted{item: %{type: :command_execution} = cmd}, acc ->
%{acc | commands: [cmd | acc.commands]}
%ItemCompleted{item: %{type: :file_change} = file}, acc ->
%{acc | files: [file | acc.files]}
_, acc ->
acc
end)Structured Output with Validation
schema = %{
"type" => "object",
"properties" => %{
"status" => %{"type" => "string", "enum" => ["success", "failure"]},
"data" => %{"type" => "object"}
},
"required" => ["status"]
}
turn_opts = %{output_schema: schema}
{:ok, result} = Codex.Thread.run(thread, "Check system status", turn_opts)
case Jason.decode(result.final_response) do
{:ok, %{"status" => "success", "data" => data}} ->
process_data(data)
{:ok, %{"status" => "failure"}} ->
handle_failure()
{:error, _} ->
{:error, :invalid_json}
endMigration from TypeScript SDK
For developers familiar with the TypeScript SDK:
| TypeScript | Elixir |
|---|---|
new Codex() | Codex module (no instance needed) |
codex.startThread() | Codex.start_thread() |
codex.resumeThread(id) | Codex.resume_thread(id) |
await thread.run(input) | Codex.Thread.run(thread, input) |
await thread.runStreamed(input) | Codex.Thread.run_streamed(thread, input) |
for await (const event of events) | Enum.each(stream, fn event -> ... end) |
CodexOptions | %Codex.Options{} |
ThreadOptions | %Codex.Thread.Options{} |
TurnOptions | map/keyword (e.g., %{output_schema: schema}) |