mirror of
https://github.com/openai/codex.git
synced 2026-05-19 10:43:38 +00:00
## Why Desktop and mobile Codex clients need a machine-readable way to bootstrap and manage `codex app-server` on remote machines reached over SSH. The same flow is also useful for bringing up app-server with `remote_control` enabled on a fresh developer machine and keeping that managed install current without requiring a human session. ## What changed - add the new experimental `codex-app-server-daemon` crate and wire it into `codex app-server daemon` lifecycle commands: `start`, `restart`, `stop`, `version`, and `bootstrap` - add explicit `enable-remote-control` and `disable-remote-control` commands that persist the launch setting and restart a running managed daemon so the change takes effect immediately - emit JSON success responses for daemon commands so remote callers can consume them directly - support a Unix-only pidfile-backed detached backend for lifecycle management - assume the standalone `install.sh` layout for daemon-managed binaries and always launch `CODEX_HOME/packages/standalone/current/codex` - add bootstrap support for the standalone managed install plus a detached hourly updater loop - harden lifecycle management around concurrent operations, pidfile ownership, stale state cleanup, updater ownership, managed-binary preflight, Unix-only rejection, forced shutdown after the graceful window, and updater process-group tracking/cleanup - document the experimental Unix-only support boundary plus the standalone bootstrap/update flow in `codex-rs/app-server-daemon/README.md` ## Verification - `cargo test -p codex-app-server-daemon -p codex-cli` - live pid validation on `cb4`: `bootstrap --remote-control`, `restart`, `version`, `stop` ## Follow-up - Add updater self-refresh so the long-lived `pid-update-loop` can replace its own executable image after installing a newer managed Codex binary.
105 lines
4.7 KiB
Markdown
105 lines
4.7 KiB
Markdown
# codex-app-server-daemon
|
|
|
|
> `codex-app-server-daemon` is experimental and its lifecycle contract may
|
|
> change while the remote-management flow is still being developed.
|
|
|
|
`codex-app-server-daemon` backs the machine-readable `codex app-server`
|
|
lifecycle commands used by remote clients such as the desktop and mobile apps.
|
|
It is intended for Codex instances launched over SSH, including fresh developer
|
|
machines that should expose app-server with `remote_control` enabled.
|
|
|
|
## Platform support
|
|
|
|
The current daemon implementation is Unix-only. It uses pidfile-backed
|
|
daemonization plus Unix process and file-locking primitives, and does not yet
|
|
support Windows lifecycle management.
|
|
|
|
## Commands
|
|
|
|
```sh
|
|
codex app-server daemon start
|
|
codex app-server daemon restart
|
|
codex app-server daemon enable-remote-control
|
|
codex app-server daemon disable-remote-control
|
|
codex app-server daemon stop
|
|
codex app-server daemon version
|
|
codex app-server daemon bootstrap --remote-control
|
|
```
|
|
|
|
On success, every command writes exactly one JSON object to stdout. Consumers
|
|
should parse that JSON rather than relying on human-readable text. Lifecycle
|
|
responses report the resolved backend, socket path, local CLI version, and
|
|
running app-server version when applicable.
|
|
|
|
## Bootstrap flow
|
|
|
|
For a new remote machine:
|
|
|
|
```sh
|
|
curl -fsSL https://chatgpt.com/codex/install.sh | sh
|
|
$HOME/.codex/packages/standalone/current/codex app-server daemon bootstrap --remote-control
|
|
```
|
|
|
|
`bootstrap` requires the standalone managed install. It records the daemon
|
|
settings under `CODEX_HOME/app-server-daemon/`, starts app-server as a
|
|
pidfile-backed detached process, and launches a detached updater loop.
|
|
|
|
## Installation and update cases
|
|
|
|
The daemon assumes Codex is installed through `install.sh` and always launches
|
|
the standalone managed binary under `CODEX_HOME`.
|
|
|
|
| Situation | What starts | Does this daemon fetch new binaries? | Does a running app-server eventually move to a newer binary on its own? |
|
|
| --- | --- | --- | --- |
|
|
| `install.sh` has run, but only `start` is used | `start` uses `CODEX_HOME/packages/standalone/current/codex` | No | No. The managed path is used when starting or restarting, but no updater is installed. |
|
|
| `install.sh` has run, then `bootstrap` is used | The pidfile backend uses `CODEX_HOME/packages/standalone/current/codex` | Yes. Bootstrap launches a detached updater loop that runs `install.sh` hourly. | Yes, while that updater process is alive. After a successful fetch, it restarts a currently running app-server only when the managed binary reports a different version. |
|
|
| Some other tool updates the managed binary path | The next fresh start or restart uses the updated file at that path | No | Not automatically. The existing process keeps the old executable image until an explicit `restart`. |
|
|
|
|
### Standalone installs
|
|
|
|
For installs created by `install.sh`:
|
|
|
|
- lifecycle commands always use the standalone managed binary path
|
|
- `bootstrap` is supported
|
|
- `bootstrap` starts a detached pid-backed updater loop that fetches via
|
|
`install.sh`, then restarts app-server if it is running on a different version
|
|
- the updater loop is not reboot-persistent; it must be started again by
|
|
rerunning `bootstrap` after a reboot
|
|
|
|
### Out-of-band updates
|
|
|
|
This daemon does not watch arbitrary executable files for replacement. If some
|
|
other tool updates a binary that the daemon would use on its next launch:
|
|
|
|
- a currently running app-server remains on the old executable image
|
|
- `restart` will launch the updated binary
|
|
- for bootstrapped daemons, the detached updater loop only reacts to updates it
|
|
fetched itself; it does not watch arbitrary file replacement
|
|
|
|
## Lifecycle semantics
|
|
|
|
`start` is idempotent and returns after app-server is ready to answer the normal
|
|
JSON-RPC initialize handshake on the Unix control socket.
|
|
|
|
`restart` stops any managed daemon and starts it again.
|
|
|
|
`enable-remote-control` and `disable-remote-control` persist the launch setting
|
|
for future starts. If a managed app-server is already running, they restart it
|
|
so the new setting takes effect immediately.
|
|
|
|
`stop` sends a graceful termination request first, then sends a second
|
|
termination signal after the grace window if the process is still alive.
|
|
|
|
All mutating lifecycle commands are serialized per `CODEX_HOME`, so a concurrent
|
|
`start`, `restart`, `enable-remote-control`, `disable-remote-control`, `stop`,
|
|
or `bootstrap` does not race another in-flight lifecycle operation.
|
|
|
|
## State
|
|
|
|
The daemon stores its local state under `CODEX_HOME/app-server-daemon/`:
|
|
|
|
- `settings.json` for persisted launch settings
|
|
- `app-server.pid` for the app-server process record
|
|
- `app-server-updater.pid` for the pid-backed standalone updater loop
|
|
- `daemon.lock` for daemon-wide lifecycle serialization
|