# FAQ ## Thread vs turn - A `Thread` is conversation state. - A `Turn` is one model execution inside that thread. - Multi-turn chat means multiple turns on the same `Thread`. ## `run()` vs `stream()` - `Turn.run()` is the easiest path. It consumes events until completion and returns `TurnResult`. - `Turn.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. ## Sync vs async clients - `Codex` is the minimal sync SDK and best default. - `AsyncAppServerClient` wraps the sync transport with `asyncio.to_thread(...)` for async-friendly call sites. If your app is not already async, stay with `Codex`. ## `thread(...)` vs `thread_resume(...)` - `codex.thread(thread_id)` only binds a local helper to an existing thread ID. - `codex.thread_resume(thread_id, ...)` performs a `thread/resume` RPC and can apply overrides (model, instructions, sandbox, etc.). Use `thread(...)` for simple continuation. Use `thread_resume(...)` when you need explicit resume semantics or override fields. ## Why does constructor fail? `Codex()` is eager: it starts transport and calls `initialize` in `__init__`. Common causes: - published runtime package (`codex-cli-bin`) is not installed - local `codex_bin` override points to a missing file - local auth/session is missing - incompatible/old app-server Maintainers stage releases by building the SDK once and the runtime once per platform with the same pinned runtime version. Publish `codex-cli-bin` as platform wheels only; do not publish an sdist: ```bash cd sdk/python python scripts/update_sdk_artifacts.py generate-types python scripts/update_sdk_artifacts.py \ stage-sdk \ /tmp/codex-python-release/codex-app-server-sdk \ --runtime-version 1.2.3 python scripts/update_sdk_artifacts.py \ stage-runtime \ /tmp/codex-python-release/codex-cli-bin \ /path/to/codex \ --runtime-version 1.2.3 ``` ## Why does a turn "hang"? A turn is complete only when `turn/completed` arrives for that turn ID. - `run()` waits for this automatically. - With `stream()`, make sure you keep consuming notifications until completion. ## How do I retry safely? Use `retry_on_overload(...)` for transient overload failures (`ServerBusyError`). Do not blindly retry all errors. For `InvalidParamsError` or `MethodNotFoundError`, fix inputs/version compatibility instead. ## Common pitfalls - Starting a new thread for every prompt when you wanted continuity. - Forgetting to `close()` (or not using `with Codex() as codex:`). - Ignoring `TurnResult.status` and `TurnResult.error`. - Mixing SDK input classes with raw dicts incorrectly in minimal API paths.