Python client SDK for the Codex app-server JSON-RPC protocol
Project description
Codex App Server Client SDK
Python client for the Codex app-server JSON-RPC protocol. Build AI-powered applications with full type safety, streaming support, and bidirectional communication.
Installation
Prerequisites
- Python: ≥3.11
- Codex CLI: A
codexbinary on your PATH (see OpenAI Codex for installation)
Install from PyPI
pip install codex-app-server-client
Or with uv:
uv pip install codex-app-server-client
Install from source
For contributors or to install the latest development version:
git clone https://github.com/paras-anekantvad/codex-app-server-client-sdk.git
cd codex-app-server-client-sdk
uv sync --all-extras
Quick Examples
Simple: Ask a question
import asyncio
from codex_app_server_client import CodexAppServer
async def main():
async with CodexAppServer() as codex:
thread = await codex.start_thread()
result = await thread.run("Explain Python decorators in 3 sentences")
print(result.final_response)
asyncio.run(main())
Streaming: Print deltas as they arrive
from codex_app_server_client import CodexAppServer
from codex_app_server_client.types.events import AgentMessageDeltaEvent
async with CodexAppServer() as codex:
thread = await codex.start_thread()
async for event in thread.run_streamed("Write a haiku about recursion"):
if isinstance(event, AgentMessageDeltaEvent):
print(event.delta, end="", flush=True)
print() # newline
Advanced: Policy control with event callbacks
Block disallowed actions in real-time:
from codex_app_server_client import CodexAppServer, EventAction
from codex_app_server_client.types.events import ItemCompletedEvent, ThreadEvent
ALLOWED_TYPES = {"agentMessage", "plan", "reasoning", "webSearch"}
def policy_filter(method: str, event: ThreadEvent) -> EventAction | None:
if isinstance(event, ItemCompletedEvent):
item_type = event.item.get("type") if isinstance(event.item, dict) else None
if item_type and item_type not in ALLOWED_TYPES:
return EventAction.INTERRUPT # block unsafe actions
return None
async with CodexAppServer() as codex:
thread = await codex.start_thread()
result = await thread.run(
"Write and run a shell script",
on_event=policy_filter,
)
if result.status == "interrupted":
print("Turn blocked due to policy violation")
Key Features
- Type-safe: Full protocol coverage with Pydantic models
- Async & sync: Both
asyncioand synchronous APIs - Streaming: Real-time events via
run_streamed() - Policy control:
on_eventcallbacks for approval/interrupt logic - Bidirectional: Handle server-initiated approval requests
- Thread management: Resume conversations, fork threads, rollback turns
- Error handling: Typed exceptions and structured error payloads
Common Patterns
Resume an existing thread
async with CodexAppServer() as codex:
# List recent threads
threads = await codex.list_threads(limit=10)
thread_id = threads[0].id
# Resume and continue conversation
thread = await codex.resume_thread(thread_id)
result = await thread.run("Summarize our conversation so far")
Select a specific model
# Set model at thread creation
thread = await codex.start_thread(
model="gpt-5.2-codex",
cwd="/path/to/project",
)
# Or override per-turn
result = await thread.run(
"Quick question",
model="gpt-5.3-codex",
)
Handle approval requests
For bidirectional scenarios where the server requests client approval:
from codex_app_server_client import AsyncCodexClient
client = AsyncCodexClient()
async def approve_safe_commands(method: str, params: dict) -> dict:
if method == "commandExecution/approve":
command = params.get("command", "")
if command.startswith(("ls", "cat", "grep")):
return {"decision": "approve"}
return {"decision": "decline"}
client.on_server_request("commandExecution/approve", approve_safe_commands)
await client.start()
# ... use client ...
Set timeouts and handle errors
try:
result = await thread.run(
"Long-running task",
timeout_s=60, # raise TimeoutError after 60s
)
if result.status == "failed":
print(f"Turn failed: {result.error.message}")
except TimeoutError:
print("Turn timed out")
Sync API (for non-async codebases)
from codex_app_server_client import SyncCodexAppServer
with SyncCodexAppServer() as codex:
thread = codex.start_thread()
result = thread.run("Hello!")
print(result.final_response)
API Reference
High-level API
CodexAppServer/SyncCodexAppServer: Context managers for managing the app-server lifecycle. Exposesstart_thread(),resume_thread(),list_threads().AsyncThread/SyncThread: Bound to a thread ID. Main methods:run(input, **kwargs) -> TurnResult: Execute a turn, block until completerun_streamed(input, **kwargs) -> AsyncIterator[ThreadEvent]: Stream events in real-time
TurnResult: Dataclass with:final_response: str— agent's text responsestatus: str—"completed","interrupted", or"failed"items: list[dict]— all completed itemsusage: ThreadTokenUsage | None— token countserror: TurnError | None— error details if failed
Low-level API
AsyncCodexClient/SyncCodexClient: Direct protocol access. Every app-server method has a typed wrapper:thread_start(),thread_resume(),thread_list(),thread_fork(),thread_rollback()turn_start(),turn_interrupt(),turn_steer()account_read(),account_login_start()on_notification(method, callback)— register event handlerson_server_request(method, callback)— handle server-initiated requests
Types
All in codex_app_server_client.types.*:
ThreadInfo,TurnInfo,ThreadItem(15 variants)ThreadEvent(25+ event types):TurnStartedEvent,ItemCompletedEvent,AgentMessageDeltaEvent, etc.TurnStartParams,ThreadStartParams,ApprovalPolicy,SandboxPolicy
See src/codex_app_server_client/__init__.py for all exports.
Configuration
CodexAppServer(
codex_bin="/path/to/codex", # Path to codex binary (default: auto-detect)
client_name="my_app", # Client identifier for logging
client_version="1.0.0", # Your app version
experimental_api=True, # Enable experimental protocol features
extra_args=["--model", "gpt-5.2-codex"], # Extra CLI args for codex subprocess
env={"OPENAI_API_KEY": "sk-..."}, # Environment variables
)
Development
Use the Makefile for common tasks:
make install # install dependencies (uv sync --all-extras)
make test # run tests with coverage
make lint # run ruff linter
make format # format code with ruff
make type-check # run mypy type checker
make fix # auto-fix linting issues
make pre-commit # run all checks (CI-like)
Or run uv commands directly:
uv sync --all-extras # install dependencies
uv run pytest # run tests
uv run ruff check src/ tests/ # lint
uv run ruff format src/ tests/ # format
uv run mypy src/ # typecheck (strict)
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file codex_app_server_client-0.1.0.tar.gz.
File metadata
- Download URL: codex_app_server_client-0.1.0.tar.gz
- Upload date:
- Size: 82.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7eb3eac1f0c471ae77b502e777cbf1db91f2e9b7b84df09eab4b74ec5ed7ea66
|
|
| MD5 |
b882ac258ad80ad28d4dba0187d3dab0
|
|
| BLAKE2b-256 |
b78fd178eab35fff923d39589dc31af185a806d3061e2675635c55ba234155ae
|
Provenance
The following attestation bundles were made for codex_app_server_client-0.1.0.tar.gz:
Publisher:
publish.yml on paras-anekantvad/codex-app-server-client-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
codex_app_server_client-0.1.0.tar.gz -
Subject digest:
7eb3eac1f0c471ae77b502e777cbf1db91f2e9b7b84df09eab4b74ec5ed7ea66 - Sigstore transparency entry: 976341221
- Sigstore integration time:
-
Permalink:
paras-anekantvad/codex-app-server-client-sdk@25c94bb366d73ae18937ca143f619572a4cc0639 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/paras-anekantvad
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@25c94bb366d73ae18937ca143f619572a4cc0639 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file codex_app_server_client-0.1.0-py3-none-any.whl.
File metadata
- Download URL: codex_app_server_client-0.1.0-py3-none-any.whl
- Upload date:
- Size: 39.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8e2c9d322beb99702f3661c5366afede7fe89294c571ef5260fd9db23f597593
|
|
| MD5 |
72714ae8a8dc20a348f774d572fb2c53
|
|
| BLAKE2b-256 |
91b4e6598c8f17b73bd7be81904d25462a6040ab5d433d0a7f81bf0ea87c300b
|
Provenance
The following attestation bundles were made for codex_app_server_client-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on paras-anekantvad/codex-app-server-client-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
codex_app_server_client-0.1.0-py3-none-any.whl -
Subject digest:
8e2c9d322beb99702f3661c5366afede7fe89294c571ef5260fd9db23f597593 - Sigstore transparency entry: 976341225
- Sigstore integration time:
-
Permalink:
paras-anekantvad/codex-app-server-client-sdk@25c94bb366d73ae18937ca143f619572a4cc0639 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/paras-anekantvad
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@25c94bb366d73ae18937ca143f619572a4cc0639 -
Trigger Event:
workflow_dispatch
-
Statement type: