License: MIT
This repository contains codex_ws_client.py, a lightweight client for codex app-server over WebSocket.
The script lives at skills/codex-ws-client/scripts/codex_ws_client.py.
The primary use case is running it inside Claude Code so Claude models can collaborate with Codex through a live codex app-server connection.
brainstorm.mp4
If inline playback is unavailable, open brainstorm.mp4 directly.
It is intended for agents or scripts that need to:
- send a prompt to a running Codex app-server
- reuse a persisted thread with
--thread-id - stream or buffer assistant output
- get machine-readable JSON output
- use REPL mode for repeated prompts on one connection
- inspect richer server behavior through stderr logs or NDJSON traces
This repo already packages the client as a skill at skills/codex-ws-client/.
To install project-locally (skill available only in this project):
Copy-Item -Recurse -Force skills/codex-ws-client .codex/skills/codex-ws-clientTo install globally (skill available across all projects):
Copy-Item -Recurse -Force skills/codex-ws-client $HOME/.codex/skills/codex-ws-clientAfter a project-local install, run the client from that path:
python .codex/skills/codex-ws-client/scripts/codex_ws_client.py --json "Summarize this repo"After a global install, use $HOME/.codex/skills/codex-ws-client/scripts/codex_ws_client.py instead.
Claude CLI sibling client:
Copy-Item -Recurse -Force skills/claude-cli-client .codex/skills/claude-cli-client
python .codex/skills/claude-cli-client/scripts/claude_cli_client.py --json "Summarize this repo"Use this script when:
- you want Claude Code to delegate work to Codex or continue a shared Codex thread
- a long-lived
codex app-serveris already running - you want lower overhead than spawning
codex execfor every turn - you want direct control over thread ids, timeouts, JSON output, and logging
Do not use it if:
- you need stdio transport instead of WebSocket
- you need full job/session orchestration like a larger wrapper tool
- you need robust interactive approvals outside REPL mode
This client talks only to:
codex app-server --listen ws://HOST:PORT
Default URI:
ws://127.0.0.1:8765
The client uses this protocol flow:
- connect to the WebSocket
- send
initialize - send
initialized - create or resume a thread
- send
turn/start - consume streamed notifications until the turn finishes
It handles:
item/agentMessage/deltaturn/completedturn/failed- approval/file-change/permissions server requests
- selected thread/tool/command/file-change notifications
Fresh thread:
- if
--thread-idis omitted, the client creates a new thread
Resumed thread:
- if
--thread-idis provided, the client callsthread/resume - resumed turns use
--resume-timeout
Persistence:
- threads are persisted by default
--ephemeraldisables persistence--thread-idonly makes sense for non-ephemeral threads
Important:
--ephemeralthreads cannot be resumed across connections- if a resumed thread cannot be loaded, one-shot mode fails fast
- in REPL mode, some stale-thread cases may fall back to a new thread
Plain text:
- default mode streams deltas to stdout
Buffered text:
--no-streamprints the final assistant text once at end of turn
JSON:
--jsonprints a structured JSON object to stdout- this is the best mode for another LLM or tool to consume
Current JSON shape includes:
thread_idturn_idstatustext- optional
error - optional
notifications - optional
metrics
metrics currently includes:
latency_msinput_tokensoutput_tokens
One-shot prompt:
python skills/codex-ws-client/scripts/codex_ws_client.py "Summarize this repo"JSON output for tool use:
python skills/codex-ws-client/scripts/codex_ws_client.py --json "List the main entrypoints"Reuse a persisted thread:
python skills/codex-ws-client/scripts/codex_ws_client.py --thread-id THREAD_ID "Continue the previous conversation"Interactive REPL:
python skills/codex-ws-client/scripts/codex_ws_client.py --repl --print-thread-idREPL with interactive approvals:
python skills/codex-ws-client/scripts/codex_ws_client.py --repl --interactive-approvalsPrompt from file:
python skills/codex-ws-client/scripts/codex_ws_client.py --prompt-file prompt.txtStructured output with trace:
python skills/codex-ws-client/scripts/codex_ws_client.py --json --ndjson-file trace.jsonl "Return metadata"Available in REPL mode:
/threadprints the current thread id/newcreates a new thread/exitor/quitexits the REPL
Verbosity:
-vprints lifecycle and selected notification summaries to stderr-vvprints raw JSON-RPC traffic to stderr
Trace file:
--ndjson-file FILEappends JSON-RPC traffic as JSON lines
Summary:
--summaryprints token usage and latency to stderr
Save final message:
--out FILEwrites the final assistant text to a file
Default behavior:
- command approvals are auto-declined
- file-change approvals are auto-declined
- permission requests are denied
REPL override:
--interactive-approvalsenables prompt-based handling for:- command approvals
- file-change approvals
- permission requests
Still unsupported:
- dynamic tool execution requested by server
- tool user input requests outside the simple approval prompts
- ChatGPT auth token refresh requests
Unsupported server requests are answered explicitly instead of being ignored.
--timeout
- normal WebSocket message wait timeout
--connect-timeout
- initial connection timeout
--resume-timeout
- timeout for turns sent on resumed threads
Set any of them to 0 for no timeout.
0: success1: turn failure2: bad arguments3: connection failure4: timeout5: JSON/schema parse error130: interrupted
Prefer:
--jsonfor machine consumption--no-streamif you only need the final answer text--thread-idonly for known persisted threads--ndjson-filewhen debugging protocol behavior
Avoid:
- using
--thread-idwith threads created via--ephemeral - relying on REPL-only features from one-shot mode
- expecting full protocol coverage for every server request type
Recommended one-shot pattern:
python skills/codex-ws-client/scripts/codex_ws_client.py --json --connect-timeout 10 --timeout 120 "YOUR PROMPT"Recommended resumed-thread pattern:
python skills/codex-ws-client/scripts/codex_ws_client.py --json --thread-id THREAD_ID --resume-timeout 300 "YOUR PROMPT"- WebSocket only, no stdio mode
- single-process CLI design, not a reusable library
- not a full protocol framework
- Windows graceful interrupt of an in-flight turn is still limited
- richer server-request families are partially handled, not comprehensively implemented
This script is a client.
It does not start the server automatically.
You must already have something like:
codex app-server --listen ws://127.0.0.1:8765running before using it.
If you hit a bug, open an issue with the command you ran, the expected behavior, the actual behavior, and any relevant stderr or NDJSON trace output.
Contributions are welcome. Keep changes focused, update documentation when behavior changes, and include validation steps or reproduction notes in the pull request.