Sign in

    codex

    Codex SDK, with some useful tools for building AI applications.

    AI
    Download zip
    Version
    0.47.1
    License
    Apache-2.0
    Last updated
    10 months ago
    Downloads
    7K

    #MoonBit Codex SDK

    This is the Codex SDK for MoonBit, ported from the TypeScript SDK.

    The SDK communicates with Codex by spawning it in non-interactive mode using codex exec. The target Codex version is 0.46.0.

    Codex must be installed and available on your PATH. If not, install with:

    pnpm install -g @openai/codex@0.46.0

    #Usage

    The simplest way to use Codex is to create a @codex.Codex and start a @codex.Thread. Then create a @codex.Turn from the thread using @codex.Thread::run. By default, the OPENAI_API_KEY environment variable is read.

    If you are already paid ChatGPT users, you can run the code below directly

    #skip
    async test {
    let codex = @codex.Codex::new()
    let thread = codex.start_thread()
    let turn = thread.run("Hello, what model are you using?")
    // I’m `GPT-5.2`, running inside the Codex CLI harness in your repo (`/Users/../codex-sdk`).
    println(turn.final_response)
    println(turn.items.to_json().stringify())
    println(turn.usage.to_json().stringify())
    }
    ///|
    #skip
    async test {
    let codex = @codex.Codex::new(
    options=@codex.CodexOptions::new(base_url="https://openrouter.ai/api/v1"),
    )
    let thread = codex.start_thread(
    options=@codex.ThreadOptions::new(model="anthropic/claude-sonnet-4.5"),
    )
    let turn = thread.run("Hello?")
    println(turn.final_response)
    println(turn.items.to_json().stringify())
    println(turn.usage.to_json().stringify())
    }

    For incremental usage, import the @generator package and use @codex.Thread::run_streamed.

    ///|
    #skip
    async test {
    let codex = @codex.Codex::new(
    options=@codex.CodexOptions::new(base_url="https://openrouter.ai/api/v1"),
    )
    let thread = codex.start_thread(
    options=@codex.ThreadOptions::new(model="anthropic/claude-sonnet-4.5"),
    )
    try {
    let streamed_turn = thread.run_streamed("Hello?")
    while streamed_turn.events.next() is Some(event) {
    println(event.to_json().stringify())
    }
    } catch {
    e => println(e)
    }
    }

    #Architecture Overview

    #Process boundary and transport

    The MoonBit SDK is a thin but strongly typed wrapper around codex exec:

    1. @codex.CodexExec::run spawns the CLI with --experimental-json, automatically wiring API endpoint overrides, API keys, sandbox flags, working directory overrides, and thread resumption arguments.
    2. The CLI's JSONL stream is fed through @generator.AsyncGenerator so the SDK can yield events as soon as they arrive. This keeps Codex long-running commands responsive while avoiding blocking MoonBit's async runtime.
    3. Each line is decoded into the rich @codex.Event / @codex.ThreadItem hierarchy (events.mbt and items.mbt), which means MoonBit callers never manipulate raw JSON.

    The Codex/Thread/Turn trio mirrors the CLI lifecycle: a Codex holds process-level configuration, a Thread models a Codex conversation, and a Turn captures the completed response plus token usage metrics.

    #Thread lifecycle and safety

    • Thread::run_streamed owns the async generator returned by CodexExec::run. The method updates the cached thread id when ThreadStarted surfaces, so a later Thread::run call automatically resumes the same conversation.
    • Thread::run is implemented on top of the streaming primitive. It drains the generator, records AgentMessageItem content as the Turn.final_response, retains the full item history for post-processing (e.g., capturing diffs or tool invocations), and surfaces TurnFailed by raising an error after draining the iterator to prevent resource leaks.
    • Structured cleanup exists everywhere a temporary artifact is created; for example, @codex::create_output_schema_file creates /tmp/codex-output-schema-* directories and ensures they are removed even when errors occur.

    #Events, items, and observability

    The CLI emits high-level telemetry that is mirrored by the SDK:

    • Event::ThreadStarted, TurnStarted, TurnCompleted, and TurnFailed make it trivial to instrument throughput, retries, and token usage.
    • ThreadItem variants capture everything the agent does: CommandExecutionItem surfaces shell commands with exit codes, FileChangeItem contains per-file diffs, McpToolCallItem shows MCP tool usage, and TodoListItem exposes the agent's internal plan.
    • All enums (sandbox mode, approval mode, command status, etc.) expose ToJson/FromJson so you can persist structured logs or forward them to observability backends without lossy string manipulation.

    #Structured output and schema enforcement

    TurnOptions.output_schema accepts an arbitrary JSON schema. When provided, Thread::run / run_streamed transparently:

    1. Creates a temporary schema file on disk.
    2. Passes --output-schema /tmp/.../schema.json to the CLI.
    3. Deletes the schema file after the turn completes or fails (even if exceptions arise).

    This makes it safe to require JSON output without managing files yourself. The final assistant message still flows through ThreadItem::AgentMessageItem, so you can parse it with @json.parse once the turn completes.

    #Configuration layers

    • CodexOptions sets global API concerns (binary override, base URL, API key) once per process.
    • ThreadOptions controls per-thread concerns such as the model, sandbox levels (read-only, workspace-write, danger-full-access), working directory routing, and Git safety checks.
    • TurnOptions tunes per-turn behavior, currently focusing on structured output but intentionally keeping room for future features (e.g., custom completion criteria). Because configuration objects implement ToJson/FromJson, they can be marshalled into other systems (task schedulers, Codex automation) without reimplementing serialization.

    #Advanced Usage Patterns

    #Instrument streaming events

    You can subscribe to the event stream for telemetry, custom retry logic, or UI overlays without waiting for a completed turn:

    ///|
    #skip
    async test {
    let codex = @codex.Codex::new()
    let thread = codex.start_thread()
    let turn = thread.run_streamed("Summarize today's commits")
    while turn.events.next() is Some(event) {
    match event {
    ItemStarted(item) => println("started: \{item.to_json().stringify()}")
    ItemCompleted(AgentMessageItem( text~,..)) => println("assistant: \{text}")
    TurnCompleted(usage) =>
    println("tokens in/out: \{usage.input_tokens}/\{usage.output_tokens}")
    TurnFailed(error) => fail("codex turn failed: \{error.message}")
    _ => ()
    }
    }
    }

    #Enforce structured responses

    The temporary-schema mechanism lets you demand JSON (or any schema-valid structure) without extra boilerplate:

    ///|
    #skip
    async test {
    let codex = @codex.Codex::new()
    let thread = codex.start_thread()
    let turn = thread.run(
    "Plan the next refactor as JSON",
    turn_options=@codex.TurnOptions::new(output_schema={
    "type": "object",
    "properties": {
    "summary": { "type": "string" },
    "files_to_touch": { "type": "array", "items": { "type": "string" } },
    },
    "required": ["summary", "files_to_touch"],
    "additionalProperties": false, // required to be supplied as valid schema
    }),
    )
    println(turn.final_response)
    let plan_json = @json.parse(turn.final_response)
    println(plan_json.stringify(indent=2))
    }

    These primitives compose cleanly with your own orchestration layers, since everything in the SDK is expressed as plain MoonBit structs and async functions.

    Input

    type Input = String

    An input to send to the agent.

    ApprovalMode

    pub(all) enum ApprovalMode {
    Never
    OnRequest
    OnFailure
    Untrusted
    }

    Approval mode for actions that require user consent.

    Codex

    type Codex

    Codex is the main class for interacting with the Codex agent.

    Use the start_thread() method to start a new thread or resume_thread() to resume a previously started thread.

    Codex::new

    fn Codex::new(options? : CodexOptions) -> Codex

    Create a new Codex instance.

    Arguments

    • options - Optional configuration for the Codex client

    Returns

    A new Codex instance

    Codex::resume_thread

    fn Codex::resume_thread(self : Codex, id : String, options? : ThreadOptions) -> Thread

    Resumes a conversation with an agent based on the thread id. Threads are persisted in ~/.codex/sessions.

    Arguments

    • id - The id of the thread to resume
    • options - Optional configuration for the thread

    Returns

    A new thread instance

    Codex::start_thread

    fn Codex::start_thread(self : Codex, options? : ThreadOptions) -> Thread

    Starts a new conversation with an agent.

    Arguments

    • options - Optional configuration for the thread

    Returns

    A new thread instance

    CodexExecArgs

    type CodexExecArgs

    Arguments for executing a Codex command.

    CodexExecArgs::new

    fn CodexExecArgs::new(input : String, base_url? : String, api_key? : String, thread_id? : String, model? : String, sandbox_mode? : SandboxMode, working_directory? : String, skip_git_repo_check? : Bool, output_schema_file? : String) -> CodexExecArgs

    CodexOptions

    type CodexOptions

    Options for configuring the Codex client.

    CodexOptions::new

    fn CodexOptions::new(codex_path_override? : String, base_url? : String, api_key? : String) -> CodexOptions

    CommandExecutionStatus

    pub enum CommandExecutionStatus {
    InProgress
    Completed
    Failed
    }

    Event

    pub enum Event {
    ThreadStarted(String)
    TurnStarted
    TurnCompleted(Usage)
    TurnFailed(ThreadError)
    ItemStarted(ThreadItem)
    ItemUpdated(ThreadItem)
    ItemCompleted(ThreadItem)
    ThreadErrorEvent(String)
    }

    FileUpdateChange

    pub struct FileUpdateChange {
    path : String
    kind : PatchChangeKind
    }

    A set of file changes by the agent.

    McpToolCallStatus

    pub enum McpToolCallStatus {
    InProgress
    Completed
    Failed
    }

    The status of an MCP tool call.

    PatchApplyStatus

    pub enum PatchApplyStatus {
    Completed
    Failed
    }

    The status of a file change.

    PatchChangeKind

    pub enum PatchChangeKind {
    Add
    Delete
    Update
    }

    Indicates the type of the file change.

    SandboxMode

    pub(all) enum SandboxMode {
    ReadOnly
    WorkspaceWrite
    DangerFullAccess
    }

    Sandbox mode that controls the level of access the agent has.

    StreamedTurn

    #alias(RunStreamedResult)
    pub struct StreamedTurn {
    events :
    AsyncGenerator
    [Event]
    }

    The result of the run_streamed method.

    Thread

    type Thread

    Represent a thread of conversation with the agent. One thread can have multiple consecutive turns.

    Thread::id

    fn Thread::id(self : Thread) -> String?

    Returns the ID of the thread. Populated after the first turn starts.

    Thread::run

    async fn Thread::run(self : Thread, input : String, turn_options? : TurnOptions) -> Turn

    Provides the input to the agent and returns the completed turn.

    Arguments

    • input - The user input/prompt to send to the agent
    • turn_options - Options for configuring this turn

    Returns

    A Turn containing all items, the final response, and usage information

    Thread::run_streamed

    async fn Thread::run_streamed(self : Thread, input : String, turn_options? : TurnOptions) -> StreamedTurn

    Provides the input to the agent and streams events as they are produced during the turn.

    Arguments

    • input - The user input/prompt to send to the agent
    • turn_options - Options for configuring this turn

    Returns

    A StreamedTurn containing an async iterator of events

    ThreadError

    pub struct ThreadError {
    message : String
    }

    ThreadItem

    pub enum ThreadItem {
    AgentMessageItem(String, String)
    ReasoningItem(String, String)
    CommandExecutionItem(String, String, String, Int?, CommandExecutionStatus)
    FileChangeItem(String, Array[FileUpdateChange], PatchApplyStatus)
    McpToolCallItem(String, String, String, McpToolCallStatus)
    WebSearchItem(String, String)
    TodoListItem(String, Array[TodoItem])
    ErrorItem(String, String)
    }

    ThreadOptions

    type ThreadOptions

    Options for configuring a thread.

    ThreadOptions::new

    fn ThreadOptions::new(model? : String, sandbox_mode? : SandboxMode, working_directory? : String, skip_git_repo_check? : Bool) -> ThreadOptions

    TodoItem

    pub struct TodoItem {
    text : String
    completed : Bool
    }

    An item in the agent's to-do list.
    impl Show for TodoItem
    impl ToJson for TodoItem

    Turn

    #alias(RunResult)
    pub struct Turn {
    items : Array[ThreadItem]
    final_response : String
    usage : Usage?
    }

    Completed turn.

    TurnOptions

    type TurnOptions

    Options for configuring a turn.

    TurnOptions::new

    fn TurnOptions::new(output_schema? : Json) -> TurnOptions

    Usage

    pub struct Usage {
    input_tokens : Int
    cached_input_tokens : Int
    output_tokens : Int
    }

    Describes the usage of tokens during a turn.
    impl ToJson for Usage