Skip to content

Desktop app zsh snapshot export filter omits PATH, breaking Homebrew tools #20220

@lattwood

Description

@lattwood

What version of the Codex App are you using (From “About Codex” dialog)?

26.422.71525

What subscription do you have?

API Key

What platform is your computer?

Darwin 25.4.0 arm64 arm

What issue are you seeing?

Codex Desktop shell commands can fail to find tools that are installed via Homebrew, for example gh, even though the same Codex config works when Codex is launched from a terminal.

My config uses shell_environment_policy.inherit = "all" and keeps PATH in include_only. For a CLI/terminal-launched Codex process, tool execution inherits the terminal PATH, which includes /opt/homebrew/bin. In the Desktop app, the app-server process is launched from the macOS GUI environment, so the inherited PATH does not include /opt/homebrew/bin.

Shell snapshots are supposed to bridge that gap by sourcing .zshrc and restoring the resulting shell environment before running the final non-interactive command. In this case, the app-server log shows the shell snapshot was created successfully, but the snapshot omitted the actual PATH export. A later gh --version tool call was logged as /bin/zsh -lc "gh --version" and failed with:

zsh:1: command not found: gh

The likely source is the zsh snapshot export/declare filter. zsh emits tied path parameters as:

export -T PATH path=( /opt/homebrew/bin /usr/bin /bin ... )

but the current filter only preserves simple export/declare -x/typeset -x lines whose parsed name looks like NAME=.... It parses the zsh line as something like -T PATH path, rejects it as an invalid variable name, and drops it. The snapshot succeeds, but does not restore PATH.

What steps can reproduce the bug?

  1. On macOS with zsh, install gh or another CLI tool under /opt/homebrew/bin.
  2. Configure PATH from ~/.zshrc, not from a global launchd environment.
  3. Use a Codex config that inherits PATH into tool execution, for example:
[shell_environment_policy]
inherit = "all"
ignore_default_excludes = true
include_only = ["HOME", "LOGNAME", "PATH", "SHELL", "USER", "TMPDIR", "TEMP", "TMP"]
  1. Launch Codex Desktop from the macOS app/Finder/Dock, not from a terminal.
  2. In a thread, run a command such as gh --version or command -v gh.

Observed in one Desktop-backed rollout:

command=["/bin/zsh","-lc","gh --version"]
stderr="zsh:1: command not found: gh"
exit_code=127
  1. Check app-server logs in ~/.codex/logs_2.sqlite: the shell snapshot had succeeded before the command ran, so this was not a snapshot timeout.
  2. Inspect a generated zsh snapshot under ~/.codex/shell_snapshots/*.sh: there is no top-level export PATH=..., declare -x PATH=..., or typeset -x PATH=...; PATH only appears incidentally inside captured function bodies.

What is the expected behavior?

Codex Desktop should behave the same as a terminal-launched Codex process under the same shell config. If .zshrc adds /opt/homebrew/bin to PATH and the zsh shell snapshot succeeds, subsequent shell commands should be able to resolve tools from that PATH.

The zsh snapshot should preserve tied exported path parameters such as export -T PATH path=(...), or otherwise normalize them into a sourceable scalar export PATH=... line before the final non-login/non-interactive shell command is executed.

Additional information

This appears Desktop-specific because the broken snapshot is masked when Codex is launched from a terminal whose parent environment already contains the desired PATH.

Relevant source locations from current openai/codex:

  • codex-rs/core/src/shell_snapshot.rs: zsh_snapshot_script() captures exports via export -p | awk ....
  • codex-rs/core/src/tools/runtimes/mod.rs: maybe_wrap_shell_lc_with_snapshot() sources the snapshot, then executes the original command with exec <shell> -c <script>.
  • Current tests only assert that the snapshot text contains PATH; this can pass when PATH appears inside captured function bodies even if the snapshot does not restore the PATH variable.

In the investigated Desktop session, app-server logs showed:

Shell snapshot successfully created: ~/.codex/shell_snapshots/<thread-id>.tmp-...

No Snapshot command timed out, Failed to create shell snapshot, validation failure, or finalize failure was logged for that thread.


Also, I investigated this issue with Codex, and using the Computer Use MCP, got it to fill out all of the fields. I did review all of the text, I'm not going to subject y'all to my slop.

Metadata

Metadata

Assignees

No one assigned

    Labels

    appIssues related to the Codex desktop appapp-serverIssues involving app server protocol or interfacesbugSomething isn't workingtool-callsIssues related to tool calling

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions