Skip to content

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

claude-conversation-transfer

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.

Install

go install github.com/arghhhhh/claude-conversation-transfer@latest

Usage

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).

Examples

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.

What it rewrites

  • Every occurrence of the source CWD inside .jsonl files, 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.

What it does NOT rewrite

  • memory/MEMORY.md and memory/*.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.

Environment

CLAUDE_CONFIG_DIR is honored: when set, the projects directory is $CLAUDE_CONFIG_DIR/projects/ instead of the default ~/.claude/projects/.

Verification is part of the contract

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.

Exit codes

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)

Tests

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.

About

Export/import a Claude Code project's conversation history across machines and OSes

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages