Session Migration for Claude Code

Move the Session
Without Breaking It

Move a Claude Code session to the project it actually belongs to, subagent transcripts included, so /resume finds it there instead of the old one.

The session you need is filed under the wrong project. Moving it by hand quietly breaks it.

The external problem

A session started under one project’s folder, but the conversation actually belongs under another. /resume in the right project comes up empty, and a plain file move doesn’t fix it: the transcript still points at the old path in nine different encodings.

The internal problem

You can see the .jsonl file sitting right there on disk. But every check Claude Code runs says it belongs to a different project, so it stays invisible exactly when you want it back.

What's at stake

Hours hand-editing paths that half-work, or a naive copy that leaves the subagent transcripts behind, corrupts the cwd field, and leaves you with no backup to recover from.

Five steps: back up, copy, rewrite paths, note it, verify.

Point it at a session UUID and a target project; it handles the backup, the copy, and the verification without you touching a path by hand.

01

Backup Both Sides

Full copies of the source and target project directories, taken before anything is touched, so there’s a rollback and a ground truth to validate against.

02

Sidecar-Aware Copy

The session’s .jsonl moves together with its subagents/ sidecar directory, so subagent transcripts don’t get left behind the way a plain copy would leave them.

03

Rewrite Every Path

All nine path-encoding variants get rewritten across every entry: JSON-escaped and plain backslash, forward slash, MSYS, hyphenated project name, and both drive-letter cases.

04

Migration Note

A visible message gets appended to the transcript recording what moved and how to recover, so you and Claude both see it on the next /resume.

05

Verify End-to-End

A validator checks JSONL integrity, path consistency, sidecar files, and the pre-migration backup before anything gets called done, so success is proven, not assumed.

Grounded in what actually breaks.

Nine path forms exist because nine different subsystems write paths into a transcript, and the failure modes below all happened for real: a missed sidecar, a false-positive stale-reference warning, an ambiguous UUID lookup after migration. The script and its validator are built against these two files, not a guess at how Claude Code stores sessions.

Reference

Path Encoding

The nine variants

For an old path C:\Users\name\old\repo migrating to C:\Users\name\new\repo, the script rewrites all of these:

KeyEncodingExample old formWhere it appears
AJSON-escaped backslash, uppercase driveC:\\Users\\name\\old\\repocwd field on most entries; tool inputs serialized as JSON strings. This is usually the highest-count replacement by far.
BJSON-escaped backslash, lowercase drivec:\\Users\\name\\old\\repoRare; only when something on the system normalized the drive to lowercase.
CForward slash, uppercase driveC:/Users/name/old/repoTool outputs from Unix-ish utilities running on Windows (e.g. find, grep via Git Bash).
DHyphenated project-dir name, lowercase drivec--Users-name-old-repoReferences to the encoded project dir under .claude/projects/ in lowercase.
EMSYS / Git Bash path/c/Users/name/old/repoBash tool outputs from MSYS / Git Bash.
FHyphenated project-dir name, uppercase driveC--Users-name-old-repoReferences to the encoded project dir, the form Claude Code itself uses on Windows.
GForward slash, lowercase drivec:/Users/name/old/repoRare lowercase-drive variant of C.
HPlain backslash, uppercase driveC:\Users\name\old\repoConversation text — when Claude prints a path inline, it usually uses this form.
IPlain backslash, lowercase drivec:\Users\name\old\repoRare lowercase-drive variant of H.

How the encoded project-dir name is built

Given a Windows path like C:\Users\name\old\repo:

  • Take the drive letter and colon → C:
  • Append each path segment separated by \C:\Users\name\old\repo
  • Replace every :, \, /, space, and ' with -C--Users-name-old-repo

This is the folder name under ~/.claude/projects/. Claude Code creates the uppercase-drive form on Windows; the lowercase form exists for case-insensitive filesystem quirks.

Why this matters for migrations

Most replacements happen in the cwd field (variant A). But other variants show up in:

  • Subagent transcripts that captured shell output (variants C, E, G)
  • Tool result strings where Claude or a tool quoted a path (variant H)
  • References to other sessions or the project dir itself (variants D, F)

The replacement count printed by the migration script's dry-run reveals which subsystems your session interacted with. A session that only ever talked to native Windows tools will show 100% pattern A; one that ran a lot of git or bash will show a mix.

What does NOT get rewritten

  • The new project's encoded folder name (new-repo's C--... form). This is computed from --new-repo and used as the target directory name; it isn't substituted into entry bodies.
  • File contents outside the session transcripts. The script operates only on text files inside the project directory under ~/.claude/projects/.
  • Anything that doesn't include the old path as a substring. The script does literal substring matching, not pattern matching.

What to do when the new path is a substring of the old path (or vice versa)

This happens when you migrate a session into a subdirectory of its current project (e.g. Other Claude CodeOther Claude Code\Sub-Project). The script handles it correctly thanks to longest-first sorting, but its post-migration verifier will produce false-positive warnings because every occurrence of the new path also contains the old path as a substring.

See references/troubleshooting.md → "Stale reference false positive" for the recipe that distinguishes real stale references from prefix-containment artifacts.

Use it now. It's free.

Works on all platforms. Pick yours and get set up in under a minute.

Download & upload in 60 seconds

One click downloads the zip and opens Claude.ai.

01

Click below — the zip downloads and Claude.ai opens.

02

Click the + button in the skills column on the left.

03

Select Create a skill.

04

Select Upload a skill and upload the zip.

05

Start your session migration by running /estack-migrate-claude-session-history.

Migrate Claude Session History ships in E-Stack, a set of 20 free skills installed by one command. See the whole stack.