Fixing Codex Transfer on Windows: Path Lookup and Repeat Imports

Fixing Codex Transfer on Windows: Path Lookup and Repeat Imports

/codex:transfer reported that it could not find an imported thread. Yet the import ledger showed that a Codex session had already been created.

Codex reported that the Claude import completed, but did not record an imported thread.

Fixing a Windows path comparison made the first transfer work. Transferring the same conversation again produced another failure with a different cause: Claude and Codex had both acquired new turns, so their histories had diverged.

This article follows both failures and the local changes used to import the latest Claude conversation without changing the existing records.

Diverging Claude and Codex histories and a local snapshot imported as a separate session
Explanatory diagram, not a screenshot of the application.

Test environment

The test record is dated October 18, 2026.

Component Version
Claude Code 2.1.301
Codex CLI 0.163.0
Node.js 24.15.0
codex-plugin-cc 1.0.6
Shell and operating system PowerShell on Windows

I invoked the actual plugin commands through Claude Code’s noninteractive -p mode and checked resumption with codex exec resume.

I backed up the original files before patching the installed plugin cache. These are local modifications, not changes shipped in the official release.

For installation and the code review example, see the Windows installation and test guide.

Two strings for the same file

The import ledger and the plugin lookup used these paths:

Import ledger:
\\?\C:\Users\...\session.jsonl

Plugin comparison:
C:\Users\...\session.jsonl

Windows uses \\?\ for extended path syntax. In this case, both paths referred to the same file, but exact string comparison returned false.

The installed plugin’s importedThreadIdForSource function contained this condition:

record?.source_path === canonicalSource &&

Comparing the actual ledger entry returned false. Removing the prefix for a diagnostic comparison returned true.

Changing the comparison

The file on this installation was:

%USERPROFILE%\.claude\plugins\cache\openai-codex\codex\1.0.6\scripts\lib\codex.mjs

The location may differ with another installation or version. I replaced the comparison with:

typeof record?.source_path === "string" &&
(process.platform === "win32"
  ? path.toNamespacedPath(record.source_path) ===
    path.toNamespacedPath(canonicalSource)
  : record.source_path === canonicalSource) &&

On Windows, both paths are converted to the same extended form. Other platforms keep the original comparison.

I kept the following content-hash and thread-ID checks:

record?.content_sha256 === contentSha256 &&
typeof record?.imported_thread_id === "string"

A path match alone can select an older import record. The content must also match the current source.

Checking the first transfer

Syntax validation and eight path or hash cases passed:

Case Result
Ordinary and extended Windows paths Match
Identical ordinary Windows paths Match
UNC and extended UNC paths Match
Different file paths No match
Same path, different content hash No match
Missing source path Excluded
Identical POSIX paths Match
POSIX paths with different case No match

The POSIX cases were mock checks of the lookup function. They were not plugin executions on Linux.

In a new Claude conversation, /codex:transfer returned a session ID and a resume command. Resuming that ID, Codex correctly recalled MAPLE-836, the results -1900 and 80, and the remaining / 100 fix.

Why the repeat transfer failed

After the successful first transfer, I imported the same conversation again. It failed.

The append logic in Codex CLI 0.163.0 checks whether the destination’s model-visible conversation is an exact prefix of the imported source conversation. It refuses an append in cases including diverged histories, an active destination or an archived destination.

My context-check question and Codex’s answer were absent from the Claude source. I had also continued the Claude conversation:

Shared conversation at the first import
├─ Claude: new marker and revised next steps
└─ Codex: context-check question and answer

Appending the new Claude turns would require a decision about how to merge the different follow-up histories. The importer refused that operation.

The plugin then failed to find a ledger record matching the current source and displayed a generic error. The path lookup failure and the diverged history therefore appeared under the same message.

A local option for a separate new session

I added a route that imports the latest Claude conversation into a new Codex session:

/codex:transfer --fresh

This option was added by the local patch. The unmodified official 1.0.6 transfer command does not support it.

After the existing source-path validation, it reads the Claude source and writes a JSONL snapshot under .codex-transfer-snapshots in the source folder. Each snapshot has a unique name and is created without overwriting an existing file. The snapshot is imported, and the plugin returns a new session ID and resume command.

File Local change
scripts/lib/codex.mjs Snapshot creation, import handling and error guidance
scripts/codex-companion.mjs Passing --fresh and displaying the result
commands/transfer.md Documentation for the local option

When a normal transfer cannot find a record for the current source, the revised message says the destination may have diverged or be active, and describes --fresh. It leaves room for other causes of the lookup failure.

The path-comparison snippet above does not implement --fresh by itself. That option needs the argument handling and snapshot import implementation across all three files. This article documents the structure and test results; it is not a complete installable patch.

Did the new instructions reach Codex?

I added a marker and changed the next task in the previously imported Claude conversation:

Previous marker: MAPLE-836
New marker: CEDAR-915

Previous task:
Restore / 100 in the discount calculation

Revised task:
Add a zero-percent discount test before restoring / 100

/codex:transfer --fresh created a separate session. After resuming it, I asked for the latest marker and task order without providing the answers again.

Codex answered CEDAR-915 and put the zero-percent test before the calculation fix. It also identified the earlier marker and the older instruction to restore the calculation directly.

Were the original records preserved?

Integration checks compared file hashes during normal repeat transfer and --fresh:

Check Result
Normal transfer after histories diverged Refused, with local --fresh guidance
Transfer with --fresh Separate new session
Source and import snapshot Byte-for-byte match
Original Claude file Hash unchanged
Existing Codex conversation file Hash unchanged
Latest context in the new session Recalled correctly

The patch imports a snapshot of the latest Claude source into a separate session. It does not merge that source with the old Codex conversation.

Limits of the local patch

Each --fresh execution creates another snapshot and session. The snapshot contains the Claude conversation at that moment; later turns are not synchronized.

Turns that exist only in the old Codex conversation are absent from the new snapshot. Put any decisions from those turns into a handoff note if they are needed.

I did not test desktop-app resumption, preservation of attachments or complete tool records, execution after exhausting Claude usage, or import from the personal bridge’s separate record folder.

Updating or reinstalling the plugin can replace the patched cache files. Before applying this approach to another version, check whether the same failure and code structure still exist. To undo the patch, restore the backed-up original files.

The personal bridge’s source-and-copy guide explains its separate record locations. If work continued on both sides, first identify which record contains the latest decisions.

Test record: October 18, 2026. Official 1.0.6 behavior is distinguished from local patch results.

Scroll to Top