Transfer your Claude Code sessions between different devices seamlessly
Claude Context Sync is a CLI tool that exports and imports Claude Code sessions between devices. It solves the problem of absolute path differences between machines using a smart path-transformation system.
Current version: 0.6.0
Features:
- Full session transfer: messages, file-history, and todos
- Automatic path transformation between devices (no manual editing)
- gzip compression (
--compress) — reduces bundle size by up to 86% - Automatic progress bars for large sessions
- Git-based sync via private repository (
sync-push/sync-pull) - Central server mode — HTTP server replaces/complements Git when
server-urlis configured - Interactive session picker — no need to copy/paste UUIDs
sync-push --all— push all sessions from the current project at oncesync-pull --all— pull all available bundles from the repository at once- Descriptive Git commit labels (project name + first prompt)
- SHA256 integrity validation
- Backwards-compatible with older bundles (v1.0.0)
- Automatic sync hooks — SessionEnd/SessionStart integration with Claude Code (
hooks-install) - Optional AES-256-GCM encryption — passphrase-based, no raw key files to manage (
--encrypt) - Structured logs —
hook.logfor automatic sync,--verbosefor manual commands - Local bundle backup — every push/pull saves a copy in
~/.claude-sync-git/backups/for local rollback - File watcher daemon — auto-push on session change (
watch --daemon) - Session sharing — share sessions with other users on the same server (
share/inbox)
Platform support: Fully tested on Windows. Linux and macOS binaries available via the VSCode extension (bundled) and GitHub Actions releases.
The easiest way to use Claude Context Sync is through the VSCode extension — no terminal required.
→ Claude Context Sync on VS Code Marketplace
The extension includes the CLI bundled inside — no Python or pip installation needed. Just install the extension and it works.
- Local Sessions panel — browse all your Claude Code sessions grouped by project
- Remote Bundles panel — see all sessions stored in your Git repo or central server
- Push / Pull buttons — sync sessions with one click directly from the sidebar
- Backup history — view and restore previous backups of any session by date
- Auto Sync toggle — start/stop the file watcher daemon from the sidebar
- Status bar — shows "Auto Sync: ON / OFF" (clickable)
- Settings UI — configure everything without touching the terminal, including
serverUrlandserverToken
- Install the extension from the Marketplace
- Open VSCode and click the Claude Sync icon in the Activity Bar
- Open Settings (
Ctrl+,) → searchclaudeContextSync→ set Default Repo to your private Git repo URL - Use the ↑ push button to send a session, or ↓ pull to receive one from another machine
The extension still requires Git installed and a private repository configured — see the Git Setup section below.
When working across two different PCs, you constantly lose your Claude Code conversation context because:
- Absolute paths differ between machines (
C:\Users\alice\...vsD:\Projects\...) - Directory structures vary between devices
- There is no native way to transfer the full conversation history
This tool solves all of that.
- Python 3.8+
- Git (for Git-based sync)
# Clone the repository
git clone https://github.com/<your-username>/claude-context-sync.git
cd claude-context-sync
# Install pip if needed
python -m ensurepip --upgrade
# Install the package
python -m pip install -e .This installs the claude-sync command globally on your system.
Every Claude Code conversation has a unique session ID — a UUID that never changes:
097f3474-8974-4405-98c0-b70d4bf920d5
Use claude-sync list to see your session IDs. Because the ID never changes, you can always use it to sync the same conversation across devices.
Each PC needs to be configured once with claude-sync config, telling the tool where your projects live on that device. The tool uses this to automatically convert paths during export and import.
1. Configure the device:
claude-sync config --device-id desktop --projects-path "C:/Users/<username>/Documents/projects" --set-current2. List your sessions:
claude-sync listOutput:
Found 3 session(s):
Session ID: 097f3474-8974-4405-98c0-b70d4bf920d5
First prompt: Fix the authentication bug in login
Messages: 1504
Created: 2026-01-15T10:00:00.000Z
Modified: 2026-02-19T18:42:40.303Z
Project: c--users-alice-documents-projects-my-app
Session ID: bedcc029-db4a-4474-a179-10ff88888ef0
First prompt: Implement dashboard main page
Messages: 312
...
3. Set a default repository (once per device):
claude-sync repo git@github.com:your-username/claude-sessions.git
# [OK] Default repository set to: git@github.com:your-username/claude-sessions.git
# You can now run sync-push/pull/list without --repo4. Push a session to Git:
From inside the project folder, run sync-push without any arguments to pick interactively:
cd C:/Users/<username>/Documents/projects/my-app
claude-sync sync-push --compressOutput:
Sessions in current project (my-app):
[1] 097f3474 2026-02-20 Fix the authentication bug in login
[2] bedcc029 2026-02-18 Implement dashboard main page
Choose session number: 1
Exporting session: 097f3474-8974-4405-98c0-b70d4bf920d5
Reading messages: 100%|##########| 1504/1504 [00:00<00:00]
Read 1504 messages from session
Normalizing paths: 100%|##########| 1504/1504 [00:00<00:00]
Exporting file-history and todos...
[OK] Exported 1504 messages to 097f3474-8974-4405-98c0-b70d4bf920d5.bundle.gz (compressed)
Checksum: b77d1ef4...
File-history: 36 entries
Todos: 4 items
Pushing to Git repository: git@github.com:...
[OK] Bundle pushed to repository: 097f3474-8974-4405-98c0-b70d4bf920d5.bundle.gz
[SUCCESS] Session synced to Git successfully!
On another device, run:
claude-sync sync-pull
5. Install claude-context-sync (same steps as the Installation section above)
6. Configure the device:
claude-sync config --device-id laptop --projects-path "D:/Projects" --set-current7. Set the default repository (once per device):
claude-sync repo git@github.com:your-username/claude-sessions.git8. Pull interactively — no need to know the session ID:
claude-sync sync-pullOutput:
Pulling from Git repository: git@github.com:...
Using project path: D:/Projects/my-app
(use --project-path to change)
Available bundles in repository:
[1] 097f3474 my-app | Fix the authentication bug in login
[2] bedcc029 my-app | Implement dashboard main page
Choose session number: 1
[OK] Found bundle: 097f3474-8974-4405-98c0-b70d4bf920d5.bundle.gz
[OK] Bundle validation passed
Denormalizing paths: 100%|##########| 1504/1504 [00:00<00:00]
Target project path: D:\Projects\my-app
[OK] Wrote 1504 messages
[OK] Restored 36 file-history entries
[OK] Restored 4 todo items
[OK] Updated sessions index
[SUCCESS] Session '097f3474...' imported successfully!
9. Resume in Claude Code:
Open Claude Code inside the corresponding project folder and use /resume to select the imported session.
Because the session ID never changes, syncing the latest state of a conversation is always the same command:
# PC 1 — update the bundle in the repo with the latest messages
claude-sync sync-push --compress
# PC 2 — pull the updated version (use --force since the session already exists locally)
claude-sync sync-pull --forceYou can use a single Git repository for all your sessions. Each bundle is named with the session ID, so there are no collisions:
# Set the repo once
claude-sync repo git@github.com:user/sessions.git
# Push sessions from different projects to the same repo
cd C:/projects/my-app && claude-sync sync-push --compress
cd C:/projects/api-server && claude-sync sync-push --compress
cd C:/projects/frontend && claude-sync sync-push --compress
# On the other PC, see all available sessions with labels
claude-sync sync-list
# Pull only the one you need
claude-sync sync-pullIf you prefer not to use Git, transfer the bundle directly via USB, Google Drive, etc.:
# PC 1 — export to a file
claude-sync export 097f3474-8974-4405-98c0-b70d4bf920d5 \
--output my-session.bundle \
--compress
# Copy my-session.bundle.gz to the other PC via USB, Drive, etc.
# PC 2 — import the received file
claude-sync import my-session.bundle.gzTo use Git-based sync, you need a private repository with authenticated access.
- Go to github.com/new
- Give it a name (e.g.,
claude-sessions) - Set it as Private
- Click Create repository — leave it empty, no README
Repeat the authentication setup below on each PC you use.
ls ~/.ssh/id_ed25519.pubIf the file exists, skip to Step 3.
On Windows, the .ssh folder may not exist yet. Create it first:
mkdir -p ~/.ssh
chmod 700 ~/.ssh
ssh-keygen -t ed25519 -C "this-pc-name" -f ~/.ssh/id_ed25519 -N ""Replace
this-pc-namewith something that identifies the device, e.g.,desktop,work-laptop.
Required on Windows — without this the connection fails with Host key verification failed:
ssh-keyscan github.com >> ~/.ssh/known_hosts# Copy the output of this command
cat ~/.ssh/id_ed25519.pub- Go to github.com/settings/ssh/new
- Title: a name that identifies this PC (e.g.,
home-laptop) - Key: paste the key copied above
- Click Add SSH key
ssh -T git@github.com
# Expected: Hi your-username! You've successfully authenticated...If you see Permission denied (publickey), the key was not added correctly — redo Step 4.
If you see Host key verification failed, redo Step 3.
If you prefer not to configure SSH, use HTTPS with a Personal Access Token:
- Generate a token at: GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic)
- Required scopes: check repo
claude-sync sync-push \
--repo https://your-username:YOUR_TOKEN@github.com/your-username/claude-sessions.git \
--compressThe token appears in the URL — do not share this command with anyone.
Configure path mappings for a device. Run once per device.
claude-sync config --device-id DEVICE_ID --projects-path PATH [OPTIONS]| Option | Description |
|---|---|
--device-id |
Device identifier (e.g., desktop, laptop) — required |
--projects-path |
Path to your projects folder — required |
--user |
Windows username (default: current user) |
--home |
Home directory (default: current home) |
--claude-dir |
.claude directory path (default: ~/.claude) |
--set-current |
Set this device as the current one |
# Windows
claude-sync config --device-id desktop --projects-path "C:/Users/<username>/Documents/projects" --set-current
# Linux / macOS
claude-sync config --device-id laptop --projects-path "/home/<username>/projects" --set-currentList all sessions available in the local Claude Code installation.
claude-sync list [--project PATH] [--limit N]claude-sync list
claude-sync list --limit 50
claude-sync list --project "C:/Users/<username>/Documents/projects/my-app"Export a session to a local bundle file.
claude-sync export SESSION_ID [--output PATH] [--compress]| Option | Description |
|---|---|
--output |
Output file path (default: session.bundle) |
--compress |
Compress with gzip — recommended, reduces size by ~86% |
claude-sync export 097f3474-8974-4405-98c0-b70d4bf920d5
claude-sync export 097f3474-8974-4405-98c0-b70d4bf920d5 --output ~/Desktop/session.bundle --compressImport a session from a bundle file. Supports both .bundle and .bundle.gz automatically.
claude-sync import BUNDLE_PATH [--force]claude-sync import session.bundle
claude-sync import session.bundle.gz
claude-sync import session.bundle.gz --force # overwrite if session already existsSet the default Git repository URL. Run once per device — after that, sync-push, sync-pull, and sync-list use it automatically without requiring --repo.
claude-sync repo URLclaude-sync repo git@github.com:your-username/claude-sessions.gitThe URL is saved in config/path_mappings.json and can be overwritten at any time by running the command again. To use a different repo for a single command, pass --repo URL directly.
Export a session and push it to the Git repository.
claude-sync sync-push [SESSION_ID] [--session UUID] [--repo URL] [--output NAME] [--compress] [--encrypt] [--all] [--auto] [--verbose]| Option/Argument | Description |
|---|---|
SESSION_ID |
Session UUID (optional — if omitted, lists sessions in the current project) |
--session UUID |
Alternative to positional argument — useful for scripts and hooks |
--repo |
Git repository URL (optional if set with claude-sync repo) |
--output |
Bundle filename (default: <session-id>.bundle) |
--compress |
Compress with gzip |
--encrypt |
Encrypt bundle with AES-256-GCM (prompts for passphrase, or uses saved key) |
--all |
Push every session found in the current project directory at once |
--auto |
Non-interactive mode for hooks — no prompts, errors logged to hook.log |
--verbose |
Write detailed steps to ~/.claude-context-sync/logs/app.log |
Without session ID — interactive picker from current project:
cd C:/projects/my-app
claude-sync sync-push --compressOutput:
Sessions in current project (my-app):
[1] 097f3474 2026-02-20 Fix the authentication bug in login
[2] bedcc029 2026-02-18 Implement dashboard main page
Choose session number: 1
With session ID — direct (no listing):
claude-sync sync-push 097f3474-8974-4405-98c0-b70d4bf920d5 --compressThe Git commit generated includes the project name and first prompt as a description:
sync: session 097f3474 | my-app | Fix the authentication bug in login
Pull a bundle from the Git repository and import the session.
claude-sync sync-pull [SESSION_ID_PREFIX] [--repo URL] [--force] [--project-path PATH] [--latest] [--all] [--auto] [--verbose]| Option/Argument | Description |
|---|---|
SESSION_ID_PREFIX |
First 8 chars of the session ID (optional — if omitted, lists bundles to choose from) |
--repo |
Git repository URL (optional if set with claude-sync repo) |
--force |
Overwrite the session if it already exists locally |
--project-path |
Local project path on this device (default: current directory) |
--latest |
Pull the most recently pushed bundle — used by SessionStart hooks |
--all |
Pull the latest version of every session in the repository at once |
--auto |
Non-interactive mode for hooks — no prompts, errors logged to hook.log |
--verbose |
Write detailed steps to ~/.claude-context-sync/logs/app.log |
Without session ID — interactive picker from remote repository:
claude-sync sync-pullOutput:
Available bundles in repository:
[1] 097f3474 my-app | Fix the authentication bug in login
[2] bedcc029 my-app | Implement dashboard main page
Choose session number: 1
With session ID prefix — direct (no listing):
claude-sync sync-pull 097f3474
claude-sync sync-pull 097f3474 --force
claude-sync sync-pull 097f3474 --project-path "D:/Projects/my-app"List all bundles available in the Git repository, with their labels and IDs for use with sync-pull.
claude-sync sync-list [--repo URL]claude-sync sync-list
# or with a specific repo:
claude-sync sync-list --repo git@github.com:user/another-repo.gitOutput:
Found 3 bundle(s):
097f3474-8974-4405-98c0-b70d4bf920d5.bundle.gz
sync: session 097f3474 | my-app | Fix the authentication bug in login
sync-pull ID: 097f3474
bedcc029-db4a-4474-a179-10ff88888ef0.bundle.gz
sync: session bedcc029 | api-server | Implement dashboard main page
sync-pull ID: bedcc029
To import a bundle:
claude-sync sync-pull <sync-pull ID>
Install automatic sync hooks in Claude Code. After running this command, sessions are pushed automatically when you close a conversation and pulled when you open Claude Code.
claude-sync hooks-install # install (or show status if already installed)
claude-sync hooks-install --force # update hooks to the current versionThis writes to ~/.claude/settings.json:
- SessionEnd → runs
sync-push --session $CLAUDE_SESSION_ID --auto - SessionStart → runs
sync-pull --latest --auto
A backup is saved to ~/.claude/settings.json.bak before any changes.
Run hooks-install on each machine you want to sync automatically. Running it again when already installed shows the current hook status without modifying anything. Use --force to update hooks to the latest version.
Remove the automatic sync hooks from Claude Code settings. Does not affect other hooks.
claude-sync hooks-uninstallConfigure an encryption passphrase for automatic encrypted sync.
claude-sync crypto-setupThe passphrase is used to derive an AES-256 key, which is saved locally at ~/.claude-context-sync/key. Run this on every machine with the same passphrase — sessions encrypted on one machine can then be decrypted on the other automatically.
After setup:
sync-push --autowill encrypt bundles automatically (no prompt)sync-pull --autowill decrypt them automatically (no prompt)
If you prefer to type the passphrase manually each time (without saving a key), just use sync-push --encrypt — it will prompt for the passphrase interactively.
Start a file watcher daemon that auto-pushes sessions whenever they change.
claude-sync watch # run in foreground
claude-sync watch --daemon # start background daemon
claude-sync watch --status # check if daemon is running
claude-sync watch --stop # stop the daemon
claude-sync watch --debounce N # debounce delay in seconds (default: 30)The daemon monitors ~/.claude/projects/**/*.jsonl. When a session file is modified, it waits for the debounce period to expire and then runs sync-push --session {id} --auto --compress. PID is saved at ~/.claude-context-sync/watch.pid; log at ~/.claude-context-sync/logs/watch.log.
Configure the central server URL. When set, sync-push, sync-pull, and sync-list use HTTP instead of Git.
claude-sync server-url # show current URL
claude-sync server-url https://sync.example.com # set URLGit remains as the fallback if server-url is not configured.
Manage authentication tokens for the central server.
claude-sync token --save TOKEN # save a token received from the admin
claude-sync token --show # display the saved token (masked)
claude-sync token --create-user NAME # create a new user token (admin only)Share a session with another user on the same server.
claude-sync share SESSION_PREFIX --with USER [--message MSG]claude-sync share 097f3474 --with maria
claude-sync share 097f3474 --with maria --message "Here's the auth bug context"The recipient sees the share in their inbox. Sharing requires server-url to be configured.
List sessions shared with you, or download one.
claude-sync inbox # list pending shares
claude-sync inbox --pull SHARE_ID # download a shared session
claude-sync inbox --pull SHARE_ID --project-path PATH # download to a specific project folderclaude-sync inbox
# → [abc123] usuario-a | my-app | 2026-03-20 | "Fix the auth bug"
claude-sync inbox --pull abc123 --project-path "C:/Projects/my-app"List configured devices.
claude-sync devicesSet the current device.
claude-sync use DEVICE_IDclaude-sync use laptop
claude-sync use desktopThe core problem is that absolute paths differ between devices:
| Device | Path |
|---|---|
| desktop | C:\Users\alice\Documents\projects\my-app |
| laptop | D:\Projects\my-app |
Solution: template variables that are resolved per device.
Export (desktop): C:\Users\alice\Documents\projects\my-app
→ ${PROJECTS}/my-app
Import (laptop): ${PROJECTS}/my-app
→ D:\Projects\my-app
{
"version": "1.1.0",
"exportedAt": "2026-02-23T17:31:14.574567",
"sourceDevice": "desktop",
"session": {
"sessionId": "097f3474-8974-4405-98c0-b70d4bf920d5",
"messages": [...],
"metadata": {
"projectPath": "${PROJECTS}/my-app",
"messageCount": 1504,
"firstPrompt": "...",
"created": "2026-01-15T10:00:00.000Z"
},
"fileHistory": {
"09e54f171b709bcd@v2": "<tracked file content>",
...
},
"todos": [
{"content": "Task 1", "status": "completed", "activeForm": "Working on task 1"},
...
]
},
"checksum": "a3f5b2c8..."
}Every bundle includes a SHA256 checksum computed over the entire session (messages + file-history + todos). If the file is corrupted or modified during transfer, the import rejects the bundle with an error.
claude-sync list # see available session IDsBundle corrupted during transfer. Re-export from the original device.
claude-sync import session.bundle.gz --force
claude-sync sync-pull 097f3474 --forceclaude-sync devices # see configured devices
claude-sync config --device-id laptop --projects-path "D:/Projects" --set-currentpython -m ensurepip --upgrade
python -m pip install -e .The .ssh folder exists but GitHub is not in known hosts yet. Run:
ssh-keyscan github.com >> ~/.ssh/known_hostsThe SSH key is not registered on GitHub, or the .ssh folder did not exist when the key was generated.
# 1. Create the .ssh folder if it doesn't exist
mkdir -p ~/.ssh && chmod 700 ~/.ssh
# 2. Generate a new key
ssh-keygen -t ed25519 -C "this-pc-name" -f ~/.ssh/id_ed25519 -N ""
# 3. Add GitHub to known hosts
ssh-keyscan github.com >> ~/.ssh/known_hosts
# 4. Copy and add the public key to GitHub
cat ~/.ssh/id_ed25519.pub
# → github.com/settings/ssh/new
# 5. Test
ssh -T git@github.comHappens on the very first push to a freshly created repository. The tool detects this automatically and skips the pull step. Just run the command normally.
If automatic sync stops working after running hooks-install, check the hook log:
- Windows:
%USERPROFILE%\.claude-context-sync\logs\hook.log - Linux/macOS:
~/.claude-context-sync/logs/hook.log
The log records every automatic sync attempt with timestamp and error details.
For more detail on a manual command, add --verbose:
claude-sync sync-push --verbose
claude-sync sync-pull --verboseThis writes step-by-step output to ~/.claude-context-sync/logs/app.log.
The passphrase entered does not match the one used to encrypt the bundle. Make sure you ran crypto-setup with the same passphrase on both machines. If you set up a saved key (crypto-setup), the key files on both machines must have been derived from the same passphrase.
- No conflict resolution — use sessions alternately between devices (push from A, pull on B, work on B, push from B, pull on A)
- Automatic hooks require
claude-syncto be on the system PATH — install viapip install -e . - Requires Git installed and authenticated for Git-based sync
- Full session export: messages, file-history, todos
- gzip compression (
--compress) - Automatic progress bars
- Git sync (
sync-push/sync-pull/sync-list) - Configurable default repository (
claude-sync repo <url>) —--repooptional -
sync-pushwithout session ID — interactive picker from current project -
sync-pullwithout session ID — interactive picker from remote repository - Descriptive Git commit labels (project name + first prompt)
- SHA256 integrity validation
- Automatic sync hooks (
hooks-install/hooks-uninstall) — SessionEnd + SessionStart - Non-interactive mode (
--auto) for hook execution - Pull most recent bundle (
--latest) for SessionStart hooks - Optional AES-256-GCM encryption (
--encrypt,crypto-setup) - Passphrase-derived keys via PBKDF2 — no raw key file management
- Structured logs:
hook.log(always) +app.log(--verbose) - Timestamp in bundle filename (
session_YYYYMMDD-HHMMSS.bundle) -
importcommand supports encrypted bundles (.bundle.gz.enc) directly
- Bundles organized per project in the git repo (
{project}/session.bundle.gz) - Local bundle backup after every push/pull (
~/.claude-sync-git/backups/) - VSCode Extension — push, pull, browse sessions and backups without terminal
- Bundled CLI binary inside the extension — no Python required for extension users
-
hooks-install --forceto update existing hooks; status display when already installed - Session discovery via direct
.jsonlscan (nosessions-index.jsonrequired)
-
sync-push --all— push all sessions from the current project at once -
sync-pull --all— pull all available bundles from the repository at once - Project name correctly decoded from Claude's encoded directory names
-
sync-pushdetects project name even whensessions-index.jsonis missing - VSCode extension warns on project mismatch when pulling a remote session
- Linux and macOS binaries built via GitHub Actions and bundled in the extension
- File watcher daemon (
watch --daemon/--stop/--status/--debounce) - Central server mode — FastAPI server with push/pull/list/delete, token auth, admin dashboard
-
server-urlcommand — configure HTTP backend; Git used as fallback when not set -
tokencommand — save/show tokens, create users (admin) -
sharecommand — share a session with a specific user on the server -
inboxcommand — list and download sessions shared with you - VSCode extension: Auto Sync toggle button in Local Sessions toolbar
- VSCode extension: status bar item "Auto Sync: ON / OFF" (clickable)
- VSCode extension:
serverUrlandserverTokensettings, synced to CLI on activation - VSCode extension: restarts watcher daemon on activation when
autoSyncwas ON - Docker support for the central server (Dockerfile + docker-compose.yml)
- Admin web dashboard at
/admin/with session management and sharing overview
- Fork the project
- Create a branch (
git checkout -b feature/my-feature) - Commit your changes
- Push and open a Pull Request
MIT License
Daniel de Oliveira Trindade