app-server local command execution lacks a cwd-scoped environment contract
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:
- both local TUI launches use the same command-env provenance, or
- 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.
9 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
I reviewed the two suggested duplicates. I think they are related but not duplicates.
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:
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.
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
-coverride prevents implicit local app-server daemon reuse. So the confusing part is not a specific shell, env provider, or toolchain. It is thatcwdstays visible and local-looking while the env source can silently switch between daemon-derived and launch-process-derived.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 requirescli_kv_overrides.is_empty().create_env(...)constructs command env fromstd::env::vars()in the process doing execution.That explains the observed behavior: a no-op-looking
-coverride 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.Based on a deeper read of the code in the previous comment, this looks related to #17216 and #23538.
I confirmed this on Linux with
codex-cli 0.135.0.Minimal repro:
This confirms the reported behavior: plain TUI reuses the existing app-server
environment, while any
-coverride switches to the launcher environment.I think the core question is the mental model Codex wants for local app-server reuse.
Possible design philosophies
Users are expected to understand that a new
codexmay attach to an existing daemon and inherit its context. This is the current behavior.App-server reuse is an implementation detail, and shell/exec behavior follows the launching terminal. This would mean storing env in
SessionConfigurationand updating its call sites.Same as (2), but proxy/CA env such as
https_proxyalso affects LLM requests. This would also need client-specific transport context.(This is how I found this issue, after wondering why
https_proxy=... codexstill 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.
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?
After checking the docs further, I think only option (2) matches the semantics of
shell_environment_policy.inheritandinherit = "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?