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.
- Current Status
- Repository Map
- What The App Does
- What The App Does Not Do Yet
- Prerequisites
- Quick Start
- Running The Local App Server
- Configuring The iOS App
- Using The App
- Architecture
- Codex App-Server Integration
- Swift SDK
- Authentication And Security
- Persistence
- Validation And Tests
- Troubleshooting
- Development Notes
- Known Limitations
- Useful Commands
- Reference Material
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
CodexSDKfor 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.
UserDefaultspersistence 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.
.
|-- 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'sCodexClientabstraction.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.
- 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.
- 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.
- 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 defaultproject when no prior thread has a path. - Persists the selected project between app launches.
- 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.
- 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.
- 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
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.
Required:
- macOS.
- Xcode installed.
- iPhone Simulator or physical iPhone.
- Codex CLI installed and available as
codex, or an explicitCODEX_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. screenfor a persistent local app-server session. The start script falls back tonohupwhenscreenis 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.
From the repository root:
./local-app-server/start.shThe 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
open codex/codex.xcodeprojRun the codex scheme in Xcode.
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:
- Tap
Test connection. - If Settings reports that ChatGPT auth is required, tap
Sign in with ChatGPT. - Complete the device-code flow in the browser.
- Return to the app and tap
I finished login - check again. - Tap
Refresh projects and chats.
- Go to Home.
- Select a project.
- Select a model.
- Type a prompt into
Ask Codex anything.... - Tap send.
- Watch the task detail screen for progress.
The local app-server helper scripts live in local-app-server/.
./local-app-server/start.shWhat 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
screensession when available - falls back to
nohupwhenscreenis 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-serverExamples:
CODEX_APP_SERVER_PORT=4600 ./local-app-server/start.shCODEX_BIN=/opt/homebrew/bin/codex ./local-app-server/start.shCODEX_APP_SERVER_LAN_IP=100.64.0.10 ./local-app-server/start.sh./local-app-server/stop.shThe stop script:
- stops the configured
screensession if it exists - otherwise reads
local-app-server/state/app-server.pid - sends
killto the recorded process - removes the pid file
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.
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.
Open Settings in the app.
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.
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 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:
- 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
If account status says ChatGPT login is required:
- Tap
Sign in with ChatGPT. - Copy or inspect the displayed device code.
- Tap
Open verification page. - Complete the login in the browser.
- Return to the app.
- 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.
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.
Home is the fastest task-launch surface.
Primary controls:
- Prompt composer: type a task request.
- Run profile menu: currently exposes
5.5 High,Medium, andLow. - Project selector: picks the
cwdused for new tasks. - Model selector: currently exposes
GPT-4.1,gpt-5.5, andgpt-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 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 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 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.
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 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
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 is the live implementation.
Responsibilities:
- stores base URL and bearer token
- checks readiness through
baseURL.httpProbeURL.appendingPathComponent("readyz") - creates a shared
CodexSDK 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
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.
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.
The app talks to the Codex app-server v2 JSON-RPC surface over WebSocket through CodexSwiftSDK.
High-level runtime flow:
local-app-server/start.shlaunchescodex app-server.- The app stores the server URL and bearer token.
- Settings
Test connectionprobes readiness and reads account status. Refresh projects and chatscalls thread list.- Home
Sendcalls thread start, then turn start. - The app inserts a placeholder local task so the UI navigates immediately.
- The monitor starts notification streaming and polling.
- Task detail renders events as they arrive.
- Follow-up resumes the same thread and starts a new turn.
- Stop interrupts the active turn.
Representative app-server/SDK methods used:
initializeinitializedaccount/readaccount/login/startaccount/logoutthread/listthread/startthread/resumethread/readturn/startturn/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.
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 testThe 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.
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.
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.
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.
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.
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-tokenlocal-app-server/state/app-server.loglocal-app-server/state/app-server.pid
From the repository root, with the app-server running:
node ./local-app-server/send-smoke-message.mjsThe 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.mjscd CodexSwiftSDK
swift testOpen:
open codex/codex.xcodeprojThen build/run the codex scheme in Xcode.
If you prefer command line builds, inspect available schemes first:
xcodebuild -list -project codex/codex.xcodeprojThen build with an appropriate destination for your installed Xcode/iOS runtime.
Check:
- server URL is not empty
- server URL starts with
ws://orwss:// - 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.
Check:
./local-app-server/start.shis runninglocal-app-server/state/app-server.logfor 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.mjsCommon causes:
- using
127.0.0.1on the iPhone, which points to the phone itself - using
0.0.0.0as 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.shUse:
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
If Settings shows that ChatGPT login is required:
- Tap
Sign in with ChatGPT. - Complete the browser device-code flow.
- Return to Settings.
- 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
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.
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 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/interrupterrors
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.
If local-app-server/state/ws-token was deleted/regenerated:
- Open Settings.
- Replace the token.
- Tap
Test connection. - Tap
Refresh projects and chats.
Use another port:
CODEX_APP_SERVER_PORT=4600 ./local-app-server/start.shThen configure the app with:
ws://127.0.0.1:4600
or the printed iPhone URL.
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.
Recommended path:
- Add or update typed SDK models in
CodexSwiftSDK/Sources/CodexSDK. - Add the SDK request/notification handling.
- Add app-facing models if the UI needs a new shape.
- Extend
CodexClientonly if the UI needs a new operation. - Implement the operation in
AppServerCodexClient. - Add mock behavior in
MockCodexClientif previews or UI development need it. - Map protocol data in
Core/Mapping. - Update the relevant feature view.
- Add or update SDK tests.
- Validate with the local app-server smoke test and Xcode.
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
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 testThen rebuild the iOS app in Xcode.
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 --shortDo not assume the top-level status includes all nested repository changes.
- Prototype only; not production-hardened.
- Relies on a reachable Codex app-server.
- Uses
NSAllowsArbitraryLoadsfor 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.
Start local app-server:
./local-app-server/start.shStop local app-server:
./local-app-server/stop.shShow token:
cat local-app-server/state/ws-tokenFollow app-server log:
tail -f local-app-server/state/app-server.logRun smoke test:
node ./local-app-server/send-smoke-message.mjsRun SDK tests:
cd CodexSwiftSDK
swift testOpen Xcode project:
open codex/codex.xcodeprojList Xcode schemes:
xcodebuild -list -project codex/codex.xcodeprojCheck top-level Git status:
git status --shortCheck nested app Git status:
git -C codex status --shortPRD.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.
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.