An annotation sent with "Steer" starts as many duplicate Codex turns as there are other VS Code windows with the Codex panel open, causing multiple concurrent writes to the same rollout and workspace
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
What version of the IDE extension are you using?
openai.chatgpt 26.5727.51351-darwin-arm64
What subscription do you have?
Plus
Which IDE are you using?
VS Code
What platform is your computer?
Darwin 25.6.0 arm64 arm
What issue are you seeing?
This one is tightly related to the other concurrency bug reported in #38629, but the trigger here is different and the impact is higher: a single user action performed in one VS Code window silently starts "background" concurrent turns, one for every other VS Code window with the Codex panel open.
Each duplicate turn then independently tries to write to the same workspace at the same time as the others.
The concrete failure mode is described below.
What steps can reproduce the bug?
-
Open one VS Code window with a folder/workspace (window A).
-
Open the Codex panel in that window, send
Test. Reply "ANNOTATE_ME" and stop., and wait for the response. -
Open a few other, independent VS Code windows. Open the Codex panel in each one, and let the Codex webview load. Opening the same chat that contains
ANNOTATE_MEis not necessary for the reproduction; you may leave the panels in the default state or open other, unrelated chats. -
In the initial window A, with the initial
ANNOTATE_MEchat still open, send this prompt to imitate a long-running job:Perform 30 sequential cycles: for cycle n, run sleep 5 as a separate terminal command, then send a progress update in this format: TICK n/30. Do not combine cycles into one shell loop. Do not modify any files until I say so. Stop when you reach TICK 30/30.Wait for at least one
TICK n/30to appear. -
In the same window A, select any text in a previous Codex response, for example,
ANNOTATE_ME, click the annotation bubble ("Add to chat"), and add any annotation. To make the failure more observable without even needing to inspect rollout files, you can use this prompt:Pick a random file name <random-name>.txt (don't use one that is solely time-based), create A SINGLE FILE with that name in this workspace root, and, after each TICK, also write TICK n/30 to that file you created. Proceed until TICK 30/30.Click
Send(Ctrl/Cmd+Enter). -
Click
Steeron the just-created pending annotation message.At this point, the existing Codex app-server instances in the other VS Code windows resume the conversation and start separate turns from the same annotation. The original turn in window A also handles the annotation, so a single instruction to create a single file creates multiple
<random-name>.txtfiles, one per turn, all at almost exactly the same time. Each turn writes its own independentTICK n/30sequence to its file, and all of the turns write to the same session rollout file simultaneously.In a real project where this was observed, that led to multiple interleaving edits to the same files, until eventually 3 out of 4 concurrent Codex turns stopped to ask, "Are you editing the files while I do it?"
If you inspect the extension logs and rollout, you may see that the dormant clients resumed the conversation a few milliseconds apart, each became the owner, and the one annotation started a separate turn in each existing app-server process associated with another VS Code window.
-
Reproduce the additional failure - the inability to stop:
Click "Stop" in the visible chat - this stops only the visible branch; the hidden turns continue running and writing files. Alternatively, send something like "Fully stop now." in Steer mode. Codex may produce a visible "Stopped." reply and the UI may appear to be in the stopped state, while the hidden turns continue running and writing files.
For a successful repro, it is important to open new VS Code windows when the annotation-testing chat already exists.
What is the expected behavior?
As with #38629, a single conversation must have at most one mutation-capable active turn. A response annotation submitted with Steer should never make unrelated VS Code windows start producing duplicate/concurrent turns in the same conversation.
If a client from another VS Code window is a follower, it must remain a follower unless ownership is transferred explicitly through a single coordinated operation.
The visible Stop control should stop active work in the conversation, and no "invisible" background work should continue if the agent reports that it has stopped and the UI changes to the stopped state.
Additional information
Relevant extension log sequence from a clean three-window reproduction:
15:36:41.543 window 2 maybe_resume_started; previousResumeState=needs_resume; previousStreamRole=null
15:36:41.544 window 3 maybe_resume_started; previousResumeState=needs_resume; previousStreamRole=null
15:36:42.436 window 2 role=owner
15:36:42.438 window 2 maybe_resume_success; latest timer turn status=interrupted
15:36:42.443 window 3 role=owner
15:36:42.445 window 3 maybe_resume_success; latest timer turn status=interrupted
15:36:57.155 window 2 reasoning activity; turnId=01a03433-c275-76c3-8428-bfbcbbdd793f
15:36:58.501 window 3 reasoning activity; turnId=01a03433-c27d-7df1-bf1d-192ff7ecf81e
After windows 2 and 3 were opened, both clients logged documentVisibilityState=visible, although the marker chat had never been selected there. Ownership then oscillated between the two resumed clients while the original active client became a follower.
Bundled Codex CLI: 0.146.0-alpha.9.2.
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 with the VS Code extension's app-server resume and ownership handling, then trace the annotation Steer path; the issue provides no file or test names. Reproduce the multi-window steps and inspect extension logs for maybe_resume_started, role=owner, and turn IDs. Done means one conversation has one mutation-capable turn, and Stop prevents hidden work across windows.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust, vscode
- Domain
- desktop, developer-experience, tooling
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100