Skip to content

Event-driven wakeup when background exec sessions complete #32188

Open

Description

@praveenperera

What variant of Codex are you using?

cli

What feature would you like to see?

Description

Long-running commands currently require the model to poll write_stdin, remain inside a long-running tool call, or delegate monitoring to a subagent. Repeated polling creates additional model turns, while a monitoring subagent adds its own context and reasoning costs.

Codex already waits for background processes asynchronously and emits an ExecCommandEnd event when they exit. It would be useful to optionally wake an idle thread when that event occurs.

Proposed behavior

Add an opt-in completion mode to exec_command:

{
  "cmd": "just test",
  "yield_time_ms": 1000,
  "on_exit": "wake"
}

on_exit could accept:

  • "none": preserve the current behavior and require explicit polling
  • "wake": resume the thread once the background process exits

When "wake" is selected and the command yields a background session, Codex should:

  1. Allow the current turn to finish and become idle.
  2. Wait for the process without model inference.
  3. Enqueue a bounded completion notification when the process exits.
  4. Start one continuation turn containing the exit status, duration, and a capped output summary.
  5. Avoid a duplicate continuation if completion was already observed through write_stdin.

The tool response should make it clear that automatic notification is registered and polling is unnecessary.

Motivation

This would make long-running tests, builds, deployments, and similar commands event-driven instead of polling-driven. It would reduce unnecessary model turns and remove the need to create “babysitter” subagents solely to monitor process completion.

A recent agent run used many high-effort subagents and thousands of model cycles, accumulating roughly 470 million subagent tokens. Process monitoring was not the only source of that usage, but native completion wakeups would eliminate one avoidable class of polling and monitoring work.

Important cases

  • Existing behavior remains unchanged when on_exit is omitted.
  • Completion wakes an idle thread exactly once.
  • Completion arriving around the turn’s answer boundary is not lost.
  • Manually observing completion does not cause a later duplicate wakeup.
  • Injected command output is strictly bounded.
  • Multiple processes completing close together do not create an unbounded number of continuation turns.
  • Cancellation and session shutdown do not produce stale wakeups.

This could reuse the existing background exit watcher and pending-work scheduling mechanisms rather than requiring an active model turn while the process runs.

Additional information

No response

Activity

  1. added
    CLIIssues related to the Codex CLI
    tool-callsIssues related to tool calling
    on Jul 10, 2026
  2. github-actions commented on Jul 10, 2026

    @github-actions
    Contributor

    Potential duplicates detected. Please review them and close your issue if it is a duplicate.

    Powered by Codex Action

  3. praveenperera commented on Jul 10, 2026

    @praveenperera
    Author

    POC implementation https://github.com/praveenperera/codex/tree/32188-poc-impl @fcoury

    More fleshed out implementation here, along with a small UI change so the subagent model and reasoning level is displayed in the TUI: https://github.com/praveenperera/codex/tree/wait-fork

  4. markgerrard commented on Jul 17, 2026

    @markgerrard

    Why stock can't do this today, cited to lines (verified at rust-v0.144.5, still true at rust-v0.145.0-alpha.20):

    • When a backgrounded unified_exec process exits while the session is idle, the exit-watcher's tail is UI-only: it emits an outbound ExecCommandEnd client event and stops.
    • The TUI completion handler drops that event exactly in the idle case — tui/src/chatwidget/command_lifecycle.rs:154, if !self.bottom_pane.is_task_running() { return; }.
    • The stock idle-start path (maybe_start_turn_for_pending_work) is mailbox-driven only; a background exit is not a mailbox source, and nothing else submits work for it. The wait works; the wake doesn't exist.

    Related reports that are this same gap from the user side: #14314, #22957, #12033, and #33542 (config-level flavor of this request); #31935 is the polling-pain cousin. I filed #33712 before finding this thread and am closing it in favor of here.

    Implementation status: we run codex as a multi-agent orchestrator and hit this daily, so we built the wake path — currently in production soak as our daily driver, and we intend to open it as a small stacked series once the soak completes. Behind a default-off flag: background exit while idle wakes the session and resumes the original thread with exit code and output rendered as turn input; exits during an active turn are queued and drained when it finishes; the wake routes through the serialized submission loop as an internal op, so aborts and capacity limits compose without new race surface.

    @praveenperera your "Important cases" list turned out to be the right acceptance criteria — each of them is closed in our test matrix (exactly-once wake, completion at the answer boundary not lost, no duplicate after manual observation via write_stdin, bounded injected output, multiple near-simultaneous exits batched into one continuation, no stale wakeups across cancellation/shutdown). Production forced two cases onto the list that it doesn't have yet, sharing them here since they cost us the most review rounds: kill/interrupt attribution (an exit induced by a kill, interrupt, or session teardown must not wake — otherwise every abort path produces a phantom continuation) and capacity-ceiling composition (what a wake does when the session is at its concurrency ceiling: we gate and degrade to today's stock behavior rather than overshoot).

    The PoC (32188-poc-impl) hits the right seams — completion_wakeup, the input-queue hook, a completion fragment — clearly written by someone who read this code carefully. On the API surface: per-call on_exit is arguably the better surface (finer intent, no global behavior change); our config flag was the orchestrator-shaped choice. The honest technical point is that our core is trigger-agnostic — the queue/wake/attribution machinery doesn't care whether the opt-in arrives per-call or per-config, so it can sit under your surface, ours, or both. If you're open to it, I'd be glad to converge on one stacked series: your API shape on our hardened core. Design notes available in the meantime.

  5. Alex-R-A commented on Jul 26, 2026

    @Alex-R-A

    Independent reproduction on stock Codex CLI 0.145.0

    Confirmed twice on macOS arm64. One test used a real externally triggered detector rather than a fixed sleep, so the failure is not specific to timer commands.

    Reproduction

    1. Start a command through tracked unified exec and let it yield as still running.
    2. Allow the Codex turn to finalize so the TUI becomes idle.
    3. Let the tracked process exit normally.
    4. Observe that its completion and output are retained, but no new model turn starts.
    5. Send a user message. The resulting turn can then inspect the already completed process.

    Result: 0 automatic wakes in 2 controlled trials.

    One recorded timeline:

    • Codex turn finalized: 2026-07-26T17:10:10.676Z
    • External event caused the tracked process to complete: shortly after 2026-07-26T17:11:17Z
    • Human message started the next Codex turn: 2026-07-26T17:17:03.600Z

    No Codex inference occurred during the 346.6 seconds between the external event and the human message.

    Control

    A tracked sleep 2 completion reached Codex when the originating model turn was still active. The background process manager and completion-event path therefore work. The missing transition is specifically from an idle completion to new model inference.

    Source confirmation

    In stable 0.145.0 and current main, on_command_execution_completed records the process end and then returns when bottom_pane.is_task_running() is false. That idle path does not enqueue pending work or start a turn. This matches the observed behavior.

    Requested behavior

    An opt-in wake mode should:

    • Let the current turn finish while the process continues without model inference.
    • Start exactly one continuation turn if the tracked process exits while the thread is idle.
    • Queue the completion if another turn is active, rather than starting concurrent inference.
    • Include bounded exit status, duration, and output.
    • Suppress a later wake if write_stdin already consumed the completion.
    • Preserve completions that race with the final-answer boundary.
    • Coalesce multiple near-simultaneous completions.
    • Avoid wakeups caused by cancellation, kill, interrupt, or session shutdown.

    An optional exit-code allowlist would also help finite watchers suppress expected timeout exits while still waking for real events. Its default can remain all exit codes so failed builds and tests still wake.

    This is useful beyond timers: long builds, test suites, deployments, CI monitors, and external event detectors currently require polling, an occupied model turn, a human nudge, or a custom client that explicitly starts another turn.

  6. lunara69-ctrl commented on Aug 24, 2026

    @lunara69-ctrl

    +1 from an independent Codex CLI audit.

    The distinction between “waiting” and “model inference caused by waiting” appears important.

    In one audited workflow I found 58 WAIT/POLL continuations with no new useful information. They accounted for 6,787,563 input tokens (~117k per continuation on average), because each wake-up occurred against an already large parent context.

    This suggests that event-driven wakeup could have a larger impact than simply reducing tool-call chatter: it removes an entire class of parent inference whose semantic content is effectively zero.

    For benchmarking this feature, I would suggest measuring not only wall time or number of polls, but:

    WAIT_MAIN_INPUT = total parent-model input caused exclusively by waiting for an external operation to reach a terminal state.

    For an ideal runtime-managed wait, that metric should be 0 until an actual completion event exists.

  7. Charle4 commented on Sep 5, 2026

    @Charle4

    Adding a concrete user workflow where this missing primitive is currently a significant blocker.

    I use coding agents for research / ML experimentation, where a typical workflow is not one long command but several independent long-running jobs managed concurrently from the same parent agent:

    1. Launch experiments / evaluations A, B, and C in the background.
    2. Let the parent turn finish and become genuinely idle — no model polling or monitoring subagent should be required while the jobs are simply running.
    3. Whichever job completes first should emit a bounded completion event and wake the same parent thread exactly once.
    4. The parent inspects the result, analyzes metrics/logs, decides what to do next, and may immediately launch experiment D or a corrected rerun.
    5. The parent becomes idle again while the remaining jobs continue; each can independently trigger the same process later.

    So for this workflow the missing idle -> completion event -> continuation turn transition is more than a token-efficiency issue. It prevents the agent from acting as an event-driven orchestrator for a dynamic experiment DAG. Today the practical choices are to keep the parent alive polling, dedicate a subagent to polling, or manually come back and prompt Codex after a job finishes. All three largely defeat the purpose of first-class background execution.

    The behavior I would consider sufficient is essentially what this issue already proposes, with particular importance for multiple simultaneous outstanding jobs:

    • opt-in completion wake per background task;
    • zero model inference while all jobs are merely running;
    • exactly-once wake on normal completion;
    • queue/coalesce completion if another turn is active;
    • bounded stdout/stderr + exit status/duration in the completion event;
    • no duplicate wake if the completion was already consumed manually;
    • cancellation/interrupt/session teardown must suppress stale wakes;
    • several background jobs can remain independently tracked and wake the same parent over time.

    This is currently one of the main reasons I use Claude Code instead of Codex for long-running research/experiment workflows: background Bash/subagents can complete asynchronously and notify/wake the main agent, which makes this kind of multi-experiment orchestration natural. Codex's model capabilities are otherwise well suited to the workflow; the blocker is the harness/runtime scheduling semantics.

    Related end-to-end monitoring/orchestration request: #32993. For the narrower primitive, I think this issue (#32188) is the right canonical place rather than opening another duplicate.

  8. KaiStarkk commented on Sep 8, 2026

    @KaiStarkk

    I believe this is already possible. The method below successfully woke an idle Codex desktop task after a background command finished.

    • Tested on Linux/NixOS with codex-cli 0.153.4, using a locally packaged build with an unrelated logging patch.
    • codex queue --thread UUID --message TEXT delivered a message to the existing desktop task and triggered a new turn.
    • The test used a detached 15-second sleep. The originating turn ended before completion; no model polling was needed.

    To reproduce, ask Codex to run the following with the current task’s UUID, then end its turn:

    systemd-run --user \
      --unit=codex-completion-test \
      --collect \
      "$(command -v bash)" -c '
        sleep 15
        "$1" queue --thread "$2" \
          --message "The 15-second test finished. Confirm receipt without starting another test."
      ' _ "$(command -v codex)" YOUR_THREAD_UUID

    The command runs independently of the originating tool session. After 15 seconds, it submits the completion message through the CLI. Check delivery errors with:

    journalctl --user -u codex-completion-test --no-pager

    For an actual build, replace sleep 15 with the build command, redirect its output to an absolute log path, capture $?, and include the exit status and log path in the queued message. Queue after either success or failure, rather than using &&.

    The important part is detached execution followed by codex queue; systemd is simply the launcher used in this test. The CLI must be able to reach the target session, and its executable must be available to the detached process.

    This is one successful idle-task test. It doesn’t establish cancellation handling, deduplication, simultaneous completions, or behaviour when another turn is active. A native on_exit: "wake" option would still avoid requiring users to assemble those pieces themselves.

    Hope this provides a useful interim workaround.

  9. mkXultra commented on Sep 16, 2026

    @mkXultra

    I implemented and tested a completion-driven continuation in a personal fork. This is a reference implementation for this request, not a fix landed upstream.

    For the local interactive CLI, background command completion queues a bounded notification and resumes the same thread when idle. If another turn is active, completion is retained for a later idle boundary without interrupting or steering that turn. Existing explicit result retrieval remains available; observation/cancellation handling prevents stale or duplicate automatic continuations. No inference is needed just to poll a running command.

    A local smoke test started a background command, ended the assistant turn, and observed an automatic continuation after process exit without write_stdin polling. The command-completion implementation is commit adf2e13f4b. The linked build also includes Cell completion wake and a subsequent Cell worker-lifetime fix.

    Differences from this issue's proposal: the fork enables this behavior by default for the local interactive path rather than adding an on_exit argument. It does not implement durable completion delivery across process restarts or promise equivalent behavior for non-interactive codex exec.

    Trying the fork

    Successful GitHub Actions build and downloads, built from commit af1f26f725:

    These are unofficial fork artifacts, not an upstream release. GitHub sign-in may be required to download them; the current artifacts expire on October 15, 2026. Extract the package inside the downloaded artifact and keep its bin directory together, including codex-code-mode-host and the other bundled helpers. Run bin/codexg (bin/codexg.exe on Windows). The fork uses the normal Codex configuration/authentication/history by default. Keep the bundle in its own directory to avoid replacing an installed upstream CLI or its helpers.

    All three builds/package checks passed. End-to-end wake testing was performed locally on Linux; CI success is not a claim of full wake-behavior testing on macOS or Windows.

  10. lucaschang2021 commented on Sep 17, 2026

    @lucaschang2021

    One concrete implementation seam from current main that may help extend this beyond unified_exec to subagents:

    AgentControl::maybe_start_completion_watcher already creates a detached watcher for spawned child threads and subscribes until AgentStatus becomes final. In other words, the runtime already owns a cheap completion signal for subagents.

    The interesting part is what happens next:

    • MA v2 formats the completion and sends InterAgentCommunication::new(..., /*trigger_turn*/ false).
    • The legacy path calls inject_fragment_without_turn(...).

    So subagent completion is already machine-observable and queued, but intentionally non-waking.

    There is also already a safe turn-start path in send_inter_agent_communication: when communication.trigger_turn is true it checks execution capacity before submitting the turn.

    That suggests a relatively clean extension of the #32188 primitive: don't make every child completion wake the parent; instead add an explicit parent-owned completion-wake registration for a specific child handle. Then the existing completion watcher can choose between queue-only delivery and exactly-once wake based on whether that registration is armed.

    Conceptually:

    spawn/yield child
      -> optional CompletionWakeRegistration(parent, child)
      -> parent becomes idle
      -> child watcher waits without inference
      -> child terminal status
      -> if registration armed: enqueue bounded result + trigger one capacity-checked turn
      -> else: preserve today's queue-only behavior
    

    The registration should still carry the same armed/completed/observed/cancelled semantics discussed here so wait_agent manual observation can suppress a duplicate wake and kill/teardown cannot produce a phantom continuation.

    This also gives process and subagent waits the same runtime contract: completion events may wake inference; liveness alone should not.

  11. ToxicToxster commented on Sep 17, 2026

    @ToxicToxster

    Real-world autonomous-run use case

    I strongly support this. I recently observed another coding-agent host providing essentially this behavior for long-running local background commands: the agent launches a process, becomes inactive while the process runs, and is resumed by the host when the background task terminates. No model-mediated polling is needed in between.

    This becomes especially valuable for autonomous engineering/scientific workflows, not just builds and tests.

    Example:

    agent
    -> starts local solver / benchmark / training job
    -> registers wake-on-exit
    -> model inference stops completely

    local process runs for minutes or hours

    process exits
    -> runtime emits completion event
    -> agent resumes exactly once
    -> reads durable result artifacts
    -> decides the next action

    In my current workload, the alternative is particularly expensive: a cloud reasoning model supervising a deterministic local solver by periodically checking process state and result files can burn a substantial portion of a finite weekly inference quota while contributing no useful reasoning during the wait.

    The important architectural property is that the local process and durable artifacts remain the source of truth. The LLM does not need to stay alive as a state store or watchdog. It only needs to be resumed when an event requires reasoning.

    For an autonomous-run mode I would ideally want:

    exec_command(..., on_exit="wake")

    with:

    zero model calls while waiting;
    exactly-once wakeup on exit;
    exit code + PID/session identity + duration in the wake event;
    bounded stdout/stderr tail or artifact references;
    no duplicate wake if completion was already observed manually;
    fail-safe delivery if completion occurs around a turn boundary;
    optional persistence across app-server/session-host restarts;
    cancellation semantics that prevent stale wakeups.

    A slightly more general primitive could later support:

    on_exit
    on_failure
    on_output_match
    on_file_change
    on_artifact_created

    but process-exit wakeup alone would already eliminate a large class of wasteful polling loops.

    One additional use case is a local autonomous supervisor:

    solver cycle 1873
    |
    +-- normal completion --> local supervisor starts 1874
    |
    +-- architecture stop --> wake Codex
    |
    +-- integrity failure --> wake Codex
    |
    +-- final candidate ----> wake Codex

    In that design Codex may remain asleep for hours while deterministic work progresses locally, and inference is spent only at decision boundaries.

    This seems like a very natural fit for the existing ExecCommandEnd / pending-work machinery described in this issue.

  12. praveenperera commented on Sep 18, 2026

    @praveenperera
    Author

    I've been experiment with this, https://github.com/avencera/homebased it works with the codex queue primitive.

  13. LawrentChen commented on Sep 21, 2026

    @LawrentChen

    Hi guys. I am not a professional developer, but I made my tiny solution (a skill) for this polling issue in long-run tasks.

    https://github.com/LawrentChen/codex_callback

    For me it works pretty well. It allows the thread to be smoothly awakened and take over each time(can be more than once) the long-run task encounters a problem, and after completing phased tasks, it smoothly transitions to downstream docking tasks, requiring no polling or human intervention.

    I use codex app and ssh to my developing server. It just works fine.

    Take a look if you are interested.

  14. LawrentChen commented on Sep 22, 2026

    @LawrentChen

    #14110 (comment)
    /goal can be a better way

  15. PHPCraftdream commented on Oct 1, 2026

    @PHPCraftdream

    The codex queue experiments from @KaiStarkk and @praveenperera identify a useful interim boundary: the command can be owned by a cheap local process, and the model only needs to be contacted when there is a result. That does not replace the native on_exit: "wake" contract proposed here.

    I maintain cc-arch-hands. We have packaged that external completion path as a temporary cli-run stdio MCP tool, available in version 0.15.1 without replacing the Codex binary:

    npx cc-arch-hands@0.15.1 install --codex-skills

    This installs the optional Codex skill bundle and manages the MCP registration and a marked instruction section; restart Codex afterward.

    With run(..., delivery: "queue"), a detached Node worker owns the supplied commands. The MCP call acknowledges a task name and generated UID, so the originating turn can end. The worker captures stdout/stderr and exit results in files, waits for all jobs in that run, then submits one brief completion message through codex queue to the calling thread. There is no model-driven write_stdin loop in this wait path. status and logs provide the saved results, including a recorded queue-delivery failure rather than a claim that notification succeeded.

    For the concurrent-experiment example above, independent runs can be used when A, B, and C need separate completion notifications; placing them in one run instead produces one aggregate notification after all three finish. We do not claim runtime-level coalescing or exactly-once continuation across restarts.

    Important differences from the requested upstream feature: this uses a queued message, not a typed ExecCommandEnd event; it does not adopt existing native terminal sessions or wake native subagent parents; an unloaded/unreachable thread can prevent delivery. run executes arbitrary commands outside Codex's per-turn filesystem sandbox, so MCP approval or explicit user trust is required and is not granted by installation.

    Implementation, coverage, and limitations. Our Windows queue-wakeup reproduction is documented separately. Native ownership, cancellation, observation/deduplication, and idle-boundary scheduling remain the reason to keep this request open.

  16. renesugar commented on Oct 2, 2026

    @renesugar

    The subscriber-quota cost motivating completion-driven waiting has now been measured with a deterministic local sleeper. Analysis and individual trial reports.

    On Codex host/CLI 0.160.0, one 3690-second Astra/low baseline produced 26 estimated pre-completion sampling records and 15 pp five-hour quota drain. Keeping the same Astra/low parent and re-arming terminal waits inside deterministic JavaScript reduced that to 1 parent round and 3 pp drain. The remaining intermediate return served the host's hourly communication requirement. No cheaper monitor was used in these Codex trials.

    All targets completed normally, with no duplicate/restart/fail-safe or reset inside the measurement. The result supports handling unchanged waiting locally and delivering a bounded completion notification once. The pinned source links show existing local exit observation and the relevant continuation paths.

    This trial did not independently reproduce every idle-thread wakeup race, and its mitigation is not an implementation of on_exit wake. It quantifies the avoidable waiting workload. Exact server-side attribution remains open; snapshots include short boundary intervals and round counts are best effort. Related polling evidence: #13733 and #35259.

  17. NormanMises commented on Oct 2, 2026

    @NormanMises

    Adding another user perspective: at this point this does not look like a minor UX enhancement; it is a missing runtime scheduling primitive.

    Codex already knows when the background process exits. The missing step is turning that completion into pending work that can resume an idle thread. Requiring the model to repeatedly poll deterministic local process state wastes inference/quota, adds latency, and makes long-running builds, tests, benchmarks, training jobs, and scientific workloads materially worse than they need to be.

    What is especially hard to justify now is that this has been open for months, there are multiple independent reproductions, working downstream/reference implementations, and the acceptance criteria are already well understood:

    • zero model inference while the process is still running;
    • exactly one continuation when it exits;
    • bounded exit status/stdout/stderr delivery;
    • no duplicate wake after manual observation;
    • correct cancellation/kill/session-shutdown semantics;
    • safe handling of completion races around the turn-finalization boundary.

    Users should not have to build write_stdin polling loops, babysitter subagents, custom MCP wrappers, or codex queue callback machinery for something the runtime can already observe locally.

    Please prioritize a native on_exit: "wake" (or equivalent runtime-owned completion wake primitive). The desired contract is simple from the user's point of view: sleep with zero inference while deterministic work runs, then resume exactly once when there is actually something new to reason about.

    External workarounds are useful experiments, but they should not become the de facto product contract for background command completion.

  18. HKLHaoBin commented on Oct 2, 2026

    @HKLHaoBin

    I want to add a concrete workflow from a local GPU benchmark / CI orchestration task.

    I launched a long-running solver and several parallel evaluation processes. Once the command was running, there was no useful reasoning to do until either a process exited or a scheduled checkpoint arrived. The practical choices were repeated status polling, a babysitter process, or ending the turn and manually returning later. Polling caused repeated no-change turns and made it difficult to keep the agent genuinely idle; the user explicitly had to ask it to stop checking so often.

    Please consider exposing both sides of this as first-class runtime primitives:

    • exec_command(..., on_exit: "wake") (or equivalent): let the model turn end, wait without inference, and resume the same thread exactly once on process completion or failure with bounded exit status, duration, and output.
    • A timer wait such as wait_until(timestamp) / sleep_for(duration): suspend the thread without model calls and wake it at the requested time.

    The user-facing contract should be: zero model inference while deterministic work is running or while the timer has not elapsed; one continuation only when there is a new event to reason about. It would also be useful to support cancellation, shutdown-safe delivery, completion races at the turn boundary, duplicate suppression after manual observation, and coalescing of simultaneous completions.

    This is especially valuable for builds, CI, benchmarks, training jobs, and scientific workloads that may run for minutes or hours. A runtime-owned wait/wake mechanism would remove the need to write polling loops or custom callback/watchdog processes for normal background execution.

  19. sharifhsn commented on Oct 3, 2026

    @sharifhsn

    Adding an aggregate audit that separates time spent waiting from avoidable model continuations.

    In a fixed 30-day local snapshot, 15,622 write_stdin calls accounted for about 43.5 summed tool-hours. This is mostly process wait time, overlaps concurrent work, and must not be treated as user time lost.

    Among the request/result pairs that could be joined reliably, I found 2,680 empty-output polls that still reported a running process. Grouping consecutive quiet polls for the same job identified 243 runs containing 942 calls. A conservative scenario that re-arms a local wait up to 30 seconds during these runs reduces 942 returns to approximately 280, or 662 fewer poll returns. Depending on orchestration and batching, that could remove up to 662 model continuations; the parent-turn count was not directly measured. This is a replay estimate, not an implemented benchmark or measured time saving. Only the linkable subset was included.

    If each avoided poll would otherwise require a separate model continuation, assuming 2/5/10 seconds of inference overhead gives 22/55/110 summed minutes; actual inference time, token savings, critical-path overlap, and completion-to-observation delay remain unmeasured.

    Current source at 6326163b9abd7802c0e57be4e326e5f898bbba75 explains two relevant behaviors:

    • Empty write_stdin polls are clamped to a minimum of 5 seconds. Requesting 1-second empty polls does not create 1-second waits on this implementation.
    • The collection loop waits on output/exit notifications and can return at process completion. A local control requested a 30-second poll and returned in 1.90 seconds when the process exited. Longer bounded polls therefore need not delay observing a quiet process's completion until the full timeout.

    This supports runtime-owned unchanged waiting, and the existing exactly-once completion wake request in this issue. It does not independently verify idle-thread wakeup or every race discussed above. Benchmarking should log actual process-exit timestamps, result-delivery timestamps, inference transitions/tokens, cancellation attribution, and overlapping useful work rather than subtracting summed wait hours.

    No commands, user content, private job paths, chat identifiers, or raw logs are attached.

  20. Nakagawa-master commented on Oct 4, 2026

    @Nakagawa-master

    One state transition looks separate from the already-covered kill/cancel/shutdown cases:

    a completion event is valid evidence that process P ended
    !=
    authority to resume the objective that was current when P was armed
    

    A background process can complete normally while the parent thread has legitimately moved on. For example:

    1. turn/objective generation G1 starts process P and arms wake-on-exit;
    2. the user steers the same thread to G2 while P is still running, without killing P (its result may still be useful as historical evidence);
    3. the G2 turn finishes and the thread becomes idle;
    4. P exits successfully;
    5. an unscoped completion registration now wakes the parent and can implicitly restore G1 as actionable work.

    That is different from a stale wake caused by cancellation: P really did complete, and its result should not necessarily be discarded. What expired is the registration's authority to start a continuation for the old objective.

    I would bind a native completion-wake registration to at least the parent thread plus a turn/objective generation (or equivalent supersession token), and separate delivery from turn-start authority:

    • same current generation + armed registration -> enqueue bounded completion and trigger one turn;
    • process completed but registration generation was superseded by user steer -> retain/deliver the completion as non-waking evidence, unless the new generation explicitly re-arms/adopts it;
    • exact manual observation -> mark observed and suppress duplicate wake as already proposed;
    • kill/cancel/shutdown -> cancelled registration as already discussed.

    A regression could keep P alive across a user steer, let it exit normally afterward, and assert zero automatic continuation under the superseded generation while the completion remains retrievable. A positive control would explicitly adopt/re-arm P under G2 and then permit one wake.

    This keeps the useful runtime primitive without letting an old wait registration silently regain control of a thread after the user's objective changed.

  21. sarinstein-yan commented on Oct 18, 2026

    @sarinstein-yan

    Strong +1. For long-running experiments, I need the parent thread to become fully idle and resume once when the background job completes, with no model polling in between. A bounded completion event with exit status and a result reference would be enough for my workflow; deduplication when results were already consumed would also matter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    CLIIssues related to the Codex CLIenhancementNew feature or requesttool-callsIssues related to tool calling

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions