codex-client-sdk 0.107.0

Rust SDK for embedding the Codex agent via CLI-over-JSONL transport
Documentation

Codex Rust SDK

English | 中文

Rust SDK for embedding the Codex agent in applications by driving the codex CLI over JSONL (codex exec --experimental-json).

Table of Contents

Overview

This crate is a parity-focused Rust implementation aligned with the official Codex TypeScript SDK semantics.

It supports:

  • Thread-based multi-turn workflows (start_thread, resume_thread)
  • Buffered and streamed turn execution (run, run_streamed)
  • Structured output via JSON Schema (--output-schema)
  • Multimodal input (text + local images)
  • Cancellation and thread resume
  • CLI config/env forwarding (--config, API endpoint/key, sandbox/approval/web-search settings)

Status

  • Package version: 0.107.0 (codex-client-sdk)
  • Scope: parity-focused SDK implementation for core Codex workflows
  • Validation: crate tests pass (cargo test -p codex-client-sdk)
  • Rust docs: public API is documented and checked with missing_docs

Installation

This repository currently uses a workspace/local package layout.

[dependencies]
codex = { package = "codex-client-sdk", path = "../../crates/codex" }

Runtime prerequisites:

  • Rust 1.85+ (edition 2024)
  • Codex CLI installed and available (codex), typically from @openai/codex

Authentication and Environment Setup

The SDK invokes the external Codex CLI process. Authentication/config can be supplied either by environment variables or by CodexOptions.

Option A: environment variables

export CODEX_API_KEY="<your_api_key>"
# Optional: override endpoint
export OPENAI_BASE_URL="https://api.openai.com/v1"

Option B: programmatic overrides

use codex::{Codex, CodexOptions};

# fn example() -> codex::Result<()> {
let codex = Codex::new(Some(CodexOptions {
    api_key: Some("<your_api_key>".to_string()),
    base_url: Some("https://api.openai.com/v1".to_string()),
    ..Default::default()
}))?;
# let _ = codex;
# Ok(())
# }

Security note: do not hard-code or commit secrets to source control.

Quickstart

use codex::Codex;

# async fn example() -> codex::Result<()> {
let codex = Codex::new(None)?;
let thread = codex.start_thread(None);

let turn = thread
    .run("Diagnose the test failure and propose a fix", None)
    .await?;

println!("final response: {}", turn.final_response);
println!("items: {}", turn.items.len());
# Ok(())
# }

Continue the same conversation

# use codex::Codex;
# async fn example() -> codex::Result<()> {
# let codex = Codex::new(None)?;
# let thread = codex.start_thread(None);
let _first = thread.run("Diagnose failure", None).await?;
let second = thread.run("Implement the fix", None).await?;
println!("{}", second.final_response);
# Ok(())
# }

Stream events during a turn

use codex::{Codex, ThreadEvent};
use futures::StreamExt;

# async fn example() -> codex::Result<()> {
let codex = Codex::new(None)?;
let thread = codex.start_thread(None);
let streamed = thread.run_streamed("Diagnose the failure", None).await?;

let mut events = streamed.events;
while let Some(event) = events.next().await {
    match event? {
        ThreadEvent::ItemCompleted { item } => println!("item: {:?}", item),
        ThreadEvent::TurnCompleted { usage } => println!("usage: {:?}", usage),
        _ => {}
    }
}
# Ok(())
# }

Structured output

use codex::{Codex, TurnOptions};
use serde_json::json;

# async fn example() -> codex::Result<()> {
let codex = Codex::new(None)?;
let thread = codex.start_thread(None);

let schema = json!({
    "type": "object",
    "properties": {
        "summary": { "type": "string" },
        "status": { "type": "string", "enum": ["ok", "action_required"] }
    },
    "required": ["summary", "status"],
    "additionalProperties": false
});

let turn = thread
    .run(
        "Summarize repository status",
        Some(TurnOptions {
            output_schema: Some(schema),
            ..Default::default()
        }),
    )
    .await?;

println!("{}", turn.final_response);
# Ok(())
# }

API Selection Guide

Use case Recommended API Why
Need only final answer/items Thread::run Simple call, returns Turn directly
Need progress events/tool/file updates Thread::run_streamed Streamed typed events (ThreadEvent)
Continue prior thread by ID Codex::resume_thread + run/run_streamed Restores conversation context
Need text + images in one turn Input::Entries(Vec<UserInput>) Matches CLI --image flow

Core API Surface

  • Codex
    • new
    • start_thread
    • resume_thread
  • Thread
    • id
    • run
    • run_streamed
  • Input types
    • Input (Text, Entries)
    • UserInput (Text, LocalImage)
  • Options
    • CodexOptions
    • ThreadOptions
    • TurnOptions
  • Event/item models
    • ThreadEvent + typed event payloads
    • ThreadItem + typed item payloads
  • Low-level execution
    • CodexExec
    • CodexExecArgs

Feature Highlights

  • Robust CLI binary discovery (PATH, local node_modules, vendor, common globals)
  • Typed event/item deserialization from JSONL stream
  • Output schema temp-file lifecycle managed automatically
  • Config object flattening to repeated TOML-compatible --config flags
  • Explicit precedence behavior for overlapping options (for example web_search_mode over web_search_enabled)

Feature Comparison with Official TypeScript SDK

Feature Official TypeScript SDK This Rust SDK Notes
Start/resume threads startThread / resumeThread vs start_thread / resume_thread
Buffered turn API ✅ (run) ✅ (run) Equivalent high-level behavior
Streamed turn API ✅ (runStreamed) ✅ (run_streamed) Rust returns futures::Stream
Structured output schema Rust accepts serde_json::Value schema
Multimodal input (text + local images) Input::Entries + UserInput::LocalImage
Cancellation ✅ (AbortSignal) ✅ (CancellationToken) Rust-idiomatic token
CLI env override CodexOptions.env
Config flattening to --config flags TOML-compatible serialization
All event types (thread/turn/item) Full alignment with exec_events.rs
All item types (message/reasoning/etc) Full alignment with CLI output
Schema helper integration ✅ (Zod ecosystem) ✅ (via serde_json::Value) Rust users pass JSON Schema directly; consider schemars crate for derive-based schemas
Core SDK workflow Full parity for all core use cases

Note: This Rust SDK achieves full core parity with the official TypeScript SDK. The only ecosystem differences are:

  • TypeScript has Zod integration (zodToJsonSchema) while Rust users pass JSON Schema directly via serde_json::Value
  • For Rust schema generation, consider using the schemars crate for derive-based JSON Schema generation

Compatibility Matrix

Component Requirement / Notes
Rust 1.85+
Edition 2024
Codex CLI Required; install codex (typically via @openai/codex)
Runtime Tokio async runtime
OS support Linux/macOS/Windows expected via CLI support

Known Limitations

  • The SDK wraps an external CLI process; behavior also depends on installed CLI version.
  • No built-in JSON-schema builder helper is provided; pass schema as serde_json::Value.
  • Test suite is comprehensive at protocol/mock level; real CLI/live-model matrix testing is not part of this crate.

Testing and Validation

Reference alignment coverage (TypeScript -> Rust):

  • tests/run.test.ts -> tests/run_tests.rs
  • tests/runStreamed.test.ts -> tests/run_streamed_tests.rs
  • tests/exec.test.ts -> tests/exec_tests.rs
  • tests/abort.test.ts -> tests/abort_tests.rs

Validation commands:

RUSTDOCFLAGS='-Dwarnings -Dmissing_docs' cargo doc -p codex-client-sdk --no-deps
cargo test -p codex-client-sdk

Concurrency Model

  • run_streamed() returns a Send stream of ThreadEvent
  • run() materializes a final Turn by consuming streamed events
  • Turn cancellation uses tokio_util::sync::CancellationToken

Development

cargo test -p codex-client-sdk
cargo clippy -p codex-client-sdk --all-targets --all-features -- -D warnings

Contributing

Pull requests are welcome. Before submitting, run:

cargo fmt
cargo clippy -p codex-client-sdk --all-targets --all-features -- -D warnings
cargo test -p codex-client-sdk

License

Licensed under the Apache License, Version 2.0.