app-server: client-supplied thread id on thread/start and thread/fork, so a timed-out create is recoverable
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
What variant of Codex are you using?
CLI / app-server (codex-cli 0.151.0, macOS), driven programmatically over the app-server JSON-RPC API.
What feature would you like to see?
Please add a client-supplied identity field to thread/start and thread/fork — a clientThreadId (or idempotencyKey), mirroring the clientUserMessageId that TurnStartParams already accepts.
Why: a timed-out thread/start is unrecoverable for the client.
The app-server has no transport-level cancellation — nothing addresses "request N" — which is a reasonable design, because every cancellable thing is a named object with its own stop verb (turn/interrupt, command/exec/terminate, process/kill). But that name arrives in the response the client is still waiting for. When a request outlives its deadline, the client is left with no handle at all.
For turns this is survivable: thread/turns/list reports the thread's inProgress turn, so a client can recover the id and interrupt it. I verified this against a real app-server — recovering the id of a turn whose turn/start response I deliberately ignored, then interrupting by that recovered id, and confirming the id matched what turn/start eventually returned.
Thread creation has no equivalent. If thread/start times out, the thread may or may not exist, it has no id the client knows, and there is no way to ask "did the thread I asked for get created?" The client's only options are:
- Retry, and risk creating a second thread (this is what #36257 reports — one logical create replayed into seven
thread/startrequests). - Give up, and leak a thread that may be running unattended.
- Watch the abandoned request id and reconcile if the response ever arrives — which only helps when it does arrive.
A caller-supplied id collapses all three. The client already knows the identity it asked for, so a retry is safe, a duplicate is detectable server-side, and "did this land?" becomes answerable.
Why this level rather than a cancel verb. A generic $/cancelRequest would let the server drop the in-flight future, but dropping a future does not un-create a thread. Identity is the thing that actually fixes the failure, and it's a smaller change: one optional field on two *Params structs, following the client_user_message_id precedent in app-server-protocol/src/protocol/v2/turn.rs.
Additional information
Related, none of which cover thread/start itself:
- #36257 — Android Remote replays one
create_threadoperation into seventhread/startrequests. Same failure, different client. - #36250 — asks for an
idempotencyKey, but on the Desktop-ownedcreate_threadtool rather than the protocol method. Solving it at the app-server level would cover Desktop and every other client at once. - #30348 —
thread/starttimeouts in Desktop.
Reported from an independent MCP client that orchestrates concurrent app-server workers, so this is not Desktop-specific. Happy to send a PR if the shape above is one you'd take — the clientUserMessageId precedent makes it fairly mechanical.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in app-server-protocol/src/protocol/v2/turn.rs to review the client_user_message_id precedent, then locate the parameter definitions and handling for thread/start and thread/fork. Confirm both methods accept the optional client-supplied identity and that retries can identify an existing creation without changing current behavior; finish by running the relevant app-server protocol tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- api
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 66/100