openai-codex is a public beta. Install it with
pip install openai-codex; public APIs may change before 1.0. While beta
releases are the only published SDK releases, pip selects the latest beta.
After a stable release exists, pass --pre to opt into newer prereleases.
The SDK and runtime packages are versioned independently. Each SDK release pins and installs one compatible runtime dependency automatically.
- A
Threadis conversation state. - A
Turnis one model execution inside that thread. - Multi-turn chat means multiple turns on the same
Thread.
Thread.run(...)starts a turn and returnsTurnResult.TurnHandle.run()/AsyncTurnHandle.run()consumes events for an existing turn handle and returns the sameTurnResultshape.TurnHandle.stream()/AsyncTurnHandle.stream()yields raw notifications (Notification) so you can react event-by-event.
Choose run() for most apps. Choose stream() for progress UIs, custom timeout logic, or custom parsing.
Codexis the sync public API.AsyncCodexis an async replica of the same public API shape.- Prefer
async with AsyncCodex()for async code. It is the standard path for explicit startup/shutdown, andAsyncCodexinitializes lazily on context entry or first awaited API use.
If your app is not already async, stay with Codex.
login_api_key(...)authenticates immediately with an API key.login_chatgpt()starts browser login and returns a handle withauth_url.login_chatgpt_device_code()starts device-code login and returns a handle withverification_urlanduser_code.- Interactive handles expose
wait()for the matchingaccount/login/completednotification andcancel()to stop that attempt. account()reads the current account state, andlogout()clears it.
Public API keyword names are snake_case. The SDK still maps them to wire camelCase under the hood.
If you are migrating older code, update these names:
approvalPolicy->approval_policybaseInstructions->base_instructionsdeveloperInstructions->developer_instructionsmodelProvider->model_providermodelProviders->model_providerssortKey->sort_keysourceKinds->source_kindsoutputSchema->output_schema
Use the same sandbox= keyword for threads and turns:
from openai_codex import Sandbox
thread = codex.thread_start(sandbox=Sandbox.workspace_write)
result = thread.run("Review only.", sandbox=Sandbox.read_only)The presets are:
Sandbox.read_only: read files without allowing writes.Sandbox.workspace_write: the normal default for projects with a recorded trust decision; read files and write inside the workspace and configured writable roots.Sandbox.full_access: run without filesystem access restrictions.
When sandbox= is omitted, Codex uses its configured default. A turn
sandbox override applies to that turn and subsequent turns.
The public API keeps only explicit lifecycle calls:
thread_start(...)to create new threadsthread_resume(thread_id, ...)to continue existing threads
This avoids duplicate ways to do the same operation and keeps behavior explicit.
Codex() is eager: it starts transport and calls initialize in __init__.
Common causes:
- installation is incomplete and the pinned
openai-codex-cli-bindependency is missing - local
codex_binoverride points to a missing file - a custom local Codex executable does not support the SDK operation being used
A turn is complete only when turn/completed arrives for that turn ID.
run()waits for this automatically.- With
stream(), keep consuming notifications until completion.
Use retry_on_overload(...) for transient overload failures (ServerBusyError).
Do not blindly retry all errors. For InvalidParamsError or
MethodNotFoundError, fix the input or use the runtime pinned by the SDK.
- Starting a new thread for every prompt when you wanted continuity.
- Forgetting to
close()(or not using context managers). - Reading
Turn.itemsfrom live start/completed payloads instead of usingTurnResult.items. - Mixing SDK input classes with raw dicts incorrectly.