Build a minimal React + TypeScript web app that connects to the local Codex app-server over WebSocket and enables voice-to-code via WebRTC.
Target flow:
- Connect to
codex app-server - Start a Codex thread
- Start a voice session with
thread/realtime/start - Send mic audio to the agent and hear audio back
- Show JSON-RPC logs and agent activity in the UI
- A Vite React + TypeScript app in
voice-codex - WebSocket connection UI with JSON-RPC logging
- Thread creation UI
- Agent activity panel
- WebRTC offer generation and remote SDP handling
- Local proxy so the browser can talk to
codex app-serverdespite browserOriginrestrictions - Account status UI
- API-key login/logout UI for app-server auth endpoints
It defaults to stdio://, not a TCP listener. To expose WebSocket manually:
codex app-server --listen ws://127.0.0.1:3000codex app-server rejects requests with an Origin header. Browsers always send one for WebSocket handshakes, so we added a local proxy on port 3001.
The correct startup flow is:
initializeinitialized- then normal requests like
thread/start
The sandbox enum had to be workspace-write, not workspaceWrite.
At first, app-server kept using ChatGPT auth because Codex shared auth state from ~/.codex, likely including desktop-app login state.
We fixed that by:
- running app-server with isolated
CODEX_HOME - then explicitly logging in via JSON-RPC:
{
"method": "account/login/start",
"params": {
"type": "apiKey",
"apiKey": "sk-..."
}
}Confirmed via:
{
"result": {
"account": {
"type": "apiKey"
}
}
}Even after confirmed apiKey auth, model/list from codex app-server still only exposed Codex/GPT-5 models such as:
gpt-5.3-codexgpt-5.4gpt-5.2-codexgpt-5.1-codex-max
It did not expose realtime-capable models like:
gpt-realtimegpt-realtime-mini
Direct API model listing showed realtime models were available to the account, including:
gpt-realtimegpt-realtime-minigpt-realtime-1.5gpt-4o-realtime-preview
So the limitation is specifically in codex app-server model exposure, not in OpenAI account access.
codex app-server in this setup supports the realtime protocol surface, but does not currently expose a realtime-capable model for local threads, even under confirmed API-key auth.
That means thread/realtime/start is not viable for our goal in the current Codex path.
The frontend can now:
- connect to app-server through the local proxy
- initialize correctly
- start threads successfully
- show JSON-RPC traffic
- show agent events
- display current auth mode
- log into
apiKeymode from the UI - log out from the UI
But voice via thread/realtime/start still fails because the selected Codex thread model does not support realtime conversation.
We are pivoting to a split architecture:
- coding threads
- file edits
- shell commands
- agent activity
- tool-driven coding workflow
- low-latency voice input/output
- browser audio streaming
- speech interaction
This keeps the parts that already work:
- Codex is still used for coding
- OpenAI Realtime API is used for voice
The downside is that we now need orchestration between two systems instead of one. But this is still better than blocking on a Codex app-server capability that does not appear to be exposed in the current release.
- Browser talks to OpenAI Realtime API for audio session
- User speech is converted into instructions
- App sends those instructions into a Codex thread over app-server
- Codex performs edits / commands / coding actions
- App streams activity and results back into UI
- Optionally summarize Codex results back through the realtime voice layer
- Rotate any API keys that were pasted during debugging
- The current frontend already has useful plumbing we can reuse:
- connection handling
- JSON-RPC logging
- account status
- thread creation
- activity display
- The next implementation step should be replacing the current voice/session path with direct OpenAI Realtime API integration