Codex Desktop SSH restart disables mobile remote control by restarting app-server without --remote-control
What version of the Codex App are you using (From "About Codex" dialog)?
Codex App 26.513.31313 (2867)
Remote host Codex CLI/App Server:
codex-cli 0.132.0
What subscription do you have?
ChatGPT Pro, 5x plan. Signed in on both Codex Desktop and the ChatGPT mobile app.
What platform is your computer?
Local Codex Desktop host:
Darwin 25.4.0 arm64 arm
Remote SSH host:
Linux 5.15.120.bsk.3-amd64 x86_64 unknown
What issue are you seeing?
I am using Codex Desktop on macOS with an SSH remote host, and I want the ChatGPT mobile app to connect to/control the remote host.
The mobile remote-control path works if I manually start the new remote-control daemon entrypoint on the remote host:
~/.codex/packages/standalone/current/codex remote-control start
After that, the remote host has the expected process:
codex app-server --remote-control --listen unix://
codex app-server daemon pid-update-loop
The ChatGPT Android app can then reach the remote app-server. The remote app-server logs show requests from:
app_server.client_name="codex_chatgpt_android_remote"
However, two Codex Desktop UI actions appear to use stale/non-remote-control paths:
- In Settings -> Connections -> SSH -> remote host details, the
Available from signed-in devicestoggle turns on briefly and then immediately turns itself off. - If I use the Codex Desktop UI to restart Codex on the SSH remote host, the mobile app can no longer connect. After the restart, the remote host is running a plain app-server process without
--remote-control:
codex app-server --listen unix://
At the same time, the remote daemon settings still say remote control is enabled:
{
"remoteControlEnabled": true
}
The remote config also contains:
[features]
remote_control = true
But codex features list on the remote host reports:
remote_control removed false
This makes the UI state confusing: the actual remote-control daemon can work, but the Desktop UI toggle still reads as disabled, and the Desktop restart action replaces the working remote-control app-server with a non-remote-control app-server.
What steps can reproduce the bug?
- Use Codex Desktop on macOS and add an SSH remote host.
- On the remote host, use Codex CLI/App Server 0.132.0.
- Start remote control manually on the remote host:
``sh``
~/.codex/packages/standalone/current/codex remote-control start
- Verify the remote host is running:
``text``
codex app-server --remote-control --listen unix://
- Verify the ChatGPT mobile app can connect to the remote host.
- Open Codex Desktop Settings -> Connections -> SSH -> remote host details.
- Try to enable
Available from signed-in devices. - Observe that the toggle immediately turns itself back off.
- Use Codex Desktop's UI action to restart Codex on the SSH remote host.
- Check the remote host processes again.
Actual result after Desktop restart:
codex app-server --listen unix://
Expected process would preserve remote-control mode:
codex app-server --remote-control --listen unix://
What is the expected behavior?
- If the new supported path is
codex remote-control start, Codex Desktop's SSH remote restart action should preserve/restart the remote host in remote-control mode when remote control is enabled. - The
Available from signed-in devicestoggle should reflect the daemon/settings state that actually controls mobile remote access, instead of reading a removed feature flag as disabled. - The UI should not report the remote host as unavailable from signed-in devices when mobile remote-control is actually enabled and working.
Additional information
This may be related to the transition from the old [features].remote_control flag to the newer codex remote-control start / app-server daemon flow.
Relevant observed facts:
codex features list:
remote_control removed false
~/.codex/app-server-daemon/settings.json:
{
"remoteControlEnabled": true
}
After manual codex remote-control start, mobile remote control works. After Codex Desktop remote restart, the remote-control flag disappears from the app-server process and mobile remote control stops working.
I am omitting the concrete SSH hostname/IP/account/server IDs from this report.
5 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
This feels like a control-plane contract bug more than an SSH bug.
If remote control depends on
--remote-control, the restart path should either preserve that flag from the live session config or refuse a restart that would downgrade capabilities. Otherwise the app-server comes back "healthy" but with a different authority boundary than the user actually started with.A useful fix pattern here is to persist the restart receipt alongside the session: previous flags, new flags, and any capability delta. That makes this kind of regression obvious instead of looking like mobile control randomly died.
The strongest signal here is the mismatch between persisted intent and restarted process shape.
remoteControlEnabled: truesays the daemon should be reachable from signed-in devices, but the restart path brings backapp-serverwithout--remote-control. That makes the host locally healthy while silently losing the mobile-control capability that the user explicitly enabled.A useful invariant would be: any UI restart action must either preserve the active capability set or return a visible capability downgrade error before stopping the working daemon. The post-restart process flags should be part of the user-visible connection state, because otherwise the mobile app just sees a host that stopped working for no obvious reason.
Yes, and I would make that capability delta machine-readable rather than only human-visible.\n\nSomething like a restart receipt with:\n\n- previous launch flags\n- new launch flags\n- dropped capabilities\n- reason for the restart\n- whether the restart was allowed to proceed despite the downgrade\n\nThat gives the UI one honest state transition to show: healthy with preserved capabilities versus healthy but degraded. Right now the problem is not just that remote control breaks, it is that the restart path makes the downgrade look like success.
I believe I'm seeing a current variant of this issue with
codex-cli 0.147.0.Environment
Remote host:
The machine is a headless Linux host accessed by Codex clients over SSH. I also use ChatGPT on Android to access it via Codex Remote Control.
Symptoms
The Android app would remain indefinitely at Pending when attempting to connect to the remote host.
Interestingly:
reported successful pairing.
However:
failed with:
Existing app-server
The host had these processes:
The first process belonged to an SSH login session.
systemctl status <pid>showed:with the Codex process still inside the session cgroup:
The corresponding SSH connection itself had already disconnected.
I suspect this may be intentional behavior used by Codex clients to allow reconnection to an SSH-hosted app-server rather than simply an accidentally orphaned process.
Remote-control logs
The remote-control transport itself initialized without WARN or ERROR entries.
Relevant sequence:
It remained in
Connecting.The persisted enrollment was recognized, so I did not clear authentication, enrollment, or Codex state.
Recovery
I terminated the SSH session scope containing:
After removing that app-server, the Android client connected successfully without re-pairing, changing authentication, or resetting the remote-control enrollment.
This gives a fairly clean A/B reproduction:
Possible underlying issue
This looks like an ownership/coexistence problem between the SSH code-mode host and the newer daemon-managed Remote Control path.
In particular, an SSH client can apparently leave/reuse:
while Remote Control expects the active app-server to be managed by
codex app-server daemon.Ideally an SSH-hosted Codex server and Remote Control would either:
The current behavior makes Remote Control silently appear broken from the Android side (
Pending) even though pairing succeeds, while the actionable ownership error is only visible when runningcodex remote-control startdirectly on the host.