@btatum5/codex-bridge 0.1.0 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +473 -23
- package/bin/codex-bridge.js +136 -100
- package/bin/phodex.js +8 -0
- package/bin/remodex.js +8 -0
- package/package.json +38 -24
- package/src/bridge.js +622 -0
- package/src/codex-desktop-refresher.js +776 -0
- package/src/codex-transport.js +238 -0
- package/src/daemon-state.js +170 -0
- package/src/desktop-handler.js +407 -0
- package/src/git-handler.js +1267 -0
- package/src/index.js +35 -0
- package/src/macos-launch-agent.js +457 -0
- package/src/notifications-handler.js +95 -0
- package/src/push-notification-completion-dedupe.js +147 -0
- package/src/push-notification-service-client.js +151 -0
- package/src/push-notification-tracker.js +688 -0
- package/src/qr.js +19 -0
- package/src/rollout-live-mirror.js +730 -0
- package/src/rollout-watch.js +853 -0
- package/src/scripts/codex-handoff.applescript +100 -0
- package/src/scripts/codex-refresh.applescript +51 -0
- package/src/secure-device-state.js +430 -0
- package/src/secure-transport.js +738 -0
- package/src/session-state.js +62 -0
- package/src/thread-context-handler.js +80 -0
- package/src/workspace-handler.js +464 -0
- package/server.mjs +0 -290
package/README.md
CHANGED
|
@@ -1,39 +1,489 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="CodexMobile/CodexMobile/Assets.xcassets/codex-og.imageset/codex-og2%20(1).png" alt="Codex" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# Codex
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/remodex)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
[Follow on X](https://x.com/emanueledpt)
|
|
10
|
+
|
|
11
|
+
Control [Codex](https://openai.com/index/codex/) from your iPhone. Codex is a local-first open-source bridge + iOS app that keeps the Codex runtime on your Windows 11 PC or Mac and lets your phone connect through a paired secure session.
|
|
12
|
+
|
|
13
|
+
## Key App Features
|
|
14
|
+
|
|
15
|
+
- End-to-end encrypted pairing and chats between your iPhone and host computer
|
|
16
|
+
- Fast mode for lower-latency turns
|
|
17
|
+
- Plan mode for structured planning before execution
|
|
18
|
+
- Subagents from iPhone with the `/subagents` command
|
|
19
|
+
- Steer active runs without starting over
|
|
20
|
+
- Queue follow-up prompts while a turn is still running
|
|
21
|
+
- In-app notifications when turns finish or need attention
|
|
22
|
+
- Git actions from your phone, including commit, push, pull, and branch switching
|
|
23
|
+
- Reasoning controls to tune how much thinking Codex uses
|
|
24
|
+
- Access controls with On-Request or Full access
|
|
25
|
+
- Photo attachments from camera or library
|
|
26
|
+
- One-time QR bootstrap with trusted host reconnects
|
|
27
|
+
- macOS-only background bridge service via `launchd`
|
|
28
|
+
- Foreground bridge flow on Windows 11 and other non-macOS hosts
|
|
29
|
+
- Live streaming on your phone while Codex runs on your host computer
|
|
30
|
+
- Shared thread history with Codex on your host computer
|
|
31
|
+
|
|
32
|
+
The repo stays local-first and self-host friendly: the iOS app source does not embed a public hosted endpoint, and the transport layer remains inspectable for anyone who wants to run their own setup.
|
|
33
|
+
|
|
34
|
+
Today, the background daemon / trusted auto-reconnect flow is implemented for macOS. Self-hosted relay setups still work on other OSes, but they currently use the foreground bridge flow instead of the macOS `launchd` service path.
|
|
35
|
+
|
|
36
|
+
If you want the public-repo distribution model explained clearly, read [SELF_HOSTING_MODEL.md](SELF_HOSTING_MODEL.md).
|
|
37
|
+
|
|
38
|
+
> **I am very early in this project. Expect bugs.**
|
|
39
|
+
>
|
|
40
|
+
> I am not actively accepting contributions yet. If you still want to help, read [CONTRIBUTING.md](CONTRIBUTING.md) first.
|
|
41
|
+
|
|
42
|
+
## Get the App
|
|
43
|
+
|
|
44
|
+
Build the iOS app from source in Xcode, or use the GitHub Actions unsigned IPA workflow for SideStore-style sideloading. The device build presents itself as `Codex` on iPhone.
|
|
45
|
+
|
|
46
|
+
If you scan the pairing QR with a generic camera or QR reader before installing the app, your device may treat the QR payload as plain text and open a web search instead of pairing.
|
|
47
|
+
|
|
48
|
+
## Architecture
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
┌──────────────┐ Paired session ┌───────────────┐ stdin/stdout ┌─────────────┐
|
|
52
|
+
│ Codex iOS │ ◄────────────────────► │ Codex Bridge host │ ◄──────────────────────► │ codex │
|
|
53
|
+
│ app │ WebSocket bridge │ bridge │ JSON-RPC │ app-server │
|
|
54
|
+
└──────────────┘ └───────────────┘ └─────────────┘
|
|
55
|
+
│ │
|
|
56
|
+
│ AppleScript route bounce │ JSONL rollout
|
|
57
|
+
▼ ▼
|
|
58
|
+
┌─────────────┐ ┌─────────────┐
|
|
59
|
+
│ Codex.app │ ◄─── reads from ──────── │ ~/.codex/ │
|
|
60
|
+
│ (desktop) │ disk on navigate │ sessions │
|
|
61
|
+
└─────────────┘ └─────────────┘
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
1. Run `codex-bridge up` on your host computer
|
|
65
|
+
2. On macOS, Codex installs/starts a lightweight background bridge service and prints a QR for first-time pairing or recovery
|
|
66
|
+
3. Scan the QR once with the Codex iOS app to trust that host
|
|
67
|
+
4. After the first handshake, the iPhone can resolve the host's live session through the configured relay and reconnect automatically
|
|
68
|
+
5. Your phone sends instructions to Codex through the bridge and receives responses in real-time
|
|
69
|
+
6. The bridge handles git operations and local session persistence on your host computer
|
|
70
|
+
7. `Codex.app` can read the same thread history from disk, but it is not a true live mirror unless you enable the optional refresh workaround
|
|
71
|
+
|
|
72
|
+
## Repository Structure
|
|
73
|
+
|
|
74
|
+
This repo contains the local bridge, the iOS app target, and their tests:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
├── codex-bridge/ # Node.js bridge package used by `remodex`
|
|
78
|
+
│ ├── bin/ # CLI entrypoints
|
|
79
|
+
│ └── src/ # Bridge runtime, git/workspace handlers, refresh helpers
|
|
80
|
+
├── CodexMobile/ # Xcode project root
|
|
81
|
+
│ ├── CodexMobile/ # App source target
|
|
82
|
+
│ │ ├── Services/ # Connection, sync, incoming-event, git, and persistence logic
|
|
83
|
+
│ │ ├── Views/ # SwiftUI screens and timeline/sidebar components
|
|
84
|
+
│ │ ├── Models/ # RPC, thread, message, and UI models
|
|
85
|
+
│ │ └── Assets.xcassets/ # App icons and UI assets
|
|
86
|
+
│ ├── CodexMobileTests/ # Unit tests
|
|
87
|
+
│ ├── CodexMobileUITests/ # UI tests
|
|
88
|
+
│ └── BuildSupport/ # Info.plist, xcconfig defaults, and local override templates
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Prerequisites
|
|
92
|
+
|
|
93
|
+
- **Node.js** v18+
|
|
94
|
+
- **[Codex CLI](https://github.com/openai/codex)** installed and in your PATH
|
|
95
|
+
- **[Codex desktop app](https://openai.com/index/codex/)** (optional — for viewing threads on your host computer)
|
|
96
|
+
- **A Codex iOS build** installed on your iPhone or iPad before scanning the pairing QR
|
|
97
|
+
- **macOS** (for desktop refresh features — the core bridge works on any OS)
|
|
98
|
+
- **Xcode 16+** (only if building the iOS app from source)
|
|
99
|
+
|
|
100
|
+
## Install the Bridge
|
|
101
|
+
|
|
102
|
+
<sub>Install from npm with `@latest` so you get the newest bridge fixes.</sub>
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
npm install -g @btatum5/codex-bridge@latest
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
To update an existing global install later:
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
npm install -g @btatum5/codex-bridge@latest
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
If you only want to try Codex, you can install it from npm and run it without cloning this repository.
|
|
115
|
+
|
|
116
|
+
## Quick Start
|
|
117
|
+
|
|
118
|
+
Install the bridge, then run:
|
|
2
119
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Run
|
|
6
|
-
|
|
7
|
-
The publishable npm package for this scaffold is `@btatum5/codex-bridge`. After publishing, you can install and run it with:
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npm install -g @btatum5/codex-bridge
|
|
120
|
+
```sh
|
|
11
121
|
codex-bridge up
|
|
12
122
|
```
|
|
13
123
|
|
|
14
|
-
|
|
124
|
+
If you are running from a source checkout on Windows, use `.\run-local-codex.ps1` from the repo root instead so the local relay starts and the pairing QR can be generated automatically.
|
|
15
125
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
126
|
+
On first connect, open the Codex app, follow the onboarding flow, then scan the QR code from inside the app.
|
|
127
|
+
|
|
128
|
+
After that first scan:
|
|
129
|
+
|
|
130
|
+
- the iPhone saves the host as a trusted device
|
|
131
|
+
- the host bridge keeps its identity locally
|
|
132
|
+
- the app tries trusted reconnect automatically on later launches
|
|
133
|
+
- the QR remains available as a recovery path if trust changes or the relay cannot resolve the live session
|
|
134
|
+
|
|
135
|
+
For now, the daemon-backed trusted reconnect path is macOS-only. If you self-host on Linux or Windows, pairing still works, but the bridge runs in the foreground unless you set up your own OS-specific service wrapper.
|
|
136
|
+
|
|
137
|
+
## Run Locally
|
|
138
|
+
|
|
139
|
+
```sh
|
|
140
|
+
git clone https://github.com/NightVibes3/Codex-iOS.git
|
|
141
|
+
cd Codex-iOS
|
|
142
|
+
./run-local-codex.sh
|
|
19
143
|
```
|
|
20
144
|
|
|
21
|
-
|
|
145
|
+
On Windows, use:
|
|
22
146
|
|
|
23
147
|
```powershell
|
|
24
148
|
.\run-local-codex.ps1
|
|
25
149
|
```
|
|
26
150
|
|
|
27
|
-
|
|
151
|
+
On Windows PowerShell, use:
|
|
28
152
|
|
|
29
|
-
|
|
153
|
+
```powershell
|
|
154
|
+
.\run-local-codex.ps1
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
That launcher starts a local relay, points the bridge at `ws://<your-host>:9000/relay`, and prints the pairing QR for the iPhone app.
|
|
158
|
+
|
|
159
|
+
For iPhone self-hosting, the recommended path is Tailscale or another stable private network. Plain LAN pairing over `ws://<lan-ip>` on the same Wi-Fi is still available for local testing, but it can be unreliable on some iOS devices even when the relay and Wi-Fi are healthy.
|
|
160
|
+
|
|
161
|
+
Options:
|
|
162
|
+
|
|
163
|
+
- `./run-local-codex.sh --hostname <lan-hostname-or-ip>`
|
|
164
|
+
- `./run-local-codex.sh --bind-host 127.0.0.1 --port 9100`
|
|
165
|
+
|
|
166
|
+
If your iPhone is pairing over LAN, use a hostname or IP the phone can actually reach.
|
|
167
|
+
|
|
168
|
+
## Custom Relay Endpoint
|
|
169
|
+
|
|
170
|
+
For a full public self-hosting walkthrough, see [`Docs/self-hosting.md`](Docs/self-hosting.md).
|
|
171
|
+
|
|
172
|
+
If you want the npm bridge to point at your own setup instead of the package default, override `CODEX_BRIDGE_RELAY` explicitly:
|
|
173
|
+
|
|
174
|
+
```sh
|
|
175
|
+
CODEX_BRIDGE_RELAY="ws://localhost:9000/relay" codex-bridge up
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
For self-hosted iPhone usage, prefer a relay URL reachable over Tailscale or another stable private network. Treat plain local `ws://192.168.x.x` pairing as best-effort rather than the recommended production path on iOS.
|
|
179
|
+
|
|
180
|
+
A common private setup looks like this:
|
|
181
|
+
|
|
182
|
+
1. Run the relay on your host computer, a mini server, or a VPS you control
|
|
183
|
+
2. Put that machine on Tailscale
|
|
184
|
+
3. Set `CODEX_BRIDGE_RELAY` to the Tailscale-reachable `ws://` or `wss://` relay URL
|
|
185
|
+
4. Pair once with QR
|
|
186
|
+
5. Let the iPhone reconnect to the same trusted host over that relay later
|
|
187
|
+
|
|
188
|
+
If that relay is fronting a Mac bridge, the macOS daemon can keep the bridge alive for hands-free reconnects. If you self-host against a non-macOS bridge, the same relay path still works, but automatic background service management is not built in yet.
|
|
189
|
+
|
|
190
|
+
Reverse-proxy subpaths work too, so a hosted relay behind Traefik can live under the same domain as other APIs:
|
|
191
|
+
|
|
192
|
+
```sh
|
|
193
|
+
CODEX_BRIDGE_RELAY="wss://api.example.com/codex/relay" codex-bridge up
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
In that setup, the public endpoints can look like this:
|
|
197
|
+
|
|
198
|
+
- `wss://api.example.com/codex/relay`
|
|
199
|
+
- `https://api.example.com/codex/v1/push/session/register-device`
|
|
200
|
+
- `https://api.example.com/codex/v1/push/session/notify-completion`
|
|
201
|
+
|
|
202
|
+
Have the proxy strip `/codex` before forwarding so the relay still receives `/relay/...` and `/v1/push/...`.
|
|
203
|
+
|
|
204
|
+
If you point `CODEX_BRIDGE_RELAY` at your own self-hosted relay, managed push stays off unless you also set `CODEX_BRIDGE_PUSH_SERVICE_URL` on the bridge and explicitly enable push on the relay.
|
|
205
|
+
|
|
206
|
+
## Publish to npm
|
|
207
|
+
|
|
208
|
+
Published npm packages can embed default private relay settings at pack time via the `prepack` script.
|
|
209
|
+
|
|
210
|
+
To publish the bridge with `relay.example` as the default relay:
|
|
211
|
+
|
|
212
|
+
```sh
|
|
213
|
+
cd codex-bridge
|
|
214
|
+
npm login
|
|
215
|
+
CODEX_BRIDGE_PACKAGE_DEFAULT_RELAY_URL="wss://relay.example/relay" \
|
|
216
|
+
npm publish
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
After publish, users can still override the packaged default at runtime with `CODEX_BRIDGE_RELAY`.
|
|
220
|
+
|
|
221
|
+
You can also run the bridge from source:
|
|
222
|
+
|
|
223
|
+
```sh
|
|
224
|
+
cd codex-bridge
|
|
225
|
+
npm install
|
|
226
|
+
CODEX_BRIDGE_RELAY="ws://localhost:9000/relay" npm start
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Commands
|
|
230
|
+
|
|
231
|
+
### `codex-bridge up`
|
|
232
|
+
|
|
233
|
+
Starts Codex.
|
|
234
|
+
|
|
235
|
+
On macOS, `codex-bridge up` is the friendly entrypoint for the background bridge service:
|
|
236
|
+
|
|
237
|
+
- Writes the daemon config used by the `launchd` service
|
|
238
|
+
- Starts or restarts the background bridge service
|
|
239
|
+
- Waits for a pairing payload and prints a QR for first-time trust or recovery
|
|
240
|
+
- Keeps the bridge alive even if you close the terminal later
|
|
241
|
+
|
|
242
|
+
On non-macOS platforms, `codex-bridge up` runs the bridge in the foreground.
|
|
243
|
+
|
|
244
|
+
In both cases the bridge:
|
|
245
|
+
|
|
246
|
+
- Spawns `codex app-server` (or connects to an existing endpoint)
|
|
247
|
+
- Connects the host bridge to the configured relay
|
|
248
|
+
- Forwards JSON-RPC messages bidirectionally
|
|
249
|
+
- Handles git commands from the phone
|
|
250
|
+
- Persists the active thread for later resumption
|
|
251
|
+
|
|
252
|
+
### `codex-bridge start`
|
|
253
|
+
|
|
254
|
+
macOS only. Starts the background bridge service without waiting for or printing a QR in the current terminal.
|
|
255
|
+
|
|
256
|
+
### `codex-bridge stop`
|
|
257
|
+
|
|
258
|
+
macOS only. Stops the background bridge service and clears its transient runtime status.
|
|
259
|
+
|
|
260
|
+
### `codex-bridge status`
|
|
261
|
+
|
|
262
|
+
macOS only. Prints the current `launchd` / bridge status, including whether the service is loaded and whether a recent pairing payload exists.
|
|
263
|
+
|
|
264
|
+
### `codex-bridge run-service`
|
|
265
|
+
|
|
266
|
+
macOS only. Internal service entrypoint used by `launchd`. You normally do not run this manually.
|
|
267
|
+
|
|
268
|
+
### `codex-bridge --version`
|
|
269
|
+
|
|
270
|
+
Prints the installed Codex CLI version.
|
|
271
|
+
|
|
272
|
+
```sh
|
|
273
|
+
codex-bridge --version
|
|
274
|
+
# => 1.3.2
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### `codex-bridge reset-pairing`
|
|
278
|
+
|
|
279
|
+
Clears the saved bridge pairing state so the next trusted connection requires a fresh QR bootstrap again.
|
|
280
|
+
You normally do not need this for corrupted local state anymore: recent Codex builds auto-repair unreadable pairing files/mirrors on startup.
|
|
281
|
+
|
|
282
|
+
```sh
|
|
283
|
+
codex-bridge reset-pairing
|
|
284
|
+
# => [codex-bridge] Cleared the saved pairing state. Run `codex-bridge up` to pair again.
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### `codex-bridge resume`
|
|
288
|
+
|
|
289
|
+
Reopens the last active thread in Codex.app on your Mac.
|
|
290
|
+
|
|
291
|
+
```sh
|
|
292
|
+
codex-bridge resume
|
|
293
|
+
# => [codex-bridge] Opened last active thread: abc-123 (phone)
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### `codex-bridge watch [threadId]`
|
|
297
|
+
|
|
298
|
+
Tails the event log for a thread in real-time.
|
|
299
|
+
|
|
300
|
+
```sh
|
|
301
|
+
codex-bridge watch
|
|
302
|
+
# => [14:32:01] Phone: "Fix the login bug in auth.ts"
|
|
303
|
+
# => [14:32:05] Codex: "I'll look at auth.ts and fix the login..."
|
|
304
|
+
# => [14:32:18] Task started
|
|
305
|
+
# => [14:33:42] Task complete
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## Environment Variables
|
|
309
|
+
|
|
310
|
+
`CODEX_BRIDGE_RELAY` is optional, but the default depends on how you got Codex:
|
|
311
|
+
|
|
312
|
+
- public GitHub/source checkouts stay open-source and self-host friendly, so they do not ship with a hosted relay baked in
|
|
313
|
+
- official published packages may include a default relay at publish time
|
|
314
|
+
- if you are running from source, assume you should use `./run-local-codex.sh` or set `CODEX_BRIDGE_RELAY` yourself
|
|
315
|
+
|
|
316
|
+
| Variable | Default | Description |
|
|
317
|
+
|----------|---------|-------------|
|
|
318
|
+
| `CODEX_BRIDGE_RELAY` | empty in source checkouts; optional in published packages | Session base URL used for QR bootstrap, trusted-session resolve, and phone/host session routing |
|
|
319
|
+
| `CODEX_BRIDGE_PUSH_SERVICE_URL` | disabled by default | Optional HTTP base URL for managed push registration/completion |
|
|
320
|
+
| `CODEX_BRIDGE_CODEX_ENDPOINT` | — | Connect to an existing Codex WebSocket instead of spawning a local `codex app-server` |
|
|
321
|
+
| `CODEX_BRIDGE_REFRESH_ENABLED` | `false` | Auto-refresh Codex.app when phone activity is detected (`true` enables it explicitly) |
|
|
322
|
+
| `CODEX_BRIDGE_REFRESH_DEBOUNCE_MS` | `1200` | Debounce window (ms) for coalescing refresh events |
|
|
323
|
+
| `CODEX_BRIDGE_REFRESH_COMMAND` | — | Custom shell command to run instead of the built-in AppleScript refresh |
|
|
324
|
+
| `CODEX_BRIDGE_CODEX_BUNDLE_ID` | `com.openai.codex` | macOS bundle ID of the Codex app |
|
|
325
|
+
| `CODEX_HOME` | `~/.codex` | Codex data directory (used here for `sessions/` rollout files) |
|
|
326
|
+
|
|
327
|
+
```sh
|
|
328
|
+
# Enable desktop refresh explicitly
|
|
329
|
+
CODEX_BRIDGE_REFRESH_ENABLED=true codex-bridge up
|
|
330
|
+
|
|
331
|
+
# Connect to an existing Codex instance
|
|
332
|
+
CODEX_BRIDGE_CODEX_ENDPOINT=ws://localhost:8080 codex-bridge up
|
|
333
|
+
|
|
334
|
+
# Use a custom self-hosted relay endpoint (`ws://` is unencrypted)
|
|
335
|
+
CODEX_BRIDGE_RELAY="ws://localhost:9000/relay" codex-bridge up
|
|
336
|
+
|
|
337
|
+
# Enable managed push only if your self-hosted relay also exposes a configured APNs push service
|
|
338
|
+
CODEX_BRIDGE_RELAY="wss://relay.example/relay" \
|
|
339
|
+
CODEX_BRIDGE_PUSH_SERVICE_URL="https://relay.example" \
|
|
340
|
+
codex-bridge up
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
On the relay/VPS side, keep push disabled until you actually want it. The HTTP push endpoints are off by default and only turn on when you set `CODEX_BRIDGE_ENABLE_PUSH_SERVICE=true`.
|
|
344
|
+
|
|
345
|
+
## Pairing and Safety
|
|
346
|
+
|
|
347
|
+
- Codex is local-first: Codex, git operations, and workspace actions run on your host computer, while the iPhone acts as a paired remote control.
|
|
348
|
+
- On iPhone, the most reliable self-host setup is a Tailscale-reachable relay. Plain LAN pairing over `ws://` on the same Wi-Fi can fail on some iOS devices because local-network routing from the app is not always reliable.
|
|
349
|
+
- The pairing QR carries the connection URL, the session ID, and the bridge identity key used to bootstrap end-to-end encryption. After a successful first scan, the iPhone stores a trusted host record in Keychain and the bridge persists its trusted phone identity locally on the host computer.
|
|
350
|
+
- On macOS, the bridge can keep running as a lightweight `launchd` service, so the phone can resolve the host's current live relay session and reconnect without scanning a new QR every time.
|
|
351
|
+
- The QR is still the recovery path when trust changes, the bridge identity rotates, or the relay cannot resolve the current live session.
|
|
352
|
+
- The bridge state lives canonically in `~/.codex/device-state.json` with local-only permissions. On macOS the bridge also mirrors that state to Keychain as best-effort backup/migration data, and recent builds auto-repair unreadable local state on startup instead of requiring manual cleanup.
|
|
353
|
+
- The CLI no longer prints the connection URL in plain text below the QR.
|
|
354
|
+
- Set `CODEX_BRIDGE_RELAY` only when you want to self-host or test locally against your own setup.
|
|
355
|
+
- Leave `CODEX_BRIDGE_TRUST_PROXY` unset for direct/self-hosted installs. Turn it on only when a trusted reverse proxy such as Traefik, Nginx, or Caddy is forwarding the relay traffic.
|
|
356
|
+
- The transport implementation is public in [`relay/`](relay/), but your real deployed hostname and credentials should stay private.
|
|
357
|
+
- On the iPhone, the default agent permission mode is `On-Request`. Switching the app to `Full access` auto-approves runtime approval prompts from the agent.
|
|
358
|
+
|
|
359
|
+
## Security and Privacy
|
|
360
|
+
|
|
361
|
+
Codex now uses an authenticated end-to-end encrypted channel between the paired iPhone and the bridge running on your host computer. The transport layer still carries the WebSocket traffic, but it does not get the plaintext contents of prompts, tool calls, Codex responses, git output, or workspace RPC payloads once the secure session is established.
|
|
362
|
+
|
|
363
|
+
The secure channel is built in these steps:
|
|
364
|
+
|
|
365
|
+
1. The bridge generates and persists a long-term device identity keypair on the host computer.
|
|
366
|
+
2. The pairing QR shares the connection URL, session ID, bridge device ID, bridge identity public key, and a short expiry window.
|
|
367
|
+
3. During pairing, the iPhone and bridge exchange fresh X25519 ephemeral keys and nonces.
|
|
368
|
+
4. The bridge signs the handshake transcript with its Ed25519 identity key, and the iPhone verifies that signature against the public key from the QR code or the previously trusted host record.
|
|
369
|
+
5. The iPhone signs a client-auth transcript with its own Ed25519 identity key, and the bridge verifies that before accepting the session.
|
|
370
|
+
6. Both sides derive directional AES-256-GCM keys with HKDF-SHA256 and then wrap application messages in encrypted envelopes with monotonic counters for replay protection.
|
|
371
|
+
|
|
372
|
+
Privacy notes:
|
|
373
|
+
|
|
374
|
+
- The transport layer can still see connection metadata and the plaintext secure control messages used to set up the encrypted session, including session IDs, device IDs, public keys, nonces, and handshake result codes.
|
|
375
|
+
- The transport layer does not see decrypted application payloads after the secure handshake succeeds.
|
|
376
|
+
- A fresh QR scan can replace the previously trusted iPhone automatically. Use `codex-bridge reset-pairing` only when you intentionally want to wipe the remembered pairing state yourself.
|
|
377
|
+
- On-device message history is also encrypted at rest on iPhone using a Keychain-backed AES key.
|
|
378
|
+
|
|
379
|
+
## Git Integration
|
|
380
|
+
|
|
381
|
+
The bridge intercepts `git/*` JSON-RPC calls from the phone and executes them locally:
|
|
382
|
+
|
|
383
|
+
| Command | Description |
|
|
384
|
+
|---------|-------------|
|
|
385
|
+
| `git/status` | Branch, tracking info, dirty state, file list, and diff |
|
|
386
|
+
| `git/commit` | Commit staged changes with an optional message |
|
|
387
|
+
| `git/push` | Push to remote |
|
|
388
|
+
| `git/pull` | Pull from remote (auto-aborts on conflict) |
|
|
389
|
+
| `git/branches` | List all branches with current/default markers |
|
|
390
|
+
| `git/checkout` | Switch branches |
|
|
391
|
+
| `git/createBranch` | Create and switch to a new branch |
|
|
392
|
+
| `git/log` | Recent commit history |
|
|
393
|
+
| `git/stash` | Stash working changes |
|
|
394
|
+
| `git/stashPop` | Pop the latest stash |
|
|
395
|
+
| `git/resetToRemote` | Hard reset to remote (requires confirmation) |
|
|
396
|
+
| `git/remoteUrl` | Get the remote URL and owner/repo |
|
|
397
|
+
|
|
398
|
+
## Workspace Integration
|
|
399
|
+
|
|
400
|
+
The bridge also handles local workspace-scoped revert operations for the assistant revert flow:
|
|
401
|
+
|
|
402
|
+
| Command | Description |
|
|
403
|
+
|---------|-------------|
|
|
404
|
+
| `workspace/revertPatchPreview` | Checks whether a reverse patch can be applied cleanly in the local repo |
|
|
405
|
+
| `workspace/revertPatchApply` | Applies the reverse patch locally when the preview succeeds |
|
|
406
|
+
|
|
407
|
+
## Codex Desktop App Integration
|
|
408
|
+
|
|
409
|
+
Codex works with both the Codex CLI and the Codex desktop app (`Codex.app`). Under the hood, the bridge spawns a `codex app-server` process — the same JSON-RPC interface that powers the desktop app and IDE extensions. Conversations are persisted as JSONL rollout files under `~/.codex/sessions`, so threads started from your phone show up in the desktop app too.
|
|
410
|
+
|
|
411
|
+
What is live today:
|
|
412
|
+
|
|
413
|
+
- The iPhone conversation is live while the bridge session is connected.
|
|
414
|
+
- The host-side Codex runtime is the real runtime doing the work.
|
|
415
|
+
|
|
416
|
+
What is not fully live today:
|
|
417
|
+
|
|
418
|
+
- `Codex.app` does not act like a second live subscriber to the active run by default.
|
|
419
|
+
- The desktop app catches up from the persisted session files and can be nudged with the optional refresh workaround below.
|
|
420
|
+
- True phone-to-desktop live sync in the `Codex.app` GUI is not supported today.
|
|
421
|
+
|
|
422
|
+
To make that limitation more practical, the iPhone app includes a `Hand off to desktop app` action. On macOS, it lets you explicitly continue the current chat by opening the matching thread in `Codex.app` when you are ready to switch devices.
|
|
423
|
+
|
|
424
|
+
**Known limitation**: The Codex desktop app does not live-reload when an external `app-server` process writes new data to disk. Threads created or updated from your phone won't appear in the desktop app until it remounts that route. Codex keeps desktop refresh off by default for now because the current deep-link bounce is still disruptive. You can still enable it manually if you want the old remount workaround.
|
|
425
|
+
|
|
426
|
+
```sh
|
|
427
|
+
# Enable the old deep-link refresh workaround manually
|
|
428
|
+
CODEX_BRIDGE_REFRESH_ENABLED=true codex-bridge up
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
This triggers a debounced deep-link bounce (`codex://settings` → `codex://threads/<id>`) that forces the desktop app to remount the current thread without interrupting any running tasks. While a turn is running, Codex also watches the persisted rollout for that thread and issues occasional throttled refreshes so long responses become visible in the desktop app on macOS without a full app relaunch. If the local desktop path is unavailable, the bridge self-disables desktop refresh for the rest of that run instead of retrying noisily forever.
|
|
432
|
+
|
|
433
|
+
## Connection Resilience
|
|
434
|
+
|
|
435
|
+
- **Auto-reconnect**: If the session connection drops, the bridge reconnects with exponential backoff (1 s → 5 s max)
|
|
436
|
+
- **Secure catch-up**: The bridge keeps a bounded local outbound buffer and re-sends missed encrypted messages after a secure reconnect
|
|
437
|
+
- **Codex persistence**: The Codex process stays alive across transient session reconnects during the current bridge run
|
|
438
|
+
- **Graceful shutdown**: SIGINT/SIGTERM cleanly close all connections
|
|
439
|
+
|
|
440
|
+
## Building the iOS App
|
|
30
441
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
- `POST /v1/companion/chat`
|
|
442
|
+
```sh
|
|
443
|
+
cd CodexMobile
|
|
444
|
+
open CodexMobile.xcodeproj
|
|
445
|
+
```
|
|
36
446
|
|
|
37
|
-
|
|
447
|
+
Build and run on a physical device or simulator with Xcode. The app uses SwiftUI and the current project target is iOS 26.2.
|
|
38
448
|
|
|
39
|
-
|
|
449
|
+
For unsigned device artifacts, use `.github/workflows/ios-unsigned-ipa.yml`. It builds `CodexMobile` for `generic/platform=iOS`, disables signing, packages the `.app` into an unsigned `.ipa`, and uploads it as an artifact for SideStore-style signing/sideloading.
|
|
450
|
+
|
|
451
|
+
## Contributing
|
|
452
|
+
|
|
453
|
+
I'm not actively accepting contributions yet. See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
|
|
454
|
+
|
|
455
|
+
## FAQ
|
|
456
|
+
|
|
457
|
+
**Do I need an OpenAI API key?**
|
|
458
|
+
Not for Codex itself. You need Codex CLI set up and working independently.
|
|
459
|
+
|
|
460
|
+
**Does this work on Linux/Windows?**
|
|
461
|
+
The core bridge client (Codex forwarding + git) works on any OS. Desktop refresh (AppleScript) is macOS-only, and the built-in daemon / trusted auto-reconnect service path is currently macOS-only too.
|
|
462
|
+
|
|
463
|
+
**What happens if I close the terminal?**
|
|
464
|
+
On macOS, the bridge can keep running in the background through `launchd`, so closing the terminal does not stop the trusted reconnect path. On other OSes, the foreground bridge stops when the terminal stops.
|
|
465
|
+
|
|
466
|
+
**How do I force a fresh QR pairing?**
|
|
467
|
+
Run `codex-bridge reset-pairing`, then start the bridge again with `codex-bridge up`. You should only need this when you intentionally want to replace the paired iPhone or wipe the remembered pairing.
|
|
468
|
+
|
|
469
|
+
**Can I connect to a remote Codex instance?**
|
|
470
|
+
Yes — set `CODEX_BRIDGE_CODEX_ENDPOINT=ws://host:port` to skip spawning a local `codex app-server`.
|
|
471
|
+
|
|
472
|
+
**Why don't my phone threads show up in the Codex desktop app immediately?**
|
|
473
|
+
The desktop app reads session data from disk (`~/.codex/sessions`) but doesn't live-reload when an external process writes new data. Your phone still gets the live stream; it is the desktop GUI that lags unless you explicitly enable the refresh workaround with `CODEX_BRIDGE_REFRESH_ENABLED=true`.
|
|
474
|
+
|
|
475
|
+
**Does Codex support true live sync between phone and `Codex.app`?**
|
|
476
|
+
No. The phone session is live, but the `Codex.app` GUI is not a true live mirror of the active run. To help with that, the iPhone app includes a `Hand off to desktop app` action so you can explicitly continue the same thread in `Codex.app` on macOS.
|
|
477
|
+
|
|
478
|
+
**Can I self-host the relay?**
|
|
479
|
+
Yes. That is the intended forking path. The transport and push-service code are in [`relay/`](relay/); point `CODEX_BRIDGE_RELAY` at the instance you run.
|
|
480
|
+
|
|
481
|
+
**Can I use Tailscale?**
|
|
482
|
+
Yes. It is the recommended private-network option for self-hosting on iPhone. Run your relay somewhere reachable over Tailscale, set `CODEX_BRIDGE_RELAY` to that relay URL, pair once with QR, then let the app reconnect to the trusted host through the same relay.
|
|
483
|
+
|
|
484
|
+
**Is the transport layer safe for sensitive work?**
|
|
485
|
+
It is much stronger than a plain text proxy: traffic can be protected in transit with TLS, application payloads are end-to-end encrypted after the secure handshake, and all Codex execution still happens on your host computer. The transport can still observe connection metadata and handshake control messages, so the tightest trust model is to run it yourself.
|
|
486
|
+
|
|
487
|
+
## License
|
|
488
|
+
|
|
489
|
+
[ISC](LICENSE)
|