All articles
Dev ToolsBy Petru Popa · 6 min read

Codex CLI Starts a Self-Updating Daemon by Default. The config.toml Switch Is Not in the Docs.

Since 0.157.0, an interactive Codex session can leave behind a background server and an hourly updater. The latest release, 0.162.1, still ships it on. The opt-out key is absent from OpenAI's config reference, and the org-wide pin lives in requirements.toml.

Codex CLI 0.157.0, released on 25 September, carried a one-line release note: automatic background-server startup is now enabled for eligible interactive sessions. Eleven stable releases later the default has not moved. In the source tagged for 0.162.1, published on 9 October and the current release, the feature registry lists daemon_auto_start as a stable feature with default_enabled: true. An issue asking to make it opt-in, opened the day the change shipped, is still open and drew a fresh run of comments on 12 October. A second report, filed today against 0.162.1, says the daemon leaks environment variables across sessions.

This post is about the codex config.toml line that turns it off, why that line alone does not clean up a machine, and why a team that rolls Codex out through a package manager should treat 0.157.0 as a change in what software it runs, not a CLI update.

What turned on in 0.157.0

The issue's reporter, on 0.157.0 installed with npm under WSL2, describes four behaviours. Opening an interactive session starts a background app server that keeps running after every Codex window is closed. The CLI copies its whole platform package, about 374 MB by their measurement, into a release directory under ~/.codex/packages/app-server-daemon/ and runs the daemon from that copy, so the server version is no longer the one the package manager installed. A detached updater checks for new releases and restarts the server. And the daemon keeps the proxy variables of whichever session launched it.

The daemon's own README, at the 0.162.1 tag, confirms two of these as design rather than accident. It says shared clients use the environment inherited when the daemon started, and that per-client environment isolation is not provided. It also says eligible managed daemons check for updates five minutes after start and then hourly, that an update restarts a running daemon so active or queued work may be interrupted, and that the updater uses saved network settings, so command-line -c overrides do not reach it. The copy is in the code too: the daemon's start command prepares a missing install by copying the running CLI's package into packages/app-server-daemon under the Codex home, through a confirmation callback that always answers yes.

The startup code shows which sessions are eligible. Auto-start is skipped when the feature is off, when --no-daemon is passed, for the agents overview, and for a remote workspace target. Later checks skip it during Bedrock sign-in setup and for WSL homes on a Windows-mounted drive, the second added in 0.162.0. Everything else gets the daemon.

The question the issue left open: why stop does not stop it

The reporter found that codex app-server daemon stop stopped the server but left the pid-update-loop updater alive, and killed it by hand. The source explains why. The stop lifecycle command in the daemon library stops the app-server process and nothing else. The updater is a separate loop with no check on whether the server it updates is still running. Outside of handing itself off to a new release, it exits on a termination signal, or when it wakes for its next scheduled check and finds auto-update disabled in CODEX_HOME/app-server-daemon/settings.json.

So pkill alone is not the durable fix, because the next managed start launches the updater again. Set updater.autoUpdateEnabled to false in that settings file and the updater removes itself at its next wake, which on the default cadence can be up to an hour away. Kill it as well if you need it gone now.

The opt-out is real and undocumented

The user-level fix is one line in ~/.codex/config.toml, under [features]: daemon_auto_start = false. The config schema in the repository accepts it, and a commenter on the issue confirms it works on Windows. But the official configuration reference, fetched today, contains no entry for daemon_auto_start at all, while it does document check_for_update_on_startup, a setting the daemon crate's code never reads. A reader looking for how to stop Codex from updating itself finds the wrong switch.

The same reference does document the control that matters for a fleet. A [features] table in requirements.toml pins runtime feature flags by the same keys config.toml uses, and the code at 0.162.1 writes each pinned value over whatever the user configured. On Unix the system file is /etc/codex/requirements.toml.

One more default rode along. Pull request 49426, shipped in 0.161.0, makes daemon-launched app servers start with analytics enabled by default, honouring analytics.enabled = false in config.toml as the opt-out.

The verdict

Our view, which a vendor changelog will not print: for any team that approved Codex through npm, Homebrew, or an internal mirror, 0.157.0 moved the binary that services agent turns outside the approval path. The package you vetted starts a copy of itself, and a background process checks hourly for a release to replace it with. That is the integration gap our piece on why enterprise AI does not ship names first: the model is fine, the audit trail is what breaks. Whether a self-updating server is acceptable is a policy call; making it by default, without a documented switch, removes the call from the people who own that policy.

Adopt 0.162.1 if you need it, but pin the feature first. This advice is wrong if a release flips default_enabled to false, or if OpenAI documents the key and stops copying the package when a package manager owns the install, which is what the open issue asks for.

Checklist for this week

  1. On a developer machine that has run Codex 0.157.0 or later, list leftover processes with pgrep -fl app-server. A match after every Codex window is closed is the daemon or its updater.

  2. For managed machines, add this to /etc/codex/requirements.toml:

    [features]
    daemon_auto_start = false
    
  3. For individual users, put the same two lines in ~/.codex/config.toml.

  4. On machines where a daemon already runs: set updater.autoUpdateEnabled to false in ~/.codex/app-server-daemon/settings.json, run codex app-server daemon stop, then end any remaining updater process rather than waiting for its next wake.

  5. If your proxy or credentials vary per invocation, assume any session started after the first one inherited the first one's environment until the daemon is gone.

  6. Add analytics.enabled = false to the same config.toml if your policy requires it for daemon-launched servers.

Ready to start?

Turn this into a plan for your team.

One week, fixed fee: a working session with your team, a prioritized use-case backlog, and an ROI model for the opportunities worth chasing.

Book an AI Opportunity Sprint