Skip to content

Codex App cross-host handoff cannot discover matching saved project #29284

Open

Description

@lvtangjie-lyu

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

26.616.51431 (build 4212)

What subscription do you have?

Unknown / not relevant to local desktop handoff

What platform is your computer?

Darwin 25.4.0 arm64 arm (both source and destination are macOS hosts)

What issue are you seeing?

Cross-host thread handoff aborts immediately with:

No matching saved project was found on <destination-host>.

Both connected Macs have the same repository registered as a saved Codex project, with identical redacted path and projectId. Remote thread listing and cross-host messaging work, but handoff cannot discover the destination project.

The failure is returned synchronously, before an operationId is created, so get_handoff_status cannot be used. Restarting Codex on both hosts and reconnecting the remote host did not help.

What steps can reproduce the bug?

  1. Connect two macOS hosts in Codex App.
  2. On both hosts, save the same Git repository as a project at the identical path /Users/<user>/Work/<repo>.
  3. Verify on each host that list_projects({}) returns the project with:
    • projectId: "/Users/<user>/Work/<repo>"
    • projectKind: "local"
    • path: "/Users/<user>/Work/<repo>"
    • hostId: "local"
  4. From a separate local helper thread, call:
    handoff_thread({ threadId: "<source-thread>", destinationHostId: "<connected-remote-host>", followUpPrompt: "..." })
  5. Observe the immediate error: No matching saved project was found on <destination-host>.

Additional verified facts:

  • The source thread's cwd is the saved project path.
  • A thread running on the destination host has the same cwd.
  • list_threads successfully enumerates destination-host threads, proving the remote connection/thread index works.
  • Running list_projects({}) locally on each host returns the same three saved projects and identical IDs/paths; each host labels its own entries hostId: "local".
  • The failure reproduced repeatedly, including after both Codex Apps were restarted.

This points to the host-qualified saved-project registration/discovery layer used by handoff_thread, rather than filesystem or Git path mismatch.

What is the expected behavior?

The destination host's matching saved project should be discovered, handoff_thread should return an operationId, and the source thread (plus associated Git state) should move to the destination host and run the follow-up prompt.

Additional information

Exact project paths, host names, destination IDs, and thread IDs are redacted because this is a public issue.

The local and destination list_projects views both show the project correctly, but neither exposes the other host's projects. It appears that hostId: "local" is relative to the calling host, while the cross-host handoff preflight is missing or failing to consume the destination's host-qualified project advertisement.

No project files were modified during diagnosis.

Activity

  1. added
    bugSomething isn't working
    app-serverIssues involving app server protocol or interfaces
    on Jun 21, 2026
  2. Necmttn commented on Jun 21, 2026

    @Necmttn

    This needs a project-identity diagnostic before handoff aborts.

    For each candidate destination host, the error should expose the compared fields:

    • source thread cwd/project id
    • destination saved project ids
    • canonical repo identity if available: git root, remote, worktree id
    • local path match result
    • host id used for routing

    The handoff matcher should probably treat local path as one signal, not the whole identity. Same path on two hosts can still fail if host-local project ids differ; same repo at different paths should be recoverable if the user confirms. Without the comparison receipt, there is no way to tell whether discovery, host routing, or project identity failed.


    Generated with ax.

  3. leoxk commented on Aug 28, 2026

    @leoxk

    I can reproduce this on two Apple-silicon Macs even after updating both hosts to the same Desktop build.

    Environment:

    • Source and destination: macOS, Apple silicon
    • ChatGPT Desktop on both hosts: 26.820.80927
    • Git on both hosts: 2.50.1 (Apple Git-155)
    • Remote Control connection/websocket is healthy

    Verified project identity:

    • The repository is saved at the same absolute path on both Macs: /Users/<user>/Workspace/<repo>
    • Git top-level path, HEAD, and normalized remote.origin.url match
    • The destination Desktop sidebar visibly contains the project
    • The same origin query used in the Git 2.43 report succeeds on both Macs, including when run from the repository's .git directory

    Observed behavior:

    • handoff_thread fails immediately with No matching saved project was found on <destination-host>.
    • No operationId is created
    • The control/source host's list_projects only enumerates its local projects and does not expose the destination host's saved project
    • Re-adding the destination folder through the normal Desktop UI creates a second local project record for the same path, but does not create a remote/saved-workspace association and does not change the Handoff result
    • Restarting/reconnecting does not help

    This appears distinct from #37624: both Macs use Git 2.50.1 and the origin lookup succeeds. It still looks like the Handoff preflight is not consuming the destination host's saved-project advertisement, even though the project is visible and usable on that host.

    A supported diagnostic showing the source identity and destination candidates compared by Handoff would be very helpful. Please also clarify whether a destination project must be registered through any UI flow other than Add local project/Open folder.

  4. liang2h commented on Sep 3, 2026

    @liang2h

    Reproduced on macOS ↔ Linux (SSH) — Desktop 26.820.60940, matching fails even with fully working Git origin discovery

    Same failure mode as reported here and reproduced by @leoxk above, with one new data point: the destination is a Linux SSH host, so the affected surface is not limited to Mac↔Mac or Mac↔Windows pairings.

    As in the reproduction above, this rules out the Git 2.43 origin-lookup failure described in #37624: git config --get remote.origin.url succeeds on both hosts from the worktree root and returns byte-identical URLs. The failure therefore points at the host-qualified saved-project advertisement/matching layer, not at the origin query itself.

    Environment

    Component Value
    ChatGPT desktop app 26.820.60940 (build 7119)
    Bundled local Codex CLI 0.150.0-alpha.8
    Remote Codex CLI 0.150.1 (also reproduced on 0.149.0)
    Source host macOS 26.5.2, arm64
    Destination host Linux, connected via SSH

    Verified facts

    • The local project is saved at the Git repository root on the source host, and the remote project is saved at the Git repository root on the destination host. Both report isGitRepository: true, and each saved path equals git rev-parse --show-toplevel on its host.

    • remote.origin.url is byte-identical on both hosts.

    • The destination host is online; remote-only chats run successfully against the same repository on it.

    • Reproduction rate: 100% across historical and newly created local chats, including a chat created after the desktop app update and formally assigned to the local saved project.

    • The run-location menu in the chat footer lists only local destinations; the SSH host is absent.

    • handoff_thread fails synchronously before an operationId is created:

      No matching saved project was found on <host>.
      

    Troubleshooting performed (no effect)

    • Removed and re-added the remote saved project multiple times; the project ID changed each time and the app kept reporting isGitRepository: true.
    • Restarted the SSH connection.
    • Upgraded the remote CLI 0.149.0 → 0.150.1 and retested.

    Regression information

    The same run-location menu previously offered the SSH host as a destination. The option disappeared after updating the desktop app. Nothing changed on either side in between: same checkouts, same origin, same repository roots.

    One observation that may help narrow the matching layer

    The two saved projects carry differently formatted IDs — the local one is a hashed local-… id while the remote one is a UUID, and the UUID changes on every re-add. This is consistent with the hypothesis that re-adding a folder creates a host-local project record without establishing the host-qualified saved-workspace association the handoff matcher consumes. This is an inference from observed behavior, not a confirmed root cause.

    Expected behavior per https://learn.chatgpt.com/docs/remote-connections#hand-off-a-chat-between-hosts: the SSH host should appear in the run-location menu, and handoff_thread should return an operationId and transfer the chat and Git state.

    Related: #37624 (failed origin lookup cached as null — ruled out here), #38872 (same symptom with a Windows destination).

  5. nephaest commented on Oct 8, 2026

    @nephaest

    Additional reproduction on October 8, 2026: MacBook Air → Apple-silicon Mac Mini over the desktop Remote Control connection.

    Environment

    • Source ChatGPT desktop: 26.1002.52244 (build 13536), macOS 27.2.
    • Destination: macOS/arm64. Reported remote app-server version: 0.162.0-alpha.2 (observed in the connection details and October 7 logs; destination desktop build not collected).
    • Both devices use the Personal workspace; the user reports the same account/workspace.

    Reproduction and verified observations

    1. Save a local project at the Git repository root on each host. The two checkouts have different absolute paths but the same GitHub repository origin.
    2. Destination-local list_projects({}) returns the saved local project with a UUID projectId and its correct path (reported by the user from the destination chat).
    3. Source-local list_projects({}) returns source projects and ChatGPT projects, but no destination-local projects. This affects other destination projects too, according to the user's project inventory.
    4. From a separate source helper chat, call handoff_thread with the existing source thread ID and the connected destination host ID, without a follow-up prompt.
    5. It fails immediately with No matching saved project was found on <destination-host>. No operationId is returned.
    6. Crucially, read_thread from the source, explicitly targeting the destination host and a known destination chat ID, succeeds. The returned hostId is the remote-control destination and cwd is the destination saved project's path. The remote chat is readable and idle.

    Controls performed, with no resolution

    • Verified destination Git root using git rev-parse --show-toplevel and origin using git remote -v.
    • Initially the source origin used HTTPS and the destination used SSH. Temporarily set the source origin to the byte-identical SSH URL and retried: same handoff error. Restored the original source HTTPS URL afterward. This does not exclude stale origin caches or internal origin-query failures.
    • Created a harmless local chat within the previously empty destination project: still no destination projects in source list_projects, same handoff error.
    • Restarted the destination Mac and retried: same error.
    • Source desktop app had also been restarted during diagnosis.
    • An earlier attempt failed with a pending-composer-state error; later attempts progressed past that guard and consistently failed on project matching.
    • Source logs confirm a connected remote-control host and successful remote reconnection. An earlier Authenticated workspace changed disconnect coincided with closing/reopening the source app; a subsequent connection succeeded. That event is not established as causal.

    Expected behavior and impact

    The saved destination project should be discovered as a handoff candidate, allowing the existing chat and Git state, including uncommitted work, to transfer without starting another evaluation. The user is currently blocked from moving this workflow to the Mini. No transfer has taken place; the working files and branch remain intact.

    Qualification

    This appears consistent with this issue's destination saved-project discovery/matching failure, rather than a general inability to read remote chats. The precise cause (project enumeration, host-qualified identity, origin lookup/cache, or another matching field) is unconfirmed. We have not run the internal .git-directory origin query described in #37624, so that specific cause has not been ruled out.

    Please expose the destination candidates and compared repository identity fields, and distinguish a failed destination-project enumeration/origin lookup from an actual repository mismatch.

    Private repository names, usernames, absolute paths, chat IDs and host identifiers are intentionally redacted. No full session transcript or unreviewed logs are attached.

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 interfacesbugSomething isn't workingremote

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions