Skip to content

Expose non-interrupt queued delivery for cross-thread send_message_to_thread #30499

Open

Description

@amatsuki5032

Feature request

Codex Desktop/App already has user-facing Queue vs Steer concepts, but the app/tool surface exposed to agents for cross-thread orchestration appears to only provide send_message_to_thread without an explicit delivery mode.

For parent/worker thread orchestration, we need a way for a worker thread to send a completion notice back to a parent thread without interrupting the parent thread's current turn. The desired behavior is:

  • delivery: "queued" or interrupt: false for send_message_to_thread / equivalent cross-thread send
  • the message is accepted immediately as pending input for the target thread
  • it is processed only after the target thread's current active turn completes
  • it should not be treated as turn/steer or an urgent interruption
  • it should be durable/visible enough that the parent does not need to poll child threads with read_thread
  • optionally expose status such as queued, delivered, canceled, failed

Why this matters

A common Codex workflow is a durable parent/router thread with multiple worker threads. Worker completion notices currently have two bad options:

  1. Use direct send_message_to_thread, which can interrupt or interleave with the parent thread's active reasoning and muddy decision-making.
  2. Do not send a notice and require the parent to poll/read worker threads, which is easy to miss and makes the workflow stall.

A non-interrupt queued cross-thread send would let workers report completion reliably while preserving the parent thread's current reasoning turn.

Related/adjacent issues found

Those are related, but the specific request here is an explicit non-interrupt delivery mode for cross-thread programmatic sends, suitable for agent/worker completion notices.

Suggested API shape

send_message_to_thread({
  threadId,
  prompt,
  delivery: "queued" // or interrupt: false
})

or app-server equivalent:

{
  "method": "thread/message/send",
  "params": {
    "threadId": "...",
    "input": [{"type":"text","text":"WORKER_NOTICE ..."}],
    "delivery": "queued"
  }
}

If an active turn exists, this should enqueue. If no active turn exists, it can start normally or remain queued depending on product semantics, but the delivery mode should be explicit and observable.

Activity

  1. added
    enhancementNew feature or request
    appIssues related to the Codex desktop app
    app-serverIssues involving app server protocol or interfaces
    subagentIssues involving subagents or multi-agent features
    on Jun 29, 2026
  2. devansh-jain-18 commented on Jul 9, 2026

    @devansh-jain-18

    I strongly support this, especially for parent/worker thread workflows.

    The important distinction for me is that cross-thread communication should not always mean steering the target thread. If a worker finishes while the parent/router thread is still actively reasoning or executing, I want the worker's completion report to be queued as the parent's next input, not injected into or interleaved with the active turn.

    A useful shape would be a configurable delivery mode on cross-thread sends, for example:

    • delivery: "queued" / interrupt: false: enqueue for after the current active turn
    • delivery: "steer" / interrupt: true: urgent guidance for the current active turn
    • possibly a user or per-thread default so orchestrators can default worker reports to queue while still allowing explicit urgent steering

    This would make multi-thread orchestration much calmer: workers can report completion reliably, but the parent thread keeps its current task boundary intact unless the sender explicitly chooses to interrupt.

  3. michaelvd2 commented on Jul 14, 2026

    @michaelvd2

    Non-interrupt queued delivery would help, but worker completion needs a slightly stronger app-server transaction to avoid both polling and duplicate/partial wake behavior.

    Suggested scoped operation on the Desktop host that already owns the coordinator's app-server connection:

    1. Validate exact parent/worker lineage, a completion nonce, a compact terminal edge, and an existing report pointer.
    2. Append the completion through canonical thread history.
    3. Start exactly one normal coordinator turn.

    The append and wake should be serialized per parent thread. Duplicate nonce is a no-op. Unknown lineage, oversized payload, busy/non-wakeable coordinator, or any failed precondition must append nothing and start no turn.

    This cannot be safely emulated by attaching workers to the ChatGPT-owned stdio transport, launching a second app-server, separate thread/inject_items plus turn/start calls, rollout edits, direct steering, polling, a watcher, or a local queue: none can atomically target the already-running Desktop task with exactly-once semantics.

    Useful acceptance fixtures: schema round-trip; valid append-plus-one-turn; duplicate nonce; wrong lineage; unknown thread; invalid/oversized payload; busy coordinator; rollback on precondition failure; and a Desktop-host integration proving one visible completion plus one coordinator turn on the owning connection. A negative fixture should show that a separately launched app-server cannot claim to wake the original Desktop task.

  4. Nova-Exocortex commented on Sep 1, 2026

    @Nova-Exocortex

    Component: Codex Desktop cross-task messaging
    (codex_app.send_message_to_thread) and App Server queue integration

    Version: Codex Desktop 26.825.6671.0 on Windows

    There is now a narrower implementation path for this request.

    Since #38456, the public App Server exposes experimental persistent queue
    operations (thread/queue/add, list, update, delete, reorder, and
    start), including FIFO dispatch, change notifications, a stable submission
    ID, and a client-provided message ID.

    However, the cross-task send_message_to_thread tool available in Desktop
    still has no delivery mode, message ID, or delivery state. Sending to a task
    with an active turn can steer or reprioritize that turn immediately. The
    Desktop composer's Queue/Steer preference does not appear to govern these
    programmatic cross-task sends.

    Reproduction:

    1. Start task A with a harmless multi-step prompt that keeps it active.
    2. While A is working, use task B to call send_message_to_thread targeting A.
    3. Observe that B's message is introduced into A's active work rather than
      being held for A's next turn.
    4. Observe that B cannot request queue delivery or determine whether the
      message was queued, steered, started, or rejected.

    Impact:

    Routine worker reports can change the subject of an orchestrator's active turn,
    fragment an unfinished unit of work, or displace a pending user decision.
    Avoiding the send forces callers to poll other tasks instead.

    Expected behavior:

    • Add delivery_mode: "queue" | "steer" to cross-task sends.
    • Default agent-originated cross-task sends to queue; require an explicit
      choice for steer.
    • A queued cross-task message must not preempt the target's active user turn or
      user messages already queued ahead of it.
    • Route queued delivery through the existing App Server queue instead of
      emulating a queue in the Desktop client.
    • Return a stable message/submission ID and an observable state such as
      queued, started, applied, canceled, failed, or rejected.
    • Show the source task and delivery mode in both source and target task UI.
    • Accept a client message ID and make retries idempotent: replaying the same ID
      must not enqueue or apply the message twice.
    • If the target is idle, queued delivery may start the next normal turn
      immediately, while returning the same correlated acknowledgement.

    This would preserve user priority while still allowing explicit urgent
    steering. It would also align cross-task messaging with the queue primitives
    that already exist in the public App Server.

  5. rtol5 commented on Sep 30, 2026

    @rtol5

    We tested both underlying delivery paths on September 29 in SSH-backed Desktop sessions, remote CLI 0.159.1: active turn/steer with an exact expectedTurnId, and CLI codex queue for deferred input. Steering appended the request to the existing turn, and the peer returned a substantive result while the coordinator remained active.

    Explicit queue delivery is also essential. A useful native contract would let callers choose queue or steer, rather than infer urgency from target state. A stale-turn race or uncertain send should not silently switch modes.

    One workflow hazard we encountered: if both chats keep their turns open waiting for replies queued behind those same turns, neither can progress. Queue-only requesters must yield or do independent work; responders send once and end. Separate delivery modes make that behavior easier to design correctly.

    For this workflow, peers are independently existing feature-owner sessions, not only spawned workers. Native sender provenance and accepted/queued/delivered states would remove much of the custom coordination machinery. Unloaded-target wake-up is a separate limitation; queue acceptance alone did not wake our unloaded test chats.

  6. ZuyVladislav commented on Oct 9, 2026

    @ZuyVladislav

    Windows Desktop: supported queue-only delivery between existing chats

    Please provide a supported way to pass requests between existing Codex Desktop chats through a queue. A new request should wait for the target's current turn to finish, without steering, interrupting, or changing that turn's task.

    Environment checked on 2026-10-09: Windows, Codex Desktop 26.1002.7124.0, bundled core 0.162.0-alpha.2.

    Our local checks found:

    • The exposed send_message_to_thread schema has no explicit queue-only delivery argument.
    • Schema generation using the bundled core exposes six experimental thread/queue/* methods: add, list, update, delete, reorder, and start.
    • We have not established a supported connection to the queue of the already-running Desktop instance. An isolated local queue test does not prove this integration.

    No new live cross-chat send was performed during these checks. We did not attach to private application channels, launch a second app-server, or modify working chats. These observations do not prove that every native send interrupts a turn, or that no supported integration is possible.

    What is the supported way to use this queue for existing Desktop chats? If it is not currently exposed, please provide a native queue-only operation, with a durable submission receipt, protection against duplicate delivery, and documented behavior after a manual stop. An idle-state snapshot followed by a normal send is not enough to guarantee non-interruption.

    This is a request for supported integration and explicit delivery semantics, not a newly reproduced crash or delivery defect.

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

    appIssues related to the Codex desktop appapp-serverIssues involving app server protocol or interfacesenhancementNew feature or requestsubagentIssues involving subagents or multi-agent features

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions