Turn completes prematurely when unified_exec background processes are still running

Open 💬 2 comments Opened Mar 15, 2026 by morozow

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

Latest from main branch (commit from codex-rs/core)

What subscription do you have?

Pro

What platform is your computer?

Darwin 25.3.0 arm64 arm

What issue are you seeing?

When an agent starts a long-running process via unified_exec (e.g., uv run train.py, npm run build, or any command that takes more than a few seconds), the turn completes immediately after the model's response — without waiting for the process to finish. The agent never receives the process output.

Root cause identified in code:

In codex-rs/core/src/codex.rs, the ResponseEvent::Completed handler only checks has_pending_input():

ResponseEvent::Completed { .. } => {
    // ...
    needs_follow_up |= sess.has_pending_input().await;
    // Turn ends if needs_follow_up is false
}

This does not account for running processes in unified_exec_manager.process_store. When a process is started with exec_command and returns a process_id (indicating it's still running), the turn should not end until:

  1. The process completes, OR
  2. The agent explicitly acknowledges detachment

Observed behavior:

  • Agent calls exec_command with a long-running command
  • Process starts, returns process_id
  • Model generates response text
  • ResponseEvent::Completed fires
  • has_pending_input() returns false
  • Turn ends — agent loses opportunity to wait for output

What steps can reproduce the bug?

  1. Start a Codex session
  2. Ask the agent to run a long-running command:

``
Run
sleep 30 && echo "done" and tell me when it finishes
``

  1. Observe that the turn ends immediately after the agent starts the command
  2. The agent never reports "done" because it doesn't wait for the process

Alternative reproduction with training script:

Run `uv run train.py` and analyze the results when it completes

The agent starts the 5-minute training script but the turn ends within seconds.

Code path:

  1. exec_command is called → process starts → process_id returned (process still running)
  2. Model generates text response
  3. ResponseEvent::Completed triggers
  4. has_pending_input()false (no tool responses queued)
  5. needs_follow_up = false
  6. Turn ends

What is the expected behavior?

When a unified_exec process started in the current turn is still running, the turn should NOT complete. Instead:

  1. Codex should detect running processes via unified_exec_manager.process_store
  2. Inject a warning message to the model (e.g., "A background terminal is still running...")
  3. Set needs_follow_up = true to continue the turn
  4. Allow the model to either:
  • Wait for the process (call write_stdin to poll)
  • Explicitly acknowledge detachment

This enables reliable execution of long-running commands and autonomous workflows.

Additional information

I have implemented a fix in branch raman/fix/turn-end-guard-running-processes, commit https://github.com/openai/codex/commit/c2845daf318e70a08ccb579c99a7b45fc8c423dc:

// In ResponseEvent::Completed handler:
if !needs_follow_up && sess.has_running_unified_exec_processes(&turn_context).await {
    sess.record_model_warning(
        "A background terminal started in this turn is still running. \
        If you intend to keep waiting for it, call write_stdin on the existing \
        process_id instead of ending the turn. If you are intentionally done \
        waiting, explicitly say that you are detaching from the background process.",
        &turn_context,
    ).await;
    needs_follow_up = true;
}

Files changed:

  • codex-rs/core/src/codex.rs — added has_running_unified_exec_processes() method, modified ResponseEvent::Completed handling
  • codex-rs/core/src/unified_exec/mod.rs — made process_store, ProcessEntry accessible
  • codex-rs/core/src/unified_exec/process.rs — made has_exited() pub(crate)
  • codex-rs/core/src/codex_tests.rs — unit test
  • codex-rs/core/src/unified_exec/mod_tests.rs — integration tests

All tests pass (3 new tests added).

Context: Discovered while working on autoresearch — autonomous AI research platform where agents run 5-minute training experiments. This bug makes autonomous experiment loops impossible.

I don't currently have PR access. Happy to provide the complete diff or adjust implementation based on maintainer feedback.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗