diff --git a/src/coder_eval/agents/codex_agent.py b/src/coder_eval/agents/codex_agent.py index 43e63d6..9be3274 100644 --- a/src/coder_eval/agents/codex_agent.py +++ b/src/coder_eval/agents/codex_agent.py @@ -1089,7 +1089,13 @@ def _build_codex_env(self) -> dict[str, str] | None: # shell), which ignores HOME for dotfile selection when it is set. env["HOME"] = str(self._login_shell_home) env["ZDOTDIR"] = str(self._login_shell_home) - env["CODEX_HOME"] = str(self._codex_home()) + # The binary hard-errors on an explicitly set CODEX_HOME that does + # not exist (unset, it materializes the ~/.codex default itself) — + # hosts that auth via CODEX_API_KEY never ran `codex login`, so + # the dir may not exist yet. Create it before pinning. + codex_home = self._codex_home() + codex_home.mkdir(parents=True, exist_ok=True) + env["CODEX_HOME"] = str(codex_home) return env if env else None @staticmethod diff --git a/tests/test_codex_agent.py b/tests/test_codex_agent.py index a0e4f7b..95ee117 100644 --- a/tests/test_codex_agent.py +++ b/tests/test_codex_agent.py @@ -1755,6 +1755,20 @@ def test_build_codex_env_sets_home_and_pins_codex_home(self, monkeypatch, tmp_pa # harness reads the same _codex_home() for sub-agent rollout recovery. assert env["CODEX_HOME"] == str(agent._codex_home()) + def test_build_codex_env_creates_missing_codex_home(self, monkeypatch, tmp_path): + """The codex binary hard-errors on an explicitly set CODEX_HOME that + does not exist (unset, it materializes the ~/.codex default itself). + Runners that auth via CODEX_API_KEY never ran ``codex login``, so the + dir may not exist — pinning it must create it first.""" + monkeypatch.delenv("CODEX_API_KEY", raising=False) + monkeypatch.setenv("CODEX_HOME", str(tmp_path / "state" / ".codex")) + agent = self._agent_with_prepend(["/sandbox/mocks"]) + agent._login_shell_home = tmp_path / "login-home" + + env = agent._build_codex_env() + assert env is not None + assert Path(env["CODEX_HOME"]).is_dir() + def test_build_codex_env_without_login_home_leaves_home_alone(self, monkeypatch): monkeypatch.setenv("CODEX_API_KEY", "k") agent = CodexAgent(parse_agent_config(type=AgentKind.CODEX))