app-server local command execution lacks a cwd-scoped environment contract

Open 💬 9 comments Opened May 26, 2026 by dpritchett
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What issue are you seeing?

Codex local command execution can silently use different environment sources for visually similar TUI launches.

A plain codex session may reuse an implicit local app-server daemon. Adding any -c override prevents that reuse and starts a different execution topology. This means command env can differ even when cwd and the visible UI look equivalent.

This is surprising and operationally risky because the UI presents both sessions as local command execution in the same directory, but env-sensitive commands may behave differently.

What steps can reproduce the bug?

First, make sure an implicit local app-server daemon already exists. In my case, this was a long-lived daemon started earlier by normal Codex use. The important precondition is that plain codex can reuse an existing local app-server daemon.

Then, in a shell:

mkdir -p /tmp/codex-env-repro
cd /tmp/codex-env-repro
export CODEX_ENV_REPRO=present
printenv CODEX_ENV_REPRO

Control output:

present

Start Codex normally:

codex

Inside Codex:

pwd
printenv CODEX_ENV_REPRO

Observed:

/private/tmp/codex-env-repro
# no output

Now exit and start Codex with a config override:

codex -c shell_environment_policy.inherit=all

Inside Codex:

pwd
printenv CODEX_ENV_REPRO

Observed:

/tmp/codex-env-repro
present

What is the expected behavior?

Either:

  1. both local TUI launches use the same command-env provenance, or
  2. Codex clearly exposes when command env comes from a reused app-server daemon instead of the launching terminal process.

The important part is not this specific variable. The issue is that adding a -c override changes process topology and therefore command env, while the UI still presents both as local execution in the selected cwd.

Additional information

shell_environment_policy.inherit = "all" appears to be valid and already defaults to all, so the override value itself is probably not the fix. The relevant behavior appears to be that non-empty CLI overrides prevent implicit local app-server daemon reuse.

View original on GitHub ↗

9 Comments

github-actions[bot] contributor · 1 month ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #23642
  • #23648

Powered by Codex Action

dpritchett · 1 month ago

I reviewed the two suggested duplicates. I think they are related but not duplicates.

  • #23642 is about the VS Code extension not honoring the selected Python interpreter / venv. That is one concrete instance of environment selection drift, but it is IDE- and Python-specific.
  • #23648 is about Remote SSH new worktree threads not invoking a selected Codex environment setup script. That is remote/worktree setup lifecycle-specific.

This issue is narrower in one way and more general in another: it is about local codex app-server --listen unix:// command execution having no explicit contract for the env source relative to the command cwd.

The failure mode here is:

cwd: repo A, selected per command/thread
env: inherited from the long-lived app-server process, possibly started from repo B

That can affect Python venvs and worktree setup flows, but it also affects kube/cloud/toolchain workflows where the cwd determines the runtime environment. A diagnostic-only fix would already help: expose whether a command used app-server inherited env, client-provided env, or a cwd-derived env provider, and warn when cwd/env contexts diverge.

dpritchett · 1 month ago

I narrowed this down after filing. The original real-world failure involved a repo-local environment, but that detail is incidental and made the report noisier than necessary.

The smaller issue is the one now in the body: visually similar local TUI launches can use different command-env provenance because a -c override prevents implicit local app-server daemon reuse. So the confusing part is not a specific shell, env provider, or toolchain. It is that cwd stays visible and local-looking while the env source can silently switch between daemon-derived and launch-process-derived.

dpritchett · 1 month ago

Relevant code context from a local source read at cd934c8bcb1ba50791a980db1d0b38cef7cf84f9:

  • can_reuse_implicit_local_daemon(...) intentionally refuses daemon reuse when CLI/config-loader launch state cannot be adopted by the daemon. In particular, daemon reuse requires cli_kv_overrides.is_empty().
  • create_env(...) constructs command env from std::env::vars() in the process doing execution.

That explains the observed behavior: a no-op-looking -c override changes whether the TUI reuses an existing daemon, and command env is then derived from a different process. I did not find an obvious user-visible contract or diagnostic that tells the user when local command execution is using daemon-derived env rather than launch-process-derived env.

dpritchett · 1 month ago

Based on a deeper read of the code in the previous comment, this looks related to #17216 and #23538.

xsjk · 1 month ago

I confirmed this on Linux with codex-cli 0.135.0.

Minimal repro:

# Shell 1
A=1 codex app-server --listen unix://

# Shell 2
A=2 codex
# Then in the CLI, `!printenv A` prints `1`

# Shell 3
A=2 codex -c model=gpt-5.5
# Then in the CLI, `!printenv A` prints `2`

# Shell 4
A=2 codex --strict-config
# Then in the CLI, `!printenv A` prints `2`

This confirms the reported behavior: plain TUI reuses the existing app-server
environment, while any -c override switches to the launcher environment.

xsjk · 1 month ago

I think the core question is the mental model Codex wants for local app-server reuse.

Possible design philosophies

  1. The app-server is the real session owner.

Users are expected to understand that a new codex may attach to an existing daemon and inherit its context. This is the current behavior.

  1. The newly opened client owns the conversation env.

App-server reuse is an implementation detail, and shell/exec behavior follows the launching terminal. This would mean storing env in SessionConfiguration and updating its call sites.

  1. The newly opened client owns the whole conversation context.

Same as (2), but proxy/CA env such as https_proxy also affects LLM requests. This would also need client-specific transport context.
(This is how I found this issue, after wondering why https_proxy=... codex still could not connect. 🙃)

All three assume local app-server reuse stays the default. My preference is the fourth option, that app-server reuse should be explicit rather than implicit.

xsjk · 1 month ago
Based on a deeper read of the code in the previous comment, this looks related to #17216 and #23538.

I took a look at the two PRs you mentioned.
#17216: under remote execution, should command env come from Core/the orchestrator or from the executor?
#23538: under local app-server reuse, should session cwd come from the client invocation or the daemon process?
#24638: under local app-server reuse, should shell env come from the client invocation or the daemon process?

xsjk · 1 month ago
I think the core question is the mental model Codex wants for local app-server reuse. Possible design philosophies 1. The app-server is the real session owner. Users are expected to understand that a new codex may attach to an existing daemon and inherit its context. This is the current behavior. 2. The newly opened client owns the conversation env. App-server reuse is an implementation detail, and shell/exec behavior follows the launching terminal. This would mean storing env in SessionConfiguration and updating its call sites. 3. The newly opened client owns the whole conversation context. Same as (2), but proxy/CA env such as https_proxy also affects LLM requests. This would also need client-specific transport context. (This is how I found this issue, after wondering why https_proxy=... codex still could not connect. 🙃) All three assume local app-server reuse stays the default. My preference is the fourth option, that app-server reuse should be explicit rather than implicit.

After checking the docs further, I think only option (2) matches the semantics of shell_environment_policy.inherit and inherit = "all" is default.
https://developers.openai.com/codex/config-advanced#shell-environment-policy
https://developers.openai.com/codex/config-sample

Could the maintainers confirm whether this is intended?