Skip to content

Preserve background terminals on interrupt and rename cleanup command to /stop#14602

Merged
friel-openai merged 1 commit intomainfrom
dev/codex/rename-/clear-and-modify-ctrl-c-behavior
Mar 16, 2026
Merged

Preserve background terminals on interrupt and rename cleanup command to /stop#14602
friel-openai merged 1 commit intomainfrom
dev/codex/rename-/clear-and-modify-ctrl-c-behavior

Conversation

@friel-openai
Copy link
Copy Markdown
Contributor

Motivation

  • Interrupting a running turn (Ctrl+C / Esc) currently also terminates long‑running background shells, which is surprising for workflows like local dev servers or file watchers.
  • The existing cleanup command name was confusing; callers expect an explicit command to stop background terminals rather than a UI clear action.
  • Make background‑shell termination explicit and surface a clearer command name while preserving backward compatibility.

Description

  • Renamed the background‑terminal cleanup slash command from Clean (/clean) to Stop (/stop) and kept clean as an alias in the command parsing/visibility layer, updated the user descriptions and command popup wiring accordingly.
  • Updated the unified‑exec footer text and snapshots to point to /stop (and trimmed corresponding snapshot output to match the new label).
  • Changed interrupt behavior so Op::Interrupt (Ctrl+C / Esc interrupt) no longer closes or clears tracked unified exec / background terminal processes in the TUI or core cleanup path; background shells are now preserved after an interrupt.
  • Updated protocol/docs to clarify that turn/interrupt (or Op::Interrupt) interrupts the active turn but does not terminate background terminals, and that thread/backgroundTerminals/clean is the explicit API to stop those shells.
  • Updated unit/integration tests and insta snapshots in the TUI and core unified‑exec suites to reflect the new semantics and command name.

Testing

  • Ran formatting with just fmt in codex-rs (succeeded).
  • Ran cargo test -p codex-protocol (succeeded).
  • Attempted cargo test -p codex-tui but the build could not complete in this environment due to a native build dependency that requires libcap development headers (the codex-linux-sandbox vendored build step); install libcap-dev / make libcap.pc available in PKG_CONFIG_PATH to run the TUI test suite locally.
  • Updated and accepted the affected insta snapshots for the TUI changes so visual diffs reflect the new /stop wording and preserved interrupt behavior.

Codex Task

@friel-openai friel-openai added the codex Label used by connector to tag PRs that have been reviewed by Codex label Mar 13, 2026 — with ChatGPT Codex Connector
Copy link
Copy Markdown
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a4dac1c67d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Rollout,
Ps,
Clean,
#[strum(serialize = "stop", serialize = "clean")]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Make /stop the canonical serialized name for Stop command

Defining Stop as #[strum(serialize = "stop", serialize = "clean")] breaks lookup: command() uses IntoStaticStr, which selects Strum's preferred serialization (longest string), so this variant resolves to "clean". find_builtin_command matches only that canonical name, so /stop is not recognized even though UI/docs now instruct users to run /stop.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@codex fix comments

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Testing

  • just fmt
  • ⚠️ cargo test -p codex-tui (fails in this environment because codex-linux-sandbox’s build script cannot find libcap/libcap.pc via pkg-config)
  • ⚠️ curl -I https://docs.rs/strum/latest/strum/derive.IntoStaticStr.html | head (web lookup attempt blocked by proxy with HTTP 403)

Committed as 664b77a and created a follow-up PR via the make_pr tool.

View task →

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@codex No, I don't like that design. We shouldn't change the derive in codex-rs/tui/src/slash_command.rs, instead we should fix the enum variant or member.

I'm skeptical of your design.

Isn't it simpler to

#[strum(serialize = "stop", serialize = "clean")] 
Stop,

Change the command variant to Clean and allow it to accept stop as an alternative serialization?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Testing

  • just fmt
  • ⚠️ cargo test -p codex-tui (fails in this environment because codex-linux-sandbox requires system libcap/libcap.pc via pkg-config)

View task →

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@codex fix these tests. the first might be a red herring - a race? but look into it anyhow

────────────
Nextest run ID 5b5b8d29-401d-4c11-abc6-3ee4f5e0d6e5 with nextest profile: default
Starting 5612 tests across 132 binaries (28 tests skipped)
SLOW [> 15.000s] (─────────) codex-core unified_exec::tests::unified_exec_timeouts
FAIL [ 0.454s] (3244/5612) codex-core::all suite::unified_exec::unified_exec_interrupt_preserves_long_running_session
stdout ───

running 1 test
test suite::unified_exec::unified_exec_interrupt_preserves_long_running_session ... FAILED

failures:

failures:
    suite::unified_exec::unified_exec_interrupt_preserves_long_running_session

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 803 filtered out; finished in 0.44s

stderr ───
kill: 1155: No such process

thread 'suite::unified_exec::unified_exec_interrupt_preserves_long_running_session' (257029) panicked at core/tests/suite/unified_exec.rs:2096:5:
expected unified exec process to remain alive after interrupt
stack backtrace:
   0: __rustc::rust_begin_unwind
             at /rustc/254b59607d4417e9dffbc307138ae5c86280fe4c/library/std/src/panicking.rs:689:5
   1: core::panicking::panic_fmt
             at /rustc/254b59607d4417e9dffbc307138ae5c86280fe4c/library/core/src/panicking.rs:80:14
   2: all::suite::unified_exec::unified_exec_interrupt_preserves_long_running_session::{{closure}}
             at ./tests/suite/unified_exec.rs:2096:5
   3: <core::pin::Pin<P> as core::future::future::Future>::poll
             at /Users/runner/.rustup/toolchains/1.93.0-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/future/future.rs:133:9
   4: tokio::runtime::park::CachedParkThread::block_on::{{closure}}
             at /Users/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/runtime/park.rs:284:71
   5: tokio::task::coop::with_budget
             at /Users/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/task/coop/mod.rs:167:5
   6: tokio::task::coop::budget
             at /Users/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/task/coop/mod.rs:133:5
   7: tokio::runtime::park::CachedParkThread::block_on
             at /Users/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/runtime/park.rs:284:31
   8: tokio::runtime::context::blocking::BlockingRegionGuard::block_on
             at /Users/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/runtime/context/blocking.rs:66:14
   9: tokio::runtime::scheduler::multi_thread::MultiThread::block_on::{{closure}}
             at /Users/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/runtime/scheduler/multi_thread/mod.rs:89:22
  10: tokio::runtime::context::runtime::enter_runtime
             at /Users/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/runtime/context/runtime.rs:65:16
  11: tokio::runtime::scheduler::multi_thread::MultiThread::block_on
             at /Users/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/runtime/scheduler/multi_thread/mod.rs:88:9
  12: tokio::runtime::runtime::Runtime::block_on_inner
             at /Users/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/runtime/runtime.rs:370:50
  13: tokio::runtime::runtime::Runtime::block_on
             at /Users/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/runtime/runtime.rs:342:18
  14: all::suite::unified_exec::unified_exec_interrupt_preserves_long_running_session
             at ./tests/suite/unified_exec.rs:2104:7
  15: all::suite::unified_exec::unified_exec_interrupt_preserves_long_running_session::{{closure}}
             at ./tests/suite/unified_exec.rs:2021:69
  16: core::ops::function::FnOnce::call_once
             at /Users/runner/.rustup/toolchains/1.93.0-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5
  17: core::ops::function::FnOnce::call_once
             at /rustc/254b59607d4417e9dffbc307138ae5c86280fe4c/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

    FAIL [   0.221s] (4582/5612) codex-tui bottom_pane::slash_commands::tests::clean_command_alias_resolves_for_dispatch

stdout ───

running 1 test
test bottom_pane::slash_commands::tests::clean_command_alias_resolves_for_dispatch ... FAILED

failures:

failures:
    bottom_pane::slash_commands::tests::clean_command_alias_resolves_for_dispatch

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 1316 filtered out; finished in 0.21s

stderr ───

thread 'bottom_pane::slash_commands::tests::clean_command_alias_resolves_for_dispatch' (273078) panicked at tui/src/bottom_pane/slash_commands.rs:95:9:
assertion failed: `(left == right)`

Diff < left / right > :
<None
>Some(
>    Stop,
>)


stack backtrace:
   0: __rustc::rust_begin_unwind
             at /rustc/254b59607d4417e9dffbc307138ae5c86280fe4c/library/std/src/panicking.rs:689:5
   1: core::panicking::panic_fmt
             at /rustc/254b59607d4417e9dffbc307138ae5c86280fe4c/library/core/src/panicking.rs:80:14
   2: codex_tui::bottom_pane::slash_commands::tests::clean_command_alias_resolves_for_dispatch
             at ./src/bottom_pane/slash_commands.rs:95:9
   3: codex_tui::bottom_pane::slash_commands::tests::clean_command_alias_resolves_for_dispatch::{{closure}}
             at ./src/bottom_pane/slash_commands.rs:94:51
   4: core::ops::function::FnOnce::call_once
             at /Users/runner/.rustup/toolchains/1.93.0-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5
   5: core::ops::function::FnOnce::call_once
             at /rustc/254b59607d4417e9dffbc307138ae5c86280fe4c/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

────────────
Summary [ 165.095s] 5612 tests run: 5610 passed (1 slow), 2 failed, 28 skipped
FAIL [ 0.454s] (3244/5612) codex-core::all suite::unified_exec::unified_exec_interrupt_preserves_long_running_session
FAIL [ 0.221s] (4582/5612) codex-tui bottom_pane::slash_commands::tests::clean_command_alias_resolves_for_dispatch
error: test run failed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

  • Updated built-in slash-command resolution to support both canonical names and aliases in dispatch: find_builtin_command now first matches the visible canonical command string, then falls back to parsing aliases (like clean) and maps them back through visible built-ins so /clean correctly resolves to SlashCommand::Stop. codex-rs/tui/src/bottom_pane/slash_commands.rsL39-L55
  • Changed unified-exec process lifecycle so spawned processes are persisted before waiting for the initial yield window; this prevents interrupt-time cancellation from dropping an in-flight long-running process before it is tracked as a background terminal. Also simplified post-collection cleanup so exited processes are released from the store in one path. codex-rs/core/src/unified_exec/process_manager.rsL153-L267

Testing

  • just fmt
  • ⚠️ cargo test -p codex-tui clean_command_alias_resolves_for_dispatch -- --nocapture (build blocked in this environment: missing system libcap / libcap.pc required by codex-linux-sandbox)
  • ⚠️ cargo test -p codex-core unified_exec_interrupt_preserves_long_running_session -- --nocapture (same libcap environment limitation)

Committed as 1f8ef85, and I also created the follow-up PR via the make_pr tool.

View task →

@friel-openai friel-openai force-pushed the dev/codex/rename-/clear-and-modify-ctrl-c-behavior branch 2 times, most recently from 2e91351 to 8334001 Compare March 14, 2026 20:29
Preserve background unified-exec processes across interrupts, keep /stop as the cleanup command, and collapse the branch back to a single commit for easier future restacks.
@friel-openai friel-openai merged commit ba463a9 into main Mar 16, 2026
32 checks passed
@friel-openai friel-openai deleted the dev/codex/rename-/clear-and-modify-ctrl-c-behavior branch March 16, 2026 05:17
@github-actions github-actions bot locked and limited conversation to collaborators Mar 16, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

codex Label used by connector to tag PRs that have been reviewed by Codex

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants