openai / openai/codex

[Windows][Remote iOS] Dragging a misplaced Remote worktree thread into its project breaks its worktree binding

Open
#41,835 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

app bug remote session windows-os
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

What version of the Codex App are you using (From “About Codex” dialog)?

ChatGPT Desktop for Windows: 26.825.51511

Remote Codex CLI: 0.151.0

What subscription do you have?

Paid individual ChatGPT plan.

What platform is your computer?

Windows 11 x64 running Codex/ChatGPT Desktop, with the affected project hosted on a remote Linux environment. The affected threads were created from ChatGPT on iOS through Codex Remote.

What issue are you seeing?

A Codex Remote worktree thread created from the iOS app can be missing from its correct Remote project group on Windows Desktop and appear only under Recents.

Before anything is moved, the Recent entry still appears to know its correct execution context:

  • it shows the worktree/fork/PR-style icons expected for the thread;
  • its tooltip identifies the correct Remote host;
  • the tooltip identifies the correct project;
  • the tooltip identifies that the task is using a separate managed Remote worktree.

However, if I drag that Recent entry into the corresponding Remote project in the Windows Desktop sidebar — i.e. the project it should already have belonged to — the thread's Git/workspace context changes.

After the drag:

  • the Environment panel shows the canonical repository / main branch instead of the thread's managed worktree branch;
  • the thread no longer exposes a way to reattach to its original managed worktree;
  • attempting to select the original branch in the Environment branch picker fails because Git reports that the branch is already checked out by the original Codex-managed worktree.

Representative sanitized error:

Failed to switch branch: fatal: '<feature-branch>' is already used by worktree at
'/home/<user>/.codex/worktrees/<worktree-id>/<repo>'

The original error in this reproduction names an existing path under ~/.codex/worktrees/..., so the underlying Git worktree still appears to exist and still owns the feature branch. The failure is therefore not simply that the worktree was deleted. The Desktop thread/UI appears to have lost or changed the association that tells it to operate against that worktree.

I have now hit this with more than one in-progress Remote thread. Once affected, I cannot continue the implementation normally from the Desktop thread because the thread will not attach back to the worktree it was created with.

This is particularly dangerous because moving a sidebar entry to fix project organization can silently alter or desynchronize its Git/workspace context. Subsequent Codex operations can then execute in the main checkout rather than the isolated task worktree.

What steps can reproduce the bug?
  1. In Codex Desktop for Windows, have an existing project backed by a Remote Linux host/repository.
  2. From ChatGPT on iOS, connect through Codex Remote and open that Remote project.
  3. Start a new Codex task in worktree/fork mode so it gets its own managed worktree and feature branch.
  4. Continue working in the task from iOS. Confirm it belongs to the intended Remote project there.
  5. Open Codex Desktop on Windows.
  6. Observe that the iOS-created Remote worktree task is missing from the corresponding Remote project's thread list and can only be found under Recents.
  7. Inspect the Recent entry. Its icons/tooltip still identify the correct Remote host, project, and separate worktree.
  8. Drag the Recent entry into the corresponding Remote project in the Desktop sidebar.
  9. Reopen/select the thread.
  10. Observe that the Environment panel now resolves to the canonical repository / main branch rather than the task's managed worktree branch.
  11. Use the branch selector to choose the task's original feature branch.
  12. Observe the error:
fatal: '<feature-branch>' is already used by worktree at '/home/<user>/.codex/worktrees/<worktree-id>/<repo>'
  1. There is no apparent Desktop UI action to re-bind the existing conversation/task to that already-existing managed worktree, leaving the in-progress thread effectively stranded.
What is the expected behavior?

Two invariants should hold:

  1. A Remote worktree task created from iOS inside an existing project should appear under that same Remote project in Windows Desktop without requiring a manual move.
  2. Moving/reorganizing a thread in the Desktop sidebar must not change its execution working directory, Git worktree, branch ownership, or Remote host binding unless the user explicitly requests a workspace migration.

If a project reassignment does require workspace metadata to change, it should be atomic and preserve the existing managed-worktree association for an in-progress worktree thread.

The Environment panel, branch controls, diff/commit/PR controls, and task execution context should all resolve the same managed worktree.

Additional forensic evidence

Read-only inspection of the affected remote Codex state confirms that this is not merely a stale or incorrect Desktop UI association.

For the affected thread, the original rollout session_meta records the correct Codex-managed worktree:

/home/<user>/.codex/worktrees/<worktree-id>/<repo>

Later in the same rollout, turn_context.cwd switches to the primary repository checkout:

/home/<user>/workspaces/<repo>

The first observed switch is at approximately line 1907 of the rollout JSONL.

The current row for the same thread in:

/home/<user>/.codex/state_5.sqlite

now persists:

cwd        = /home/<user>/workspaces/<repo>
git_branch = main
git_sha    = <baseline-sha>
project_id = NULL

The rollout's original worktree context therefore remains preserved historically in session_meta, while later operational turn_context records and the mutable thread catalog now use the main repository checkout.

The Git SHA remaining unchanged while the branch changes to main is consistent with the main checkout and original worktree sharing the same baseline commit when the execution context changed.

The thread itself was not destroyed or recreated:

  • thread_spawn_edges still preserves all 12 child-thread relationships from this thread;
  • the rollout JSONL remains present;
  • thread_history_1.sqlite retains rollout offsets, turns, items, and realtime items;
  • session_index.jsonl still indexes the same thread ID.

This indicates that the failure changes the thread's execution/workspace binding while preserving its identity, history, and fork lineage.

In other words, the resulting persisted state is approximately:

thread identity       intact
transcript            intact
fork lineage          intact
original session cwd  intact historically
current runtime cwd   wrong (primary checkout)
current git branch    wrong (`main`)

There is also an observable project-association discrepancy:

  • the Codex app thread listing reports a project ID (<project-id>);
  • the affected remote threads.project_id is NULL;
  • the remote projects table contains no matching project ID.

No claim is made here about the internal mechanism responsible for that discrepancy; this report is limited to the externally observable state and consequences.

Controlled reproduction: Desktop changes the recorded session directory

The affected thread is hosted on the Remote Linux machine. ChatGPT Desktop on Windows accesses that same machine through a configured Remote connection.

The following sequence was reproduced on the same affected thread:

  1. Use the thread through Windows ChatGPT Desktop and ask for its CWD.
/home/<user>/workspaces/<repo>
  1. Shut down ChatGPT Desktop.
  2. SSH to the Remote host and explicitly resume the same thread in its managed worktree:
codex resume <thread-id> --cd /home/<user>/.codex/worktrees/<worktree-id>/<repo>

Asking for the CWD reports:

/home/<user>/.codex/worktrees/<worktree-id>/<repo>
  1. Exit that CLI session. From /home/<user>, run the same resume command again without --cd:
codex resume <thread-id>

Codex displays:

Choose working directory to resume this session

Session = latest CWD recorded in the resumed session
Current = your current working directory

Use session directory (/home/<user>/.codex/worktrees/<worktree-id>/<repo>)
Use current directory (/home/<user>)

Selecting the session directory resumes in the managed worktree, confirming that the recorded session directory is the worktree at this point.

  1. Start ChatGPT Desktop again, open the same Remote thread, and ask for the CWD. It reports:
/home/<user>/workspaces/<repo>
  1. Return to the Remote host and again run, from /home/<user>, with no --cd:
codex resume <thread-id>

Codex now displays:

Choose working directory to resume this session

Session = latest CWD recorded in the resumed session
Current = your current working directory

Use session directory (/home/<user>/workspaces/<repo>)
Use current directory (/home/<user>)

So the externally observable transition is:

CLI resume --cd <managed-worktree>
→ CWD = managed worktree

CLI resume <thread-id>, no --cd
→ stored session directory = managed worktree

Use same thread through Windows ChatGPT Desktop
→ CWD = canonical/main checkout

CLI resume <thread-id>, no --cd
→ stored session directory = canonical/main checkout

This reproduces the consequence directly: using the affected Remote thread through ChatGPT Desktop changes the thread's recorded session working directory from the managed Codex worktree to the project's canonical checkout. A subsequent native codex resume <thread-id> on the Remote host then offers that canonical checkout as the thread's stored session directory.

This section intentionally makes no claim about how or why that state change happens internally.

Commands accidentally executed after the context had changed

Before I noticed that Codex was operating in the wrong working directory, it executed:

git status --short --branch && git rev-parse HEAD && git log --oneline -6 && git remote -v
git merge-base <baseline-sha> HEAD && git diff --stat <baseline-sha>..HEAD && git diff --check <baseline-sha>..HEAD

These are diagnostic/query operations. They do not perform a merge, checkout, reset, commit, rebase, branch switch, or working-tree content modification. In particular, git merge-base only computes the best common ancestor between commits.

They therefore do not explain the observed cwd/branch transition and do not invalidate the persisted-state evidence above.

Additional information

Observed on 2026-08-31.

The core failure can now be stated as an observable outcome:

An existing Remote fork/worktree thread can retain its thread identity, transcript, and fork lineage while ChatGPT Desktop uses the project's canonical checkout instead of the managed Codex worktree. After Desktop uses the affected thread, the Remote CLI reports that canonical checkout as the thread's latest recorded session directory. Subsequent Codex operations can therefore execute in the wrong repository/worktree.

Related existing reports:

  • #23418 — mobile Remote-created worktree thread is not associated with the corresponding Desktop project. This closely matches the first stage of this reproduction, but does not cover the destructive result of dragging the misplaced thread into its correct project.
  • #32273 — iOS-created Remote tasks missing from the Desktop Project list while still being discoverable elsewhere.
  • #35167 — Windows thread moves can persist inconsistent/half-applied workspace migration state.
  • #37591 — branch controls can resolve a different worktree from the task context and produce the same already used by worktree failure.

The distinctive reproduction here is:

iOS Remote creates valid managed-worktree task
        -> Windows Desktop misplaces it under Recents
        -> Recent entry still knows correct Remote/project/worktree metadata
        -> drag entry into the project it should already belong to
        -> Desktop uses canonical checkout instead of managed worktree
        -> Remote CLI can explicitly restore and record managed worktree
        -> Desktop uses same thread again
        -> Remote CLI now reports canonical checkout as latest recorded session directory
        -> original managed worktree still exists and owns feature branch
        -> no UI path to reattach the existing thread to that worktree

I can provide screenshots of the post-drag Environment state, the already used by worktree error, the CLI working-directory prompt before and after Desktop use, and sanitized rollout/SQLite diagnostics if needed.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the codex resume flow and compare the affected thread's rollout JSONL, session_index.jsonl, thread_history_1.sqlite, and state_5.sqlite before and after opening it in Windows Desktop. Reproduce the iOS/Remote-to-Windows sequence and verify that project assignment and resume preserve the managed worktree CWD, branch, host, and thread history without falling back to the canonical checkout.

Written by the indexing model from the issue text.

Assessment

Tech stack
git, rust
Domain
cli, developer-experience
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.