NousResearch/hermes-agent

Working directory handling fixes across session types

Cluster 38775 · acp. Data as of

Nothing open on GitHub. Fix merged in #50451 on 21 Jun 2026. Check it covers your case.

The short answer

0open issues
0open PRs
3items grouped
Known?
Yes. 3 related items grouped here, 1 issue already closed.
Fix event
A fix was merged to main in PR #50451. Check it covers your case. No release data is tracked.
Tracker
The maintainers' tracker marks this resolved, deciding PR #50451. That is separate from the fix event.
Still open
Nothing open on GitHub.

A bug and several fixes addressing how the configured or current working directory is tracked and applied across app-server sessions, terminal sessions, and desktop workspaces. Changes include per-session cwd records, seeding sessions with the correct cwd, and ensuring configured directories take precedence over stale remembered values.

Open issues0

No open issues.

Open PRs0

No open pull requests.

Fixes on record

Merged to main. A stamp counts the issues a fix is linked to.

  • #50451 fix(codex): seed app-server sessions with configured cwd

    merged to main

    files: acp_adapter/session.py, agent/codex_runtime.py, tests/acp/test_session.py, tests/run_agent/test_codex_app_server_integration.py

    Show the diff
    • acp_adapter/session.py
      @@ -617,6 +617,10 @@ def _make_agent(
       
               _register_task_cwd(session_id, cwd)
               agent = AIAgent(**kwargs)
      +        # Codex app-server sessions are spawned lazily on the first turn. Stamp
      +        # the ACP workspace onto the agent so the Codex runtime starts from the
      +        # editor/session cwd instead of the Hermes daemon's process cwd.
      +        agent.session_cwd = cwd
               # ACP stdio transport requires stdout to remain protocol-only JSON-RPC.
               # Route any incidental human-readable agent output to stderr instead.
               agent._print_fn = _acp_stderr_print
    • agent/codex_runtime.py
      @@ -250,7 +250,9 @@ def run_codex_app_server_turn(
           # Spawned on first turn, reused across turns, closed at AIAgent
           # shutdown (see _cleanup hook).
           if not hasattr(agent, "_codex_session") or agent._codex_session is None:
      -        cwd = getattr(agent, "session_cwd", None) or os.getcwd()
      +        from agent.runtime_cwd import resolve_agent_cwd
      +
      +        cwd = getattr(agent, "session_cwd", None) or str(resolve_agent_cwd())
               # Approval callback: defer to Hermes' standard prompt flow if a
               # CLI thread has installed one. Gateway / cron contexts get the
               # codex-side fail-closed default.
    • tests/acp/test_session.py
      @@ -77,6 +77,50 @@ def test_get_session(self, manager):
           def test_get_nonexistent_session_returns_none(self, manager):
               assert manager.get_session("does-not-exist") is None
       
      +    def test_make_agent_stamps_session_cwd_for_codex_runtime(self, monkeypatch):
      +        class FakeAgent:
      +            model = "fake-model"
      +
      +            def __init__(self, **kwargs):
      +                self.kwargs = kwargs
      +
      +        monkeypatch.setattr("run_agent.AIAgent", FakeAgent)
      +        monkeypatch.setattr(
      +            "acp_adapter.session.load_config",
      +            lambda: {
      +                "model": {
      +                    "default": "fake-model",
      +                    "provider": "fake-provider",
      +                },
      +                "mcp_servers": {},
      +            },
      +            raising=False,
      +        )
      +        monkeypatch.setattr(
      +            "hermes_cli.config.load_config",
      +            lambda: {
      +                "model": {
      +                    "default": "fake-model",
      +                    "provider": "fake-provider",
      +                },
      +                "mcp_servers": {},
      +            },
      +        )
      +        monkeypatch.setattr(
      +            "hermes_cli.runtime_provider.resolve_runtime_provider",
      +            lambda requested=None: {
      +                "provider": requested,
      +                "api_mode": "codex_app_server",
      +                "base_url": "https://example.invalid",
      +                "api_key": "[redacted:secret-assignment]",
      +            },
      +        )
      +        monkeypatch.setattr("acp_adapter.session._register_task_cwd", lambda task_id, cwd: None)
      +
      +        state = SessionManager(db=None).create_session(cwd="/tmp/project")
      +
      +        assert state.agent.session_cwd == "/tmp/project"
      +
       
       
       
    • tests/run_agent/test_codex_app_server_integration.py
      @@ -293,6 +293,39 @@ def test_chat_completions_loop_is_not_entered(self, fake_session):
                   agent.run_conversation("hi")
               assert not client_mock.chat.completions.create.called
       
      +    def test_gateway_terminal_cwd_seeds_codex_thread_cwd(self, monkeypatch, tmp_path):
      +        """Gateway sessions set TERMINAL_CWD without stamping agent.session_cwd.
      +        Codex app-server must still start in that configured workspace instead
      +        of falling back to the Hermes daemon process cwd."""
      +        from agent.transports.codex_app_server_session import (
      +            CodexAppServerSession, TurnResult,
      +        )
      +
      +        captured: dict[str, str] = {}
      +
      +        def fake_init(self, **kwargs):
      +            captured["cwd"] = kwargs["cwd"]
      +            self._thread_id = "thread-stub-1"
      +
      +        def fake_run_turn(self, user_input: str, **kwargs):
      +            return TurnResult(
      +                final_text="ok",
      +                projected_messages=[{"role": "assistant", "content": "ok"}],
      +                turn_id="turn-stub-1",
      +                thread_id="thread-stub-1",
      +            )
      +
      +        monkeypatch.setenv("TERMINAL_CWD", str(tmp_path))
      +        monkeypatch.setattr(CodexAppServerSession, "__init__", fake_init)
      +        monkeypatch.setattr(CodexAppServerSession, "run_turn", fake_run_turn)
      +
      +        agent = _make_codex_agent()
      +        assert not hasattr(agent, "session_cwd")
      +        with patch.object(agent, "_spawn_background_review", return_value=None):
      +            agent.run_conversation("hi")
      +
      +        assert captured["cwd"] == str(tmp_path)
      +
       
       class TestReviewForkApiModeDowngrade:
           """When the parent agent runs on codex_app_server, the background

1 PR closed without merging

From the close comments: merged via another change 1

  • #38778 fix(codex): seed app-server sessions with configured cwd · merged via another change → c11ae82, #50451
Closed issues · 1
  • Closed#38775[Bug]: Codex app-server sessions ignore configured/session cwd and start sandbox in Hermes home
How this cluster was grouped
  • Link evidence (structural links throughout): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
  • Pairwise link density 0.67: the share of item pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. 1.00 means every pair is linked.

Pick up a Lab task

Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.

Open the Lab

At a glance

Subsystem
acp
Merged PRs
#50451
Closed issues
1
Attempts
1 PR closed without merging
Fix link checked
21 Jun 2026

For your agent

The same facts, typed.