What Happens When a Background Task Is Cancelled in Codex: Turn Interrupt or Process Termination?
When you cancel a background task in the Codex runtime, the system first attempts a turn interrupt against the remote Claude session, then falls back to terminating the underlying OS process tree if necessary.
Cancelling a background task in the openai/codex-plugin-cc repository is not a simple process kill. Instead, the runtime implements a coordinated two-phase shutdown that prioritizes graceful interruption of the AI turn before forcing process termination.
The Two-Phase Cancellation Sequence
The Codex runtime handles cancellation through a specific orchestration between the app-server and the local process manager. This ensures that brokered tasks receive proper cleanup signals before hard termination.
Phase 1: Turn Interrupt Attempt
When you issue a cancel command, the runtime first sends a turn interrupt request to the shared app-server coordinating the remote Claude turn. This is recorded in the cancellation payload with turnInterruptAttempted: true in the JSON response. If the interrupt succeeds, the payload includes turnInterrupted: true, allowing the Claude session to exit gracefully and release resources.
This phase applies specifically to tasks that are actively engaged in a Claude turn. The interrupt signals the AI to stop processing without immediately killing the underlying worker.
Phase 2: Process Termination Fallback
If the turn interrupt fails or the job does not belong to an active Claude turn, the runtime proceeds to process termination. The terminateProcessTree function in plugins/codex/scripts/lib/process.mjs handles the actual OS-level cleanup.
On Unix systems, this kills the entire process group. On Windows, it uses taskkill to terminate the process tree. This ensures no zombie processes remain regardless of platform.
How to Cancel a Background Task
Use the codex-companion.mjs CLI to cancel specific jobs by ID. The --json flag returns detailed status about the interruption attempt.
# Cancel a specific background job (e.g., "task-live")
node scripts/codex-companion.mjs cancel task-live --json
The command returns a JSON object indicating whether the turn interrupt succeeded:
{
"status": "cancelled",
"turnInterruptAttempted": true,
"turnInterrupted": true,
"jobId": "task-live"
}
If turnInterrupted is false, the runtime has proceeded directly to process termination or the interrupt timed out.
Key Implementation Files
The cancellation logic spans three critical files in the repository:
plugins/codex/scripts/lib/process.mjs– ImplementsterminateProcessTree, which kills the process group on Unix or invokestaskkillon Windows.plugins/codex/scripts/codex-companion.mjs– Handles thecancelcommand, constructs the cancellation payload, and triggers the turn interrupt request.tests/runtime.test.mjs– Contains unit tests verifying that cancellation sends the turn interrupt signal and correctly marks jobs as cancelled.
Summary
- Background task cancellation is a two-step procedure, not a single kill signal.
- The runtime first attempts a turn interrupt via the shared app-server to gracefully stop the Claude session.
- If the interrupt fails or is inapplicable,
terminateProcessTreeforcefully kills the OS process group. - The JSON response distinguishes between
turnInterruptAttemptedandturnInterruptedto indicate success at the AI layer versus the process layer.
Frequently Asked Questions
Does cancelling a background task immediately kill the process?
No. According to the source code in openai/codex-plugin-cc, cancellation first attempts a turn interrupt to gracefully stop the Claude session. Process termination via terminateProcessTree only occurs if the interrupt fails or the task is not associated with an active turn.
What is the difference between turn interrupt and process termination?
A turn interrupt signals the remote Claude app-server to stop the current AI turn gracefully, setting turnInterrupted: true in the response. Process termination invokes terminateProcessTree in plugins/codex/scripts/lib/process.mjs to kill the underlying OS process tree using Unix process groups or Windows taskkill.
How can I verify if a turn interrupt succeeded?
Check the JSON output from the cancel command. If turnInterrupted: true appears in the response, the Claude session was successfully interrupted. If only turnInterruptAttempted: true is present, the system proceeded to process termination instead.
Is the cancellation behavior different on Windows versus Unix systems?
The high-level two-phase sequence remains identical, but the process termination implementation differs. On Unix, terminateProcessTree kills the process group, while on Windows it uses taskkill. Both ensure complete cleanup of the background task's process tree.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →