Skip to content

Resume and interrupt Codex sessions (#395) - #405

Merged
JacobStephens2 merged 2 commits into
issue-136from
issue-395
Oct 5, 2026
Merged

JacobStephens2 merged 2 commits into
issue-136from
issue-395

Conversation

@JacobStephens2

Copy link
Copy Markdown
Owner

Summary

Codex sessions now handle killed background work and interrupts the way Claude sessions do. The Resume path, codex exec … resume <thread id> with every flag passed again, already came from #394. This PR adds the sub-agent case, interrupts, and the tests the issue asks for.

 CodexProgress::item(item)
   command_execution
     track_running(id, item, unwrapped command)
+  collab_tool_call
+    track_running(id, item, "agent spawn_agent: <first line of its prompt>")
 turn.completed
   killed = still running   # each gets the one Resume, as on Claude
 stop(child, harness)
-  SIGTERM, wait 10s
+  for signal in harness.stop_signals()   # Codex: SIGINT, SIGTERM · Claude: SIGTERM
+    send signal, wait 10s
   SIGKILL

The fake codex now catches SIGINT and SIGTERM and waits for its script, so each test's script decides how the session stops and records which signals reached it.

Evidence

  • Before: an_interrupt_sends_a_codex_session_sigint_and_the_run_ends_as_interrupted failed. Its agent recorded TERM\n, where the test expects INT\n. a_sub_agent_call_still_running_when_the_turn_completes_is_killed_background_work failed with no killed work.
    After: all 12 tests in tests/codex_sessions.rs pass, and so does the full cargo test suite. The new tests:
    • a sub-agent left running gets the one Resume, on resume fake-thread-1
    • a Resume that ends the same way gets no second Resume, and the failed Run's cause names cargo test
    • 4 Repairs each get a Resume (10 sessions in all), and the Run still reaches starting Repair 5 of 5 and goes green
    • an interrupt: the session receives INT only, and the Run ends with thirdshift: failed run (interrupted)
    • a session that ignores SIGINT receives INT and then TERM

Merge Danger

Door: two-way

Blast Radius: Codex sessions only

Claude sessions still get SIGTERM, then SIGKILL. A Codex session that ignores SIGINT can now take up to 20s to stop, where it took 10s before.

Unaddressed findings

Standards

  • running: Vec<(String, String)> is a tuple standing in for a type (Primitive Obsession). This predates the change, and the PR only rewords its doc.
  • The Codex Resume tests overlap tests/background_work.rs. I kept them on purpose: the acceptance criteria ask for this behaviour on Codex end to end, through Codex's own stream and arguments.

Spec

  • The research doc says a sub-agent may be still running when its collab_tool_call has completed, through agents_states. The issue defines killed work as "item.started but no item.completed", and that is what the code follows. The research doc marks the agents_states signal as inference that needs a live check, so I left it out.
  • A wait, send_input or close_agent call still in progress at turn end also counts as killed work. This rarely happens. When it does, a Resume is the right response anyway: the session stopped mid-call.
  • SIGINT goes to the session's whole process group, not to codex alone. That matches how SIGTERM is already sent. Codex puts the commands it spawns in their own groups, so in practice only codex receives it.

Closes #395

🤖 Generated with Claude Code

JacobStephens2 and others added 2 commits October 5, 2026 01:40
…em with SIGINT first (#395)

A Codex sub-agent call still running at turn end is now killed background
work, as a command is, so its session gets the one Resume. An interrupt
sends a Codex session SIGINT, the only signal Codex stops cleanly on,
before SIGTERM and SIGKILL. Tests cover the Resume on Codex ending the
same way, counting against no Repair cap, and the interrupt order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lled-work tracking (#395)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JacobStephens2
JacobStephens2 merged commit 51feb30 into issue-136 Oct 5, 2026
13 checks passed
@JacobStephens2
JacobStephens2 deleted the issue-395 branch October 5, 2026 05:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant