Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Codex iOS Prototype

This repository is a native iOS prototype for controlling Codex from an iPhone or iOS Simulator. It contains the SwiftUI app, a local Swift SDK for the Codex app-server JSON-RPC protocol, helper scripts for running a local Codex app-server, and reference material used while building the protocol integration.

The intended mobile loop is:

open app -> connect to Codex app-server -> authenticate -> select project -> send prompt -> watch progress -> continue, stop, or retry the task

The prototype is intentionally focused on the "phone as a Codex command center" workflow. The phone does not run Codex locally and does not check out repositories on-device. Instead, it connects to a Codex app-server running on a Mac, local network host, Tailscale/private-network machine, or another reachable server.

Table Of Contents

Current Status

This is a working prototype, not a production iOS client.

Implemented today:

  • SwiftUI iOS app with four main tabs: Home, Projects, Chats, and Settings.
  • Local Swift Package named CodexSDK for talking to the Codex app-server over WebSocket.
  • App-server readiness check through the server HTTP probe endpoint.
  • WebSocket bearer-token authentication.
  • ChatGPT device-code login flow through the app-server account APIs.
  • Project list derived from existing Codex threads and their cwd/path metadata.
  • Recent task/chat list derived from app-server thread history.
  • New task creation from the phone.
  • Live notification streaming when connected to the active app-server session.
  • Polling fallback for task state refresh.
  • Task detail screen with event timeline, follow-up input, stop, and retry.
  • Keychain-backed storage for the app-server bearer token.
  • UserDefaults persistence for server URL, selected project, selected model, and selected run profile.
  • Diagnostics view that summarizes connection, auth, selected project, runtime observer counts, and security warnings.
  • Helper scripts for starting, stopping, and smoke-testing a local codex app-server.

The app is optimized for rapid prototype iteration. Expect protocol drift, UI rough edges, and some server assumptions to change as Codex app-server evolves.

Repository Map

.
|-- README.md
|-- PRD.md
|-- codex/
|   |-- codex.xcodeproj/
|   |-- Info.plist
|   `-- codex/
|       |-- codexApp.swift
|       |-- ContentView.swift
|       |-- Core/
|       |   |-- Feedback/
|       |   |-- Mapping/
|       |   |-- Models/
|       |   |-- Networking/
|       |   |-- State/
|       |   `-- Storage/
|       |-- DesignSystem/
|       |-- Features/
|       |   |-- Chats/
|       |   |-- Home/
|       |   |-- Projects/
|       |   |-- Settings/
|       |   `-- TaskDetail/
|       `-- PreviewSupport/
|-- CodexSwiftSDK/
|   |-- Package.swift
|   |-- README.md
|   |-- Sources/CodexSDK/
|   `-- Tests/CodexSDKTests/
|-- local-app-server/
|   |-- start.sh
|   |-- stop.sh
|   |-- send-smoke-message.mjs
|   `-- state/
|-- mockups/
`-- codex-sdk-reference/

Important paths:

  • codex/: the iOS app and Xcode project.
  • codex/codex/Core/State/AppModel.swift: central app state, task orchestration, persistence hooks, streaming/polling coordination, and user actions.
  • codex/codex/Core/Networking/AppServerCodexClient.swift: live app-server implementation of the app's CodexClient abstraction.
  • codex/codex/Core/Networking/CodexClient.swift: protocol the UI talks to.
  • codex/codex/Core/Models/CodexModels.swift: app-facing project, task, event, auth, and connection models.
  • codex/codex/Core/Mapping/CodexMapping.swift: mapping from SDK/app-server thread and notification payloads into mobile task events.
  • codex/codex/Core/Storage/KeychainTokenStore.swift: Keychain storage for the bearer token.
  • codex/codex/Core/Networking/LiveCodexSessionStore.swift: keeps live SDK clients available so task notification streams can be consumed after task creation.
  • codex/codex/Features/Home/HomeView.swift: launch surface with prompt composer, project/model selectors, quick actions, recent projects, and recent chats.
  • codex/codex/Features/TaskDetail/TaskDetailView.swift: task timeline, follow-up composer, stop, retry, and auto-scroll behavior.
  • codex/codex/Features/Settings/SettingsView.swift: server URL, token, connection testing, refresh, ChatGPT login, defaults, diagnostics, and credential clearing.
  • codex/codex/Features/Settings/DiagnosticsView.swift: copyable runtime diagnostics and connection/security status.
  • codex/codex/DesignSystem/: shared colors, cards, chips, status banners, and task control button styling.
  • CodexSwiftSDK/: local Swift Package dependency used by the app.
  • local-app-server/: scripts for running and testing a local Codex app-server.
  • codex-sdk-reference/: checked-in upstream reference repo used for protocol and SDK comparison. It is not required to build the iOS target.
  • PRD.md: product requirements and first-milestone scope.

Workspace note: codex/ and codex-sdk-reference/ may be nested Git working trees inside the top-level workspace. Check status in the directory you intend to modify.

What The App Does

Server Connection

  • Accepts a Codex app-server WebSocket URL.
  • Normalizes app-server URLs before connecting.
  • Supports local Simulator URLs such as ws://127.0.0.1:4500.
  • Supports LAN/private-network URLs such as ws://192.168.1.25:4500.
  • Uses a bearer token for WebSocket authorization.
  • Tests server readiness using the app-server probe route.
  • Displays connection states: mock, disconnected, connecting, connected, and failed.
  • Shows warnings for unencrypted remote server URLs.

OpenAI / ChatGPT Auth

  • Reads app-server account status.
  • Detects when OpenAI auth is required.
  • Starts ChatGPT device-code login from Settings.
  • Displays the verification URL and user code.
  • Lets the user re-check auth after completing login.
  • Supports logout through the app-server account API.

Projects

  • Lists recent projects by reading Codex thread history from the app-server.
  • Groups project-like entries by cwd/path.
  • Derives display names from the last path component.
  • Uses Git branch metadata when the server provides it.
  • Falls back to an App Server default project when no prior thread has a path.
  • Persists the selected project between app launches.

Tasks And Chats

  • Lists recent chats/tasks from server thread history.
  • Starts a new Codex thread and turn from a phone prompt.
  • Shows a task placeholder immediately after creation.
  • Opens previous tasks and loads full thread state when available.
  • Converts server thread items and notifications into mobile timeline events.
  • Supports follow-up prompts on existing tasks.
  • Supports stopping a running task by interrupting the active turn.
  • Supports retrying failed/cancelled tasks by sending the original prompt as a follow-up.

Streaming And Polling

  • Streams app-server notifications for live tasks when available.
  • Reuses the live SDK session for tasks created in-app so notification replay is available.
  • Falls back to polling task state when streaming is unavailable or insufficient.
  • Tracks active stream and poll observer counts in diagnostics.
  • Batches pending task updates before flushing them into UI state.

UI

  • Native SwiftUI app.
  • Dark-mode-first visual language matching the current prototype mockups.
  • Four main tabs:
    • Home
    • Projects
    • Chats
    • Settings
  • Home includes:
    • server status banner
    • large prompt composer
    • run profile menu
    • project selector
    • model selector
    • quick actions
    • recent projects
    • recent chats
  • Task detail includes:
    • metadata chips
    • status pill
    • event timeline
    • stop/retry controls
    • follow-up composer
    • "go to latest" behavior when the user scrolls away from the bottom
  • Settings includes:
    • server URL
    • token field
    • connection test
    • refresh projects/chats
    • diagnostics
    • ChatGPT login/logout
    • default project/model/profile
    • credential clearing

What The App Does Not Do Yet

The prototype does not currently provide:

  • local Codex execution on the iPhone
  • repository checkout on-device
  • mobile file browser/editor
  • direct Git commit/push workflow from the app
  • full pull-request review UI
  • push notifications
  • background task monitoring when the app is suspended
  • multi-account or multi-server management
  • production-grade certificate pinning or enterprise auth
  • App Store hardening
  • offline mode

These are intentionally outside the first prototype milestone described in PRD.md.

Prerequisites

Required:

  • macOS.
  • Xcode installed.
  • iPhone Simulator or physical iPhone.
  • Codex CLI installed and available as codex, or an explicit CODEX_BIN=/absolute/path/to/codex.
  • A Codex CLI build that supports codex app-server.

Recommended:

  • Node.js for local-app-server/send-smoke-message.mjs.
  • screen for a persistent local app-server session. The start script falls back to nohup when screen is unavailable.
  • Same Wi-Fi network for Mac and iPhone when testing on a physical device.
  • Tailscale or another private network when testing away from the local LAN.

Current project target:

  • The checked-in Xcode project currently targets iOS 26.2.
  • The local Swift package declares platform support for iOS 15+ and macOS 12+, but the app target itself is controlled by the Xcode project.

Quick Start

1. Start The App Server

From the repository root:

./local-app-server/start.sh

The script prints:

  • the bind URL, usually ws://0.0.0.0:4500
  • the Simulator URL, usually ws://127.0.0.1:4500
  • the iPhone LAN URL, for example ws://192.168.1.25:4500
  • the bearer token
  • the app-server process/session information
  • the log file path

2. Open The iOS Project

open codex/codex.xcodeproj

Run the codex scheme in Xcode.

3. Configure Settings In The App

For iOS Simulator:

Server URL: ws://127.0.0.1:4500
Token:      contents printed by start.sh

For physical iPhone on the same network:

Server URL: the iPhone URL printed by start.sh
Token:      contents printed by start.sh

Then:

  1. Tap Test connection.
  2. If Settings reports that ChatGPT auth is required, tap Sign in with ChatGPT.
  3. Complete the device-code flow in the browser.
  4. Return to the app and tap I finished login - check again.
  5. Tap Refresh projects and chats.

4. Start A Task

  1. Go to Home.
  2. Select a project.
  3. Select a model.
  4. Type a prompt into Ask Codex anything....
  5. Tap send.
  6. Watch the task detail screen for progress.

Running The Local App Server

The local app-server helper scripts live in local-app-server/.

Start

./local-app-server/start.sh

What it does:

  • creates local-app-server/state/ if needed
  • creates or reuses local-app-server/state/ws-token
  • starts codex app-server
  • passes --listen ws://HOST:PORT
  • passes --ws-auth capability-token
  • passes --ws-token-file local-app-server/state/ws-token
  • writes logs to local-app-server/state/app-server.log
  • writes process/session state to local-app-server/state/app-server.pid
  • runs inside a screen session when available
  • falls back to nohup when screen is unavailable

Default values:

HOST:           0.0.0.0
PORT:           4500
SCREEN SESSION: codex-ios-app-server
TOKEN FILE:     local-app-server/state/ws-token
LOG FILE:       local-app-server/state/app-server.log

Environment overrides:

CODEX_BIN=/absolute/path/to/codex
CODEX_APP_SERVER_HOST=0.0.0.0
CODEX_APP_SERVER_PORT=4500
CODEX_APP_SERVER_LAN_IP=192.168.1.25
CODEX_APP_SERVER_SCREEN_SESSION=codex-ios-app-server

Examples:

CODEX_APP_SERVER_PORT=4600 ./local-app-server/start.sh
CODEX_BIN=/opt/homebrew/bin/codex ./local-app-server/start.sh
CODEX_APP_SERVER_LAN_IP=100.64.0.10 ./local-app-server/start.sh

Stop

./local-app-server/stop.sh

The stop script:

  • stops the configured screen session if it exists
  • otherwise reads local-app-server/state/app-server.pid
  • sends kill to the recorded process
  • removes the pid file

Token

The token is stored at:

local-app-server/state/ws-token

It is generated once and reused. Delete that file only if you intentionally want a new token. After regenerating it, update the token in the iOS app Settings.

Logs

The app-server log is stored at:

local-app-server/state/app-server.log

Use this file when:

  • Xcode shows a connection failure.
  • the smoke test cannot connect.
  • the server starts but immediately exits.
  • ChatGPT login/account APIs behave unexpectedly.
  • task creation returns a protocol error.

Configuring The iOS App

Open Settings in the app.

Server URL

Use one of these:

Simulator on same Mac: ws://127.0.0.1:4500
Physical iPhone LAN:  ws://<mac-lan-ip>:4500
Private network:      ws://<tailscale-or-private-ip>:4500
TLS endpoint:         wss://<host>

Avoid using 0.0.0.0 in the iOS app. 0.0.0.0 is a bind address for the server, not a destination address for the client.

Token

Paste the bearer token printed by start.sh, or read it from:

local-app-server/state/ws-token

The app stores this value in Keychain through KeychainTokenStore.

Test Connection

Test connection verifies:

  • the URL can be parsed
  • the app-server readiness endpoint is reachable
  • the bearer token works for the probe where required
  • account status can be read through the SDK

Refresh Projects And Chats

Refresh projects and chats:

  • connects to the app-server
  • reads account status
  • lists recent threads
  • derives projects from thread paths
  • derives chat/task summaries from thread metadata
  • updates the Home, Projects, and Chats views

ChatGPT Login

If account status says ChatGPT login is required:

  1. Tap Sign in with ChatGPT.
  2. Copy or inspect the displayed device code.
  3. Tap Open verification page.
  4. Complete the login in the browser.
  5. Return to the app.
  6. Tap I finished login - check again.

The actual OpenAI/ChatGPT auth is managed by the app-server/Codex CLI side. The iOS app starts and observes that flow; it does not store ChatGPT credentials directly.

Diagnostics

The Diagnostics screen shows:

  • normalized server URL
  • whether a token is configured
  • connection status and detail
  • account status and detail
  • active project name/path
  • selected model and run profile
  • project count
  • task count
  • running task count
  • active stream count
  • active poller count
  • pending update count
  • current security warning, if any

Use Copy diagnostics when reporting issues.

Using The App

Home

Home is the fastest task-launch surface.

Primary controls:

  • Prompt composer: type a task request.
  • Run profile menu: currently exposes 5.5 High, Medium, and Low.
  • Project selector: picks the cwd used for new tasks.
  • Model selector: currently exposes GPT-4.1, gpt-5.5, and gpt-5.4.
  • Send button: starts a new thread and turn.

Quick actions currently include:

  • Review recent commits
  • Open my latest PR
  • Connect tools
  • Generate implementation plan

Quick actions populate or start from predefined prompts using the selected project.

Projects

Projects are currently inferred from app-server thread history. A project entry generally corresponds to a unique cwd found in recent threads.

Project metadata can include:

  • name
  • path
  • branch
  • stack tags
  • last updated timestamp

Because projects are inferred, a brand-new app-server with no thread history may only show App Server default.

Chats

Chats are recent Codex threads/tasks from the app-server.

Opening a chat:

  • resumes or reads the thread through the SDK
  • loads full task details
  • maps thread items into timeline events
  • starts monitoring again if the task is still running

Task Detail

Task detail is the main monitoring surface.

It displays:

  • project/model metadata
  • status
  • user prompts
  • assistant/final messages
  • tool or activity events when the server provides them
  • file-change-style events when mapping can infer them

Available actions:

  • Stop: interrupts the active turn.
  • Retry: sends the original prompt again as a follow-up for failed/cancelled tasks.
  • Follow-up: continues the same thread once the current task is no longer running.

Architecture

The app follows a small, explicit prototype architecture:

SwiftUI Views
    |
    v
AppModel (@MainActor ObservableObject)
    |
    v
CodexClient protocol
    |
    +--> AppServerCodexClient
    |       |
    |       v
    |   CodexSwiftSDK / CodexSDK
    |       |
    |       v
    |   WebSocket JSON-RPC
    |       |
    |       v
    |   codex app-server
    |
    +--> MockCodexClient

AppModel

AppModel is the central state container. It is annotated @MainActor and exposes published state for SwiftUI.

Responsibilities:

  • owns the current projects list
  • owns the current task list
  • owns connection status
  • owns account status
  • persists selected project/model/profile/server URL
  • reads/writes the Keychain token
  • creates and caches the live app-server client
  • starts tasks
  • sends follow-ups
  • stops active turns
  • retries tasks
  • loads and opens existing tasks
  • starts stream and poll observers
  • applies task updates to UI state
  • prepares diagnostics snapshots

CodexClient Protocol

The UI does not directly know about CodexSDK. It talks to:

protocol CodexClient {
    func health() async throws -> HealthResponse
    func accountStatus(refreshToken: Bool) async throws -> CodexAccountStatus
    func startChatGPTDeviceLogin() async throws -> ChatGPTDeviceLoginInfo
    func logout() async throws
    func listProjects() async throws -> [CodexProject]
    func listTasks() async throws -> [CodexTaskSummary]
    func createTask(request: CreateTaskRequest) async throws -> CreateTaskResponse
    func sendFollowUp(threadId: String, prompt: String, cwd: String, model: String) async throws -> String?
    func interruptTask(threadId: String, turnId: String) async throws
    func getTask(id: String) async throws -> CodexTask
    func streamTaskUpdates(threadId: String) -> AsyncThrowingStream<CodexTaskUpdate, Error>
}

This keeps the UI insulated from transport details and allows MockCodexClient to support previews/prototyping.

AppServerCodexClient

AppServerCodexClient is the live implementation.

Responsibilities:

  • stores base URL and bearer token
  • checks readiness through baseURL.httpProbeURL.appendingPathComponent("readyz")
  • creates a shared Codex SDK client for account/list/read operations
  • starts ChatGPT device login
  • logs out
  • lists threads and maps them into projects/tasks
  • starts a new thread and turn for new tasks
  • resumes an existing thread and starts a turn for follow-ups
  • interrupts active turns
  • reads full task state from thread contents
  • streams notifications and maps them into CodexTaskUpdate
  • closes SDK sessions when no longer needed

LiveCodexSessionStore

New tasks are created on a live SDK connection. Streaming notifications for those tasks may arrive on that same connection. LiveCodexSessionStore lets the monitoring path reuse the SDK client associated with a newly created thread instead of immediately losing the notification stream.

Mapping Layer

The mapping layer translates SDK/app-server objects into mobile UI models:

  • account responses -> CodexAccountStatus
  • thread status -> CodexTaskStatus
  • thread items -> CodexTaskEvent
  • notifications -> CodexTaskUpdate
  • paths -> stable project identifiers
  • prompts -> task titles

The app keeps .unknown/fallback behavior in the SDK and mapping layer so protocol additions do not immediately break the UI.

Codex App-Server Integration

The app talks to the Codex app-server v2 JSON-RPC surface over WebSocket through CodexSwiftSDK.

High-level runtime flow:

  1. local-app-server/start.sh launches codex app-server.
  2. The app stores the server URL and bearer token.
  3. Settings Test connection probes readiness and reads account status.
  4. Refresh projects and chats calls thread list.
  5. Home Send calls thread start, then turn start.
  6. The app inserts a placeholder local task so the UI navigates immediately.
  7. The monitor starts notification streaming and polling.
  8. Task detail renders events as they arrive.
  9. Follow-up resumes the same thread and starts a new turn.
  10. Stop interrupts the active turn.

Representative app-server/SDK methods used:

  • initialize
  • initialized
  • account/read
  • account/login/start
  • account/logout
  • thread/list
  • thread/start
  • thread/resume
  • thread/read
  • turn/start
  • turn/interrupt
  • notification stream methods such as agent message deltas, item completions, and turn completions

The root README deliberately describes behavior at the app level. See CodexSwiftSDK/README.md and CodexSwiftSDK/Sources/CodexSDK/ for SDK-level API details.

Swift SDK

CodexSwiftSDK is a local Swift Package dependency wired into the Xcode project via:

../CodexSwiftSDK

Package details:

  • package name: CodexSwiftSDK
  • library product: CodexSDK
  • Swift tools version: 5.9
  • declared platforms: iOS 15+, macOS 12+
  • source directory: CodexSwiftSDK/Sources/CodexSDK
  • tests: CodexSwiftSDK/Tests/CodexSDKTests

The SDK provides:

  • Codex: connection lifecycle, JSON-RPC requests, and notifications.
  • CodexConfiguration: base URL, bearer token, client info, URLSession.
  • CodexThreadHandle: thread operations such as start, list, resume, read, rename, archive, unarchive, fork, and compact where implemented.
  • CodexTurnHandle: turn operations such as run, stream, steer, and interrupt where implemented.
  • typed request and response models for the app-server protocol.
  • typed notification models plus forward-compatible unknown/fallback handling.
  • support for text, remote image, local image, skill, and mention inputs.

Minimal SDK example:

import CodexSDK
import Foundation

let codex = Codex(configuration: CodexConfiguration(
    baseURL: URL(string: "ws://127.0.0.1:4500")!,
    bearerToken: "token-from-local-app-server"
))

let metadata = try await codex.connect()
print(metadata.serverInfo?.version ?? metadata.userAgent ?? "connected")

let thread = try await codex.threadStart(ThreadStartOptions(
    cwd: "/Users/me/project",
    model: "gpt-5.4",
    approvalPolicy: .onRequest,
    sessionStartSource: .startup
))

let result = try await thread.run("Diagnose the failing tests and propose a fix")
print(result.finalResponse ?? "")

Run SDK tests:

cd CodexSwiftSDK
swift test

Authentication And Security

WebSocket Bearer Token

The local server is started with:

--ws-auth capability-token
--ws-token-file local-app-server/state/ws-token

The iOS app sends:

Authorization: Bearer <token>

Keep this token private. Treat it as access to the app-server and the Codex workflows available through that server.

ChatGPT / OpenAI Auth

The app-server may require an OpenAI-authenticated account. The iOS app:

  • calls account read
  • displays whether auth is required
  • starts device-code login
  • displays the user code and verification URL
  • asks the app-server to refresh account status after the user completes login

The app does not ask for, store, or transmit a ChatGPT password.

Local Network Access

codex/Info.plist includes:

NSLocalNetworkUsageDescription = Connect to your local Codex app-server on this network.

iOS may show a local network permission prompt when connecting to a LAN app-server from a physical device.

App Transport Security

codex/Info.plist currently allows arbitrary loads:

NSAppTransportSecurity.NSAllowsArbitraryLoads = true

This is intentional for prototype development against local ws:// servers. It is not production hardening. A production client should prefer wss://, narrow ATS exceptions, and use a stronger deployment/security model.

Security Warnings In The App

The app warns when:

  • the URL is an unencrypted local/private-network URL
  • the URL is an unencrypted remote URL that does not look local/private

Local/private ws:// can be acceptable for a prototype if the network is private and bearer token auth is enforced. Remote unencrypted ws:// should be avoided.

Persistence

Stored in Keychain:

  • app-server bearer token

Stored in UserDefaults:

  • server URL
  • selected project ID
  • selected model
  • selected run profile

In-memory only:

  • current project/task arrays loaded from the server
  • active stream tasks
  • active poll tasks
  • pending update buffers
  • live SDK session references
  • pending device-login info

Runtime files on the Mac:

  • local-app-server/state/ws-token
  • local-app-server/state/app-server.log
  • local-app-server/state/app-server.pid

Validation And Tests

Smoke Test The App Server

From the repository root, with the app-server running:

node ./local-app-server/send-smoke-message.mjs

The smoke script:

  • opens a raw WebSocket connection
  • sends initialize
  • sends initialized
  • reads account status
  • starts a thread
  • starts a turn
  • prints streamed assistant deltas
  • prints final status and final text

Environment overrides:

CODEX_APP_SERVER_URL=ws://127.0.0.1:4500
CODEX_APP_SERVER_TOKEN=<token>
CODEX_SMOKE_CWD=/Users/me/project
CODEX_SMOKE_MODEL=gpt-5.4
CODEX_SMOKE_PROMPT="Say hello from smoke test."

Example:

CODEX_SMOKE_CWD="$PWD" node ./local-app-server/send-smoke-message.mjs

Swift Package Tests

cd CodexSwiftSDK
swift test

Xcode Build

Open:

open codex/codex.xcodeproj

Then build/run the codex scheme in Xcode.

If you prefer command line builds, inspect available schemes first:

xcodebuild -list -project codex/codex.xcodeproj

Then build with an appropriate destination for your installed Xcode/iOS runtime.

Troubleshooting

App Says Server Not Configured

Check:

  • server URL is not empty
  • server URL starts with ws:// or wss://
  • token is pasted into Settings
  • URL is a destination address, not 0.0.0.0

For Simulator, use:

ws://127.0.0.1:4500

For iPhone, use the LAN/private IP printed by start.sh.

App Says Connection Failed

Check:

  • ./local-app-server/start.sh is running
  • local-app-server/state/app-server.log for server errors
  • the token in the app matches local-app-server/state/ws-token
  • macOS firewall allows incoming connections for the server process
  • iPhone and Mac are on the same network
  • iOS local network permission was granted
  • the selected port is not blocked
  • no other process is occupying the same port

Run the smoke test to separate server issues from iOS issues:

node ./local-app-server/send-smoke-message.mjs

Physical iPhone Cannot Connect

Common causes:

  • using 127.0.0.1 on the iPhone, which points to the phone itself
  • using 0.0.0.0 as the app URL
  • Mac and iPhone are on different Wi-Fi networks/VLANs
  • VPN/firewall blocks LAN connections
  • app-server is bound to localhost instead of 0.0.0.0
  • local network permission denied
  • token mismatch

Use the iPhone URL printed by:

./local-app-server/start.sh

Simulator Cannot Connect

Use:

ws://127.0.0.1:4500

Then check:

  • app-server is running on the Mac
  • port matches the server output
  • token matches
  • app-server log has no startup failure

ChatGPT Login Required

If Settings shows that ChatGPT login is required:

  1. Tap Sign in with ChatGPT.
  2. Complete the browser device-code flow.
  3. Return to Settings.
  4. Tap I finished login - check again.

If it still fails:

  • inspect local-app-server/state/app-server.log
  • run the smoke test and look at the printed account status
  • confirm your Codex CLI/app-server auth state works outside the iOS app

No Projects Appear

Projects are inferred from recent threads with cwd or path metadata.

Possible explanations:

  • this is a fresh app-server with no thread history
  • existing threads do not include usable path metadata
  • thread listing failed
  • account auth is incomplete

Expected fallback:

App Server default

Start a task with an explicit/default cwd, then refresh projects and chats.

Task Starts But No Updates Stream

The app should still poll task state. If streaming looks stuck:

  • keep Task Detail open for polling refreshes
  • inspect Diagnostics for active streams and pollers
  • check app-server logs
  • open the task again from Chats
  • verify the smoke test receives deltas/final status

Stop Does Not Stop The Server Task

Stop requires the app to know the active turn ID. For tasks created in-app, this is captured from turn/start. For older/resumed tasks, the app tries to infer the running turn from thread state.

If stop fails:

  • inspect the task status in the server
  • reopen the task from Chats
  • check app-server logs for turn/interrupt errors

Model Fails

The selected model string is sent to the app-server. If the server/CLI does not support that model, task creation may fail.

Try:

gpt-5.4

or use a model known to work with your local Codex CLI/app-server build.

Token Changed

If local-app-server/state/ws-token was deleted/regenerated:

  1. Open Settings.
  2. Replace the token.
  3. Tap Test connection.
  4. Tap Refresh projects and chats.

Port Already In Use

Use another port:

CODEX_APP_SERVER_PORT=4600 ./local-app-server/start.sh

Then configure the app with:

ws://127.0.0.1:4600

or the printed iPhone URL.

Development Notes

Code Style And App Structure

The app is currently organized by feature and core service area:

  • Features/*: SwiftUI screens and screen-specific components.
  • Core/Models: app-facing data models.
  • Core/Networking: client protocols, live app-server client, and session management.
  • Core/Mapping: conversion from SDK/server protocol objects to app UI objects.
  • Core/State: global app model.
  • Core/Storage: Keychain persistence.
  • Core/Feedback: haptics abstraction.
  • DesignSystem: shared styling.
  • PreviewSupport: mock data/client support.

Keep UI code talking through AppModel and CodexClient rather than importing transport details directly into views.

Adding A New App-Server Capability

Recommended path:

  1. Add or update typed SDK models in CodexSwiftSDK/Sources/CodexSDK.
  2. Add the SDK request/notification handling.
  3. Add app-facing models if the UI needs a new shape.
  4. Extend CodexClient only if the UI needs a new operation.
  5. Implement the operation in AppServerCodexClient.
  6. Add mock behavior in MockCodexClient if previews or UI development need it.
  7. Map protocol data in Core/Mapping.
  8. Update the relevant feature view.
  9. Add or update SDK tests.
  10. Validate with the local app-server smoke test and Xcode.

Adding UI

Follow existing patterns:

  • shared colors and materials from CodexStyle.swift
  • status messaging through AppStatusBanner
  • SF Symbols for iconography
  • SwiftUI NavigationStack
  • @EnvironmentObject private var model: AppModel
  • async actions wrapped in Task
  • haptic feedback through Haptics.shared

Updating The SDK

The SDK is local. Changes do not require publishing a package. The Xcode app consumes it through the relative path dependency.

After SDK changes:

cd CodexSwiftSDK
swift test

Then rebuild the iOS app in Xcode.

Working With Nested Git Repositories

This workspace can include nested Git working trees. Before making broad edits, check:

git status --short
git -C codex status --short
git -C codex-sdk-reference status --short

Do not assume the top-level status includes all nested repository changes.

Known Limitations

  • Prototype only; not production-hardened.
  • Relies on a reachable Codex app-server.
  • Uses NSAllowsArbitraryLoads for local development.
  • Does not implement robust background execution.
  • Does not maintain a durable local task database.
  • Projects are inferred from threads, not fetched from a dedicated projects API.
  • Project stack metadata is currently sparse.
  • Branch metadata depends on what the app-server provides.
  • Some timeline event richness depends on available server notifications/thread items.
  • Task interruption depends on the active turn ID being known.
  • App-server protocol changes may require SDK updates.
  • The smoke script currently supports ws:// URLs.
  • codex-sdk-reference/ is reference material and can be large/noisy for searches.

Useful Commands

Start local app-server:

./local-app-server/start.sh

Stop local app-server:

./local-app-server/stop.sh

Show token:

cat local-app-server/state/ws-token

Follow app-server log:

tail -f local-app-server/state/app-server.log

Run smoke test:

node ./local-app-server/send-smoke-message.mjs

Run SDK tests:

cd CodexSwiftSDK
swift test

Open Xcode project:

open codex/codex.xcodeproj

List Xcode schemes:

xcodebuild -list -project codex/codex.xcodeproj

Check top-level Git status:

git status --short

Check nested app Git status:

git -C codex status --short

Reference Material

  • PRD.md: prototype product requirements.
  • CodexSwiftSDK/README.md: Swift SDK usage and package-level scope.
  • CodexSwiftSDK/Sources/CodexSDK/: SDK implementation.
  • codex-sdk-reference/README.md: checked-in upstream Codex reference material.
  • codex-sdk-reference/sdk/typescript/README.md: upstream TypeScript SDK reference.
  • codex-sdk-reference/sdk/python/README.md: upstream Python SDK reference.
  • codex-sdk-reference/sdk/python/docs/api-reference.md: Python SDK API reference.
  • mockups/: prototype UI assets and screen references.

Product Intent

The product brief in PRD.md defines the first milestone as a fast working mobile loop:

Open app -> configure server -> select project -> type prompt -> send to Codex App Server -> see live or refreshed task output -> view result

Everything in this repository should be evaluated against that milestone first. Future features such as richer PR workflows, direct Git operations, notifications, and multi-server support are valuable, but they should not compromise the basic phone-to-Codex loop.

About

Codex app for iOS + Codex SDK for Swift

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages