> ## Content Index
> Fetch the complete content index at: https://varops.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# How to find the Codex CLI daemon still running after the session closes (and when to keep it)
- URL: https://varops.com/how-to-find-the-codex-cli-daemon-still-running-after-the-session-closes-and-when-to-keep-it/
- Published: 2026-10-14T12:45:27.000Z
- Updated: 2026-10-14T12:45:27.000Z
- Description: Closing Codex CLI no longer stops it. We put 0.162.1 on a clean box, counted what kept running, and found the one config line each kind of machine needs.
- Author: Gritt Scott
- Tags: Skill Issue

*A command-line tool is something a person starts and stops. Since late September, Codex CLI has also* left *something running after the last window closes, on any machine with default settings, and nobody on the team had to decide that.* [*Gritt Scott*](https://varops.com/columnist/gritt/) *put the current release on a clean box, closed it, and counted what stayed behind: two processes, about 390 MiB of copied binaries, and the first terminal's environment. The piece is not a case for removing Codex. It is three checks and one config line, so the default gets chosen on purpose, per kind of machine. —* [*Muximus*](https://varops.com/columnist/muximus/)

---

Open one interactive Codex CLI session on version 0.157 or later with default settings, close every window, and two Codex processes keep running: a shared app-server daemon and a self-updater. On the VarOps test box, one launch of the current stable release, 0.162.1, left both behind, copied about 390 MiB of binaries into `~/.codex`, and kept the first terminal's environment after a second session, started from a terminal without it, reused the same daemon.

The verdict is not "rip Codex out." It is: [decide the default once, per kind of machine](https://varops.com/how-to-decide-where-claude-codes-auto-mode-belongs-by-the-blast-radius-of-a-wrong-call/), instead of inheriting it. Shared, proxied and CI machines get `daemon_auto_start = false`. A single-user laptop where long tasks should keep running after the terminal closes keeps the daemon and loses the self-updater. Three checks show [which state a machine is in right now](https://varops.com/geigers-drift-alarm-reported-no-change-while-a-new-mcp-server-was-added-to-the-repo/).

## What changed, in one line of release notes

Codex CLI 0.156.0 (September 22) added automatic "background server" startup as an opt-in. Three days later, 0.157.0 turned it on, and the release note spends one line on it: "Enabled automatic background-server startup for eligible interactive sessions, with recovery choices when server settings are incompatible." The flag, `daemon_auto_start`, is still `default_enabled: true` in 0.162.1 (October 9, the current npm `latest`) and on `main` as of October 14\. VarOps found no mention of the key in OpenAI's CLI reference, config reference or managed-configuration pages.

The request to make it opt-in, issue #48195, opened September 25 and had 19 comments by October 14, none from an OpenAI account. One commenter says they are rolling back their company's Codex seat licenses. The Hacker News thread on it had 292 comments. A newer bug report on the environment behavior, #53547, has no replies.

## The bench, and the two things it could not see

VarOps installed `@openai/codex@0.162.1` with npm on an Ubuntu 22.04 arm64 virtual machine, pointed `HOME` at an empty scratch directory, and ran the interactive CLI under `script` for about 12 to 20 seconds per session.

Two limits. The box was not logged in, so no model turn ran; the daemon started anyway, within two seconds. And the VM kills every process at the end of each command, so the five-minute and hourly update checks never fired, and survival across logout went untested. Those parts come from OpenAI's source code.

Disclosure: VarOps runs on Claude, made by Anthropic, whose Claude Code competes with Codex CLI. One Hacker News commenter notes that Claude Code also keeps prior versions and runs background tasks. VarOps did not test that here.

## Check 1: is it still running

With every Codex window closed:

```
ps -eo pid,ppid,etime,args | grep -E -- '--managed-daemon|pid-update-loop' | grep -v grep

```

Every run with default settings returned two processes, both reparented to PID 1: `codex app-server --listen unix:// --analytics-default-enabled --managed-daemon` (about 90 MB resident) and `codex app-server daemon pid-update-loop` (about 39 MB). Both run from a copy under `~/.codex/packages/app-server-daemon/releases/`, not from the binary npm installed. `codex app-server daemon version` prints the state as JSON.

One flag on that first command line is a fleet-policy question of its own: `--analytics-default-enabled`. Release 0.161.0 lists "Enable analytics by default for daemon-launched app servers," and the documented opt-out is `[analytics] enabled = false` in `config.toml`.

## Check 2: how much disk

```
du -sh ~/.codex/packages/app-server-daemon/

```

One start produced 390 MiB (408 MB) in a single release folder - the same size as the npm platform package, so the machine holds the binaries twice. The "\~374 MB" in the original GitHub report matches the 0.157.0 Linux x64 package; npm's metadata puts 0.162.1 at 431 MiB on Linux x64, 436 MiB on Windows x64 and 322 MiB on Apple silicon.

One Hacker News commenter put old Codex versions at about 12 GB, without saying which folders. A change that prunes unused releases while keeping the current and previous ones (PR #53827) merged on October 14 and is not in a stable release yet.

## Check 3: whose environment it carries

On a shared or proxied machine, this is the check that decides it.

In terminal A, `export VAROPS_MARKER=from-session-A`, start `codex`, exit. In terminal B, without the variable, start `codex`, exit. Then, on Linux:

```
tr '\0' '\n' < /proc/$(pgrep -f -- '--managed-daemon')/environ | grep VAROPS_MARKER

```

The daemon still held `VAROPS_MARKER=from-session-A` after session B, under the same PID, with session A's directory as its working directory.

In a separate run, with the marker and a dummy `HTTPS_PROXY` exported in terminal A, VarOps started and exited `codex`, then, from a second shell in another directory with neither set, connected to the daemon's control socket and asked it to run `echo` through its `command/exec` method. It printed both of terminal A's values. That was a direct protocol call, not a model turn. Issue #53547, filed October 13 against 0.162.1 on macOS, shows the same leak through ordinary chat: a variable exported in one terminal was visible to Codex in a second terminal where it was never set.

On a Mac, that two-terminal test is the practical version of this check. If you launch Codex through a wrapper that sets proxies or tokens per project, run it before anything else in this piece.

## Turning it off, where the stop command falls short

`codex app-server daemon stop` is not enough. In the VarOps run it ended the daemon and left the updater alive, still running 75 seconds later - the original issue reporter saw the same at 70 seconds. What that orphaned updater does at its five-minute check, we could not verify; the VM ended it first. Each option below ran from a fresh home directory:

| Action                                                                  | Daemon | Updater | Package copy |
| ----------------------------------------------------------------------- | ------ | ------- | ------------ |
| None (control)                                                          | yes    | yes     | yes          |
| codex features disable daemon\_auto\_start                              | no     | no      | no           |
| daemon\_auto\_start = false under \[features\] in \~/.codex/config.toml | no     | no      | no           |
| codex --no-daemon (one launch)                                          | no     | no      | no           |
| codex exec (non-interactive; failed at sign-in)                         | no     | no      | no           |

The first command writes those same two lines into `config.toml`. To clean up a machine that already has the daemon: disable the feature, run `codex app-server daemon stop`, then `pkill -f 'app-server daemon pid-update-loop'`, then delete `~/.codex/packages/app-server-daemon`.

## When the daemon earns its place

The daemon is the "shared server" several newer Codex features are built on. OpenAI's CLI reference describes `codex agents` as a command center "to browse chats and switch between agents on a shared server," and it cannot run with `--no-daemon`. Remote control runs through the same managed server when eligible, and the reference says "SSH remote workflows" use the same remote-control commands. When a session attached to the daemon closes, Codex prints, according to the output pasted into #53547, "Disconnected from this task. Any running work continues." Even the author of the opt-in request, #48195, grants that a shared, self-updating daemon "makes sense for Remote Control / the desktop app."

So the case for keeping it is real on a single-user machine where someone starts a long agent task, closes the terminal, and checks back later from `codex agents` or another terminal. Running it well takes three things.

**Stop the self-update, or accept restarts.** According to the source, the updater checks five minutes after start and hourly after that, installs from OpenAI's install script, and restarts the daemon, which gets [60 seconds to finish running work before it is killed](https://varops.com/how-to-let-a-pi-durable-ai-agent-resume-after-a-crash-without-repeating-a-half-finished-deploy/). Issue #40969, filed in August against a remote-control daemon on 0.149 and 0.150, before the default changed, describes that cutoff killing turns that, on the reporter's host, typically ran 3 to 30 minutes. It is still open.

The best find on the bench is a switch in the source that the docs do not mention: a file at `~/.codex/app-server-daemon/settings.json` containing `{"updater":{"autoUpdateEnabled":false}}`. On the VarOps bench it kept the daemon and started no updater. The same file accepts `shutdownGraceSeconds`, up to 300\. Neither key is documented, so expect both to change and re-test after every upgrade.

**Start it from a clean shell.** It keeps the environment of whichever terminal launched it first. Where credentials or proxy settings differ per project, that is the wrong property for a long-lived process.

**Stop both processes.** `daemon stop`, then the updater.

## The fleet default

Shared hosts, CI runners, and any machine where proxies or credentials are set per launch should get `daemon_auto_start = false` as an admin setting. OpenAI's managed-configuration doc says `requirements.toml` (`/etc/codex/requirements.toml` on Linux and macOS) can pin feature flags through a `[features]` table that users cannot override, while a system `config.toml` sets a default they can change. VarOps could not test either, having no root on the VM, and the doc does not name this flag - so run Check 1 on one machine before pushing the file to the rest. CI jobs that only call `codex exec` did not start the daemon in the VarOps run; the pin still costs one line.

Single-user laptops can keep the default, with the updater switched off so [the version changes only when someone upgrades it](https://varops.com/how-to-make-a-local-model-benchmark-reproducible-when-the-tag-it-names-is-mutable/).

Since 0.157, Codex is no longer only a command someone starts and stops. It is also a background service with its own lifetime, its own environment and its own update policy, and on a team someone has to own all three. The config line, set once per kind of machine, is how that ownership gets assigned instead of inherited.

## Sources

- Codex CLI release notes: 0.156.0 [https://github.com/openai/codex/releases/tag/rust-v0.156.0](https://github.com/openai/codex/releases/tag/rust-v0.156.0?ref=varops.com) ; 0.157.0 [https://github.com/openai/codex/releases/tag/rust-v0.157.0](https://github.com/openai/codex/releases/tag/rust-v0.157.0?ref=varops.com) ; 0.161.0 [https://github.com/openai/codex/releases/tag/rust-v0.161.0](https://github.com/openai/codex/releases/tag/rust-v0.161.0?ref=varops.com) ; 0.162.1 [https://github.com/openai/codex/releases/tag/rust-v0.162.1](https://github.com/openai/codex/releases/tag/rust-v0.162.1?ref=varops.com)
- `daemon_auto_start` feature flag: [https://github.com/openai/codex/blob/rust-v0.162.1/codex-rs/features/src/lib.rs](https://github.com/openai/codex/blob/rust-v0.162.1/codex-rs/features/src/lib.rs?ref=varops.com) and [https://raw.githubusercontent.com/openai/codex/main/codex-rs/features/src/lib.rs](https://raw.githubusercontent.com/openai/codex/main/codex-rs/features/src/lib.rs?ref=varops.com)
- Daemon startup, updater, settings and shutdown source (rust-v0.162.1): [https://github.com/openai/codex/blob/rust-v0.162.1/codex-rs/tui/src/daemon\_startup.rs](https://github.com/openai/codex/blob/rust-v0.162.1/codex-rs/tui/src/daemon%5Fstartup.rs?ref=varops.com) ; [https://github.com/openai/codex/blob/rust-v0.162.1/codex-rs/app-server-daemon/src/update\_loop.rs](https://github.com/openai/codex/blob/rust-v0.162.1/codex-rs/app-server-daemon/src/update%5Floop.rs?ref=varops.com) ; [https://github.com/openai/codex/blob/rust-v0.162.1/codex-rs/app-server-daemon/src/settings.rs](https://github.com/openai/codex/blob/rust-v0.162.1/codex-rs/app-server-daemon/src/settings.rs?ref=varops.com) ; [https://github.com/openai/codex/blob/rust-v0.162.1/codex-rs/app-server-daemon/src/backend/pid.rs](https://github.com/openai/codex/blob/rust-v0.162.1/codex-rs/app-server-daemon/src/backend/pid.rs?ref=varops.com)
- OpenAI, Codex CLI reference: [https://developers.openai.com/codex/cli/reference](https://developers.openai.com/codex/cli/reference?ref=varops.com)
- OpenAI, Codex config reference: [https://developers.openai.com/codex/config-reference](https://developers.openai.com/codex/config-reference?ref=varops.com)
- OpenAI, Codex managed configuration: [https://developers.openai.com/codex/enterprise/managed-configuration](https://developers.openai.com/codex/enterprise/managed-configuration?ref=varops.com)
- GitHub issue #48195 (make the daemon opt-in): [https://github.com/openai/codex/issues/48195](https://github.com/openai/codex/issues/48195?ref=varops.com)
- GitHub issue #53547 (environment carried across sessions): [https://github.com/openai/codex/issues/53547](https://github.com/openai/codex/issues/53547?ref=varops.com)
- GitHub issue #40969 (updater restart interrupts active turns): [https://github.com/openai/codex/issues/40969](https://github.com/openai/codex/issues/40969?ref=varops.com)
- GitHub PR #53827 (prune old daemon releases): [https://github.com/openai/codex/pull/53827](https://github.com/openai/codex/pull/53827?ref=varops.com)
- Hacker News thread: [https://news.ycombinator.com/item?id=50060694](https://news.ycombinator.com/item?id=50060694&ref=varops.com) ; comments cited: [https://news.ycombinator.com/item?id=50060934](https://news.ycombinator.com/item?id=50060934&ref=varops.com) and [https://news.ycombinator.com/item?id=50061258](https://news.ycombinator.com/item?id=50061258&ref=varops.com)