Client or integration
OpenCodex dashboard with Codex Desktop.
Area
Dashboard / service lifecycle / Codex config restore.
Summary
On macOS with the launchd background service installed, pressing the dashboard Stop proxy button stopped the proxy and made the dashboard unreachable, but left Codex routed to http://127.0.0.1:10100/v1. Codex then could not send requests until the proxy was manually started again.
The current POST /api/stop control flow appears vulnerable to terminating its own process before shared teardown completes:
stopServiceIfInstalledDetailed() is called.
- On macOS it synchronously invokes
launchctl unload for the LaunchAgent.
- Only after that returns does the handler await
performStopTeardown(), which calls the native Codex restore path.
Because the API handler runs inside the launchd-managed proxy process, unloading its own job can terminate it before step 3 finishes. This matches the observed state: the listener and dashboard were gone, while openai_base_url, experimental_realtime_ws_base_url, and model_catalog_json remained injected in the Codex config.
This ordering is still present in tag v2.48.0 at src/server/management-api.ts around lines 275-348 and src/service.ts around lines 2351 and 3927-3932.
Expected: dashboard Stop must restore native Codex and verify the restore before allowing launchd to terminate the proxy, or delegate the complete stop to an external process that survives unloading the service. If safe completion cannot be guaranteed, the dashboard should refuse and instruct the user to run ocx stop, similar to the existing Task Scheduler protection.
Reproduction
- On macOS, install and run OpenCodex as a launchd background service.
- Confirm Codex routing is injected and the dashboard is available on port 10100.
- Press Stop proxy in the dashboard and confirm.
- Observe that the proxy and dashboard stop.
- Inspect the effective Codex
config.toml.
- Observe that the loopback routing keys may remain, leaving Codex pointed to the stopped proxy.
- Start the proxy again; Codex requests work again because the stale route becomes reachable.
Version
Observed on 2.42.0. Source ordering verified unchanged in tag 2.48.0.
Operating system
macOS, Apple Silicon, launchd user service.
Provider and model
Not provider-specific.
Logs or error output
After manually starting the proxy again, the service log reported that the previous session did not shut down cleanly and restored Codex state from the journal. There was no successful native-restore message associated with the dashboard stop.
Screenshots and supporting files
Relevant source:
Related but not duplicate:
Redacted configuration
openai_base_url = "http://127.0.0.1:10100/v1"
experimental_realtime_ws_base_url = "http://127.0.0.1:10100/v1"
model_catalog_json = "/redacted/.codex/opencodex-catalog.json"
Checks
Client or integration
OpenCodex dashboard with Codex Desktop.
Area
Dashboard / service lifecycle / Codex config restore.
Summary
On macOS with the launchd background service installed, pressing the dashboard Stop proxy button stopped the proxy and made the dashboard unreachable, but left Codex routed to
http://127.0.0.1:10100/v1. Codex then could not send requests until the proxy was manually started again.The current
POST /api/stopcontrol flow appears vulnerable to terminating its own process before shared teardown completes:stopServiceIfInstalledDetailed()is called.launchctl unloadfor the LaunchAgent.performStopTeardown(), which calls the native Codex restore path.Because the API handler runs inside the launchd-managed proxy process, unloading its own job can terminate it before step 3 finishes. This matches the observed state: the listener and dashboard were gone, while
openai_base_url,experimental_realtime_ws_base_url, andmodel_catalog_jsonremained injected in the Codex config.This ordering is still present in tag
v2.48.0atsrc/server/management-api.tsaround lines 275-348 andsrc/service.tsaround lines 2351 and 3927-3932.Expected: dashboard Stop must restore native Codex and verify the restore before allowing launchd to terminate the proxy, or delegate the complete stop to an external process that survives unloading the service. If safe completion cannot be guaranteed, the dashboard should refuse and instruct the user to run
ocx stop, similar to the existing Task Scheduler protection.Reproduction
config.toml.Version
Observed on 2.42.0. Source ordering verified unchanged in tag 2.48.0.
Operating system
macOS, Apple Silicon, launchd user service.
Provider and model
Not provider-specific.
Logs or error output
After manually starting the proxy again, the service log reported that the previous session did not shut down cleanly and restored Codex state from the journal. There was no successful native-restore message associated with the dashboard stop.
Screenshots and supporting files
Relevant source:
Related but not duplicate:
Redacted configuration
Checks