Codex runs commands via bash --login and drops per-project env

Open 💬 15 comments Opened Oct 6, 2025 by apt-get-coke
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

Version

codex-cli 0.44.0

Repro steps

  1. In a repo that relies on direnv (e.g. .envrc runs use flake .) so project tools live under .devenv/profile/bin.
  2. cd into that repo and launch codex.
  3. Ask Codex to run one of those project helpers (e.g. ensure-python-stack) or just codex -- /bin/echo "/home/julien/.nix-profile/bin:/home/julien/.local/bin:/home/julien/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games".

Expected

Codex keeps the direnv-injected PATH (worked in 0.42.0); project binaries stay visible.

Actual

0.44.0 now spawns every command with bash --login -c … (see PR #4612). The login shell starts in /home/julien, the PATH is rebuilt without .devenv/profile/bin, and project helpers hit "command not found". To work around it I have to wrap every command in direnv exec . …, which re-runs the heavy enter-shell hook and makes Codex painfully slow. tmux titles flip to "home" for the same reason.

Could you drop the login shell (or add a config flag to keep the inherited environment)? This change effectively breaks Codex for direnv/devenv workflows.

View original on GitHub ↗

15 Comments

github-actions[bot] contributor · 9 months ago

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

  • #4210
  • #4808

Powered by Codex Action

o1lo01ol1o · 9 months ago

Related #4667

o1lo01ol1o · 9 months ago

@apt-get-coke Can you confirm this worked in 0.42.0?

I have, for example:

% which codex
/nix/store/67annmfwgz60y8p97ysddi9bvc7lcy7r-codex-0.42.0/bin/codex
% which foo
/nix/store/grqqy0gpv4hlnix8qhk1h0yklizkrd7r-foo-2.79.3/bin/foo

% codex
{...}

▌ what's the output of which foo?

• Ran which foo

> faust isn’t on PATH here (which foo returned exit code 1). Enter your devenv shell so
  the toolchain scripts—including foo and build-foo—become available.
apt-get-coke · 9 months ago
@apt-get-coke Can you confirm this worked in 0.42.0? I have, for example: `` % which codex /nix/store/67annmfwgz60y8p97ysddi9bvc7lcy7r-codex-0.42.0/bin/codex % which foo /nix/store/grqqy0gpv4hlnix8qhk1h0yklizkrd7r-foo-2.79.3/bin/foo % codex {...} ▌ what's the output of which foo? • Ran which foo > faust isn’t on PATH here (which foo returned exit code 1). Enter your devenv shell so the toolchain scripts—including foo and build-foo—become available. ``

Yes, it still works for us on 0.42.0. Example:

$ codex --version
codex version 0.42.0
$ pwd
/path/to/project
$ codex
codex> which foo
/path/to/project/.direnv/bin/foo
codex> exit

That project’s .envrc runs direnv/devenv so the toolchain ends up in .direnv/bin. With codex 0.44.0 the executable launches the
shell with --login, the working directory resets to $HOME, .envrc never runs, and the PATH entry disappears:

$ codex --version
codex version 0.44.0
$ codex
codex> pwd
$HOME
codex> which foo
which: no foo in ...

If we cd back into the project after codex starts and run direnv reload, the PATH comes back. The regression appears tied to the
new --login behavior wiping out the inherited cwd/direnv environment.

apt-get-coke · 9 months ago
Related #4667

Nope—#4667 is a feature request about letting codex run commands with a user-supplied PATH so it can see toolchains inside a
sandbox. Our issue is a regression in 0.44: codex now launches the shell with --login, which resets the working directory to
$HOME, so .envrc doesn’t run and our existing PATH entries aren’t retained. Different problem, unfortunately. :)

guidomb · 8 months ago

Does anyone has a way of working around this issue? We face the same issue and would be helpful to be able to use codex with devenv

apt-get-coke · 8 months ago
Does anyone has a way of working around this issue? We face the same issue and would be helpful to be able to use codex with devenv

We hit the same problem and never found a reliable fix, so we dropped per-project nix/devenv. Each Python repo now ships with " + " for reproducible envs without Codex choking on nix build steps. We still keep nix at the user level for shared dev tools, but project envs are fully uv-driven. It’s been better for us because syncs/locks much faster than nix, Codex Cloud can run immediately, and our CI runners spend less time rebuilding derivations, so overall there’s less friction while we keep the reproducibility we cared about.

o1lo01ol1o · 8 months ago

If you provide an mcp server that exposes the commands you need, you can
use:

cat .codex/config.toml

[mcp_servers.ghcid]
command = "/usr/bin/env"
args = ["direnv", "exec", ".", "mcp-ghcid", "--log-level", "debug"]
timeout = 60000

Similar flake commands can be run, but, this obviously isn't great on dynamic languages that assume fast and frequent edit - run loops ; so your uv mcp will need to manage the subprocess lifetime efficiently.

guidomb · 8 months ago

Well I ended up adding the following to ~/.codex/config.toml is

[shell_environment_policy]
inherit = "all"
ignore_default_excludes = true

and then running codex with codex --sandbox danger-full-access

This results in our devenv and .env loaded via direnv working

etiennecrb · 8 months ago

@guidomb It doesn't work for me on macos

My only workaround is to set manually the must have variables I need:

[shell_environment_policy]
# Temporary workaround until codex is compatible with direnv again
# https://github.com/openai/codex/issues/4210
set = { MY_VAR = "foo" }
guidomb · 8 months ago

@etiennecrb Mmm interesting I also run on macOS.

devenv --version
devenv 1.7.0 (aarch64-darwin)

might be related with my particular env, this is my .envrc

export DIRENV_WARN_TIMEOUT=20s

eval "$(devenv direnvrc)"

# The use_devenv function supports passing flags to the devenv command
# For example: use devenv --impure --option services.postgres.enable:bool true
use devenv --option dotenv.enable:bool true
ak2766 · 6 months ago

I was hoping to see resolution on this but still no bueno.

Let me try what @guidomb suggested above and see if this resolves my current issue which is documented below:

<details>
<summary>terminal text scrape</summary>

> pwd
/home/akk/source/profiler
> 
> ls | head -n 5
stats.sh
wrk.log
> 
> ls ${HOME} | head -n 5
__a1
__a2
__a3
__a4
__a5
> 
> codex
╭────────────────────────────────────────────────────╮
│ >_ OpenAI Codex (v0.77.0)                          │
│                                                    │
│ model:     gpt-5.2-codex medium   /model to change │
│ directory: ~/source/profiler                       │
╰────────────────────────────────────────────────────╯

  Tip: You can run any shell command from Codex using ! (e.g. !ls)


› Can you please show me the first 5 files in the current project directory?


• Explored
  └ List ls -1

─ Worked for 5s ────────────────────────────────────────────────────────────────────────────────────────────────────────────────

• First five entries (sorted by name):

  1. __a1
  2. __a2
  3. __a3
  4. __a4
  5. __a5

</details>

<details>
<summary>Terminal screenshot</summary>

<img width="400" height="511" alt="Image" src="https://github.com/user-attachments/assets/87717b2d-1511-4421-9867-05d313bff48a" />

</details>

pasky · 6 months ago

Note that both the shell being started being login shell and being interactive is an issue...

  1. The shell tool behaves weirdly in case you do something non-trivial in your .profile (echo $TERM, uptime, fortune, ...), e.g. my output looks like this:
• I'm running a shell command that prints $0, the login_shell shell option, and the current process args with the default login shell setting to confirm if it runs as a login shell and then will summarize the observed output.

$ echo "0=$0"; shopt login_shell; ps -o args= -p $$
command timed out after 10005 milliseconds
TERM=tmux-256color

"If you want to eat hippopotamus, you've got to pay the freight."
        -- attributed to an IBM guy, about why IBM software uses so much memory


 20:26:25 up 134 days, 18:57, 13 users,  load average: 0.22, 0.37, 0.48
✗ (124) • 10.01s
  1. Using interactive shell makes codex completely broken on my machine, since the tool hangs when it tries to execute it. Codex says:
The hang comes from your login shell running pyenv init - (via ~/.profile → ~/.bashrc). That invokes pyenv rehash, which tries to write ~/.pyenv/shims/.pyenv-shim; in the Codex sandbox that path isn’t writable, so pyenv rehash loops for up to 60s
  waiting on a lock and the CLI times out (~10s) instead.
  1. No other AI agent CLI I tried (claude code, gemini, ampcode, ...) uses login / interactive shell. It's not really clear to me why codex is trying to use interactive shell at all...
pasky · 6 months ago

Hmm, it seems this was introduced in https://github.com/openai/codex/pull/1725 - @pakrym-oai could you please take a look? Why is Codex behaving differently from other CLIs in this regard? Would it make sense to have this configurable?

ryoppippi · 27 days ago

any updates?