Bundle a Claude Code project's conversation history into a portable zip and import it onto another machine — correctly retargeting absolute paths across OSes. Move a whole project (every session + memory), or a single conversation.
Backs the /export-proper and /import-proper slash commands (whole project)
and /export-session and /import-session (one conversation), which kept
accumulating subtle bugs because every run re-derived the rewrite logic from
prose. This is a compiled Go binary with regression tests for the cases that
historically broke.
Two granularities, and they differ in how the target folder is treated:
| Bundles | Import behavior | |
|---|---|---|
export / import |
the whole project — every session + memory/ |
replaces the target project folder (existing one backed up to .bak-<ts>) |
export-session / import-session |
one conversation's <id>.jsonl + its <id>/ sidecar (+ memory/ only with --with-memory) |
merges into the target folder — other sessions there are left untouched |
Reach for export-session when you want to move a single chat to another
machine that already has its own conversations in that project — a full
import would wipe them; import-session adds the one chat alongside them.
go install github.com/arghhhhh/claude-conversation-transfer@latest
claude-conversation-transfer export [--cwd PATH] [--out DIR] [--json]
claude-conversation-transfer import <zip> [--target-cwd PATH] [--json]
claude-conversation-transfer export-session [--session ID] [--with-memory] [--cwd PATH] [--out DIR] [--json]
claude-conversation-transfer import-session <zip> [--target-cwd PATH] [--json]
claude-conversation-transfer rename --to PATH [--from PATH] [--rename-dir] [--json]
export zips ~/.claude/projects/<encoded-cwd>/ into the current directory.
import extracts that zip into ~/.claude/projects/<encoded-current-cwd>/,
rewrites embedded path prefixes from the source CWD to the current one, and
verifies every .jsonl line still parses as JSON.
export-session bundles just one conversation — its <id>.jsonl plus the
<id>/ sidecar subdir (e.g. subagents/) if present. Without --session it
picks the most-recently-modified session in the folder (the active one).
memory/ is left out unless you pass --with-memory. import-session
merges that zip into the target folder — it rewrites and verifies the same
way, but never touches sessions already there. A same-id collision moves the
existing session aside to .bak-<ts>; memory/ (with --with-memory) is
merged add-only, and any name that already exists is kept as .incoming-<ts>
rather than overwriting.
rename collapses the four-step "export → rename the folder → new session →
import → clean up" dance into one command for renaming a project on the same
machine. It exports the project at --from (default: current CWD), imports
it into the encoded folder for --to, rewrites embedded paths, verifies, and —
only if verification passes — deletes the old ~/.claude/projects/ folder. Add
--rename-dir to also move the working directory on disk from --from to
--to (off by default; the safe assumption is that you already renamed it).
Export the active project:
cd ~/work/my-project
claude-conversation-transfer export
# -> claude-convo-export-<encoded>-<YYYYMMDD-HHMMSS>.zip
Import onto a different machine where the project lives at a different path:
cd C:\Users\me\projects\my-project
claude-conversation-transfer import claude-convo-export-...zip
Machine-readable report:
claude-conversation-transfer import foo.zip --json
Export a single conversation (the active one) and merge it onto another machine, keeping that machine's other chats in the project intact:
cd ~/work/my-project
claude-conversation-transfer export-session
# -> claude-convo-session-<encoded>-<YYYYMMDD-HHMMSS>.zip
# ...move the zip to the other machine...
cd C:\Users\me\projects\my-project
claude-conversation-transfer import-session claude-convo-session-...zip
Export a specific past session by id, with memory:
claude-conversation-transfer export-session --session 3f2a...-...-...-... --with-memory
Rename a project in place (you already renamed the folder yourself):
cd C:\Users\me\projects\unfold-museum-pod-design
claude-conversation-transfer rename --from C:\Users\me\projects\pod-design --to C:\Users\me\projects\unfold-museum-pod-design
Or have the tool move the directory too:
claude-conversation-transfer rename \
--from ~/work/pod-design --to ~/work/unfold-museum-pod-design --rename-dir
A rename --json report looks like:
{"old_project":...,"new_project":...,"jsonl_files":N,"has_memory":bool,
"dir_renamed":bool,"preexisting_target_backup":path|"","old_data_deleted":bool,...}.
If a project folder already existed at the new path, import backs it up to a
.bak-<timestamp> folder; rename surfaces it as preexisting_target_backup
and never deletes it — it may hold real prior sessions or memory to merge.
- Every occurrence of the source CWD inside
.jsonlfiles, in both raw and JSON-escaped (\\) forms. - Path tails under the rewritten prefix — separators in nested file paths are translated to the target OS's separator, scoped strictly to tokens that start with the rewritten prefix.
memory/MEMORY.mdandmemory/*.md(already portable).- Path references outside the project CWD (source user's home, system paths, other projects). Those would not resolve on the target machine either way, and broad rewrites would corrupt message text, code blocks, and URLs.
CLAUDE_CONFIG_DIR is honored: when set, the projects directory is
$CLAUDE_CONFIG_DIR/projects/ instead of the default ~/.claude/projects/.
After import, every .jsonl line is re-parsed as JSON. If any line fails,
the binary exits non-zero and points at the offending file. Claude Code's
session list populating is not evidence the import worked — sidecar
records survive most corruption and the conversation will still open empty.
| Code | Meaning |
|---|---|
| 0 | success |
| 1 | verification failure (post-import/rename .jsonl files contain invalid JSON) |
| 2 | usage error |
| 3 | I/O / extract / read failure |
| 4 | rename --rename-dir: the on-disk directory move failed (Claude-side data left untouched) |
go test ./...
Round-trip fixtures cover POSIX→Windows, Windows→POSIX, same-OS no-op,
underscore-prefix filenames, memory/ preservation, and subagents/
substructure. export-session/import-session have their own fixtures: a
cross-OS single-session merge that proves other sessions on the target survive
and the picked session (plus its sidecar) is rewritten, the default
most-recently-modified session pick, and the add-only memory/ merge that
keeps a colliding MEMORY.md as .incoming-<ts>. rename has its own
round-trip fixtures (same-machine Windows rename, cross-OS rewrite,
preexisting-target backup, --rename-dir on a real directory, and the
refusal/missing-source guards). The regression guard for the
historical backslash-transport bug — where \\ became \ and produced invalid
JSON escapes — runs on every test invocation.