If you’re like me, you’ve probably fallen in love with Claude Code for its powerful coding assistance. But there’s a frustrating limitation: your Claude Code conversations are stored locally. Switch machines, close your laptop, or even reinstall Claude Code, and poof – your history is gone.

That’s where claude‑sync comes in. It’s an open‑source tool that automatically syncs your Claude Code sessions across all your devices, while keeping your data private and under your control.


The Problem with Local‑Only Storage

Claude Code keeps everything on the local file system for simplicity, which is fine for a single‑machine workflow. In a multi‑device world, however, you constantly lose context when you move to a new computer or need to reinstall. Re‑explaining a half‑finished refactor or digging through old prompts wastes precious time.


How claude‑sync Solves It

claude‑sync backs up every Claude Code session to a remote backend before it ever hits the network, encrypting the data on your machine with AES‑256‑GCM. The encryption key never leaves your computer, so only you can decrypt the backup.

Key Features

FeatureWhat it means for you
End‑to‑End EncryptionSessions are encrypted locally with a 256‑bit key you generate during claude‑sync init. The key is never stored in the cloud.
Pluggable BackendsChoose where the encrypted blobs live – private Git repo, AWS S3, Google Cloud Storage, Cloudflare R2, or any S3‑compatible service.
Incremental (hash‑based) SyncSince v0.4.0 claude‑sync tracks a hash of each resource’s content. On push it calls findLocal({ modifiedSinceLastSync }), filters out unchanged files, hashes the new content with hashContent(), encrypts it, and finally calls updateResourceHashBatch() to persist the new hash. Only files that actually changed are uploaded.
Pull with Conflict DetectionWhen you run claude‑sync pull --all, the CLI compares local and remote hashes. If a mismatch is found, you get an interactive prompt to resolve the conflict.
Verbose LoggingBoth pull and push now accept a --verbose flag. With it enabled you see detailed error messages, timing information, and a list of resources that failed to sync.
Dynamic Version ReportingThe CLI now reads its version from package.json via createRequire(import.meta.url), so the --version output always matches the published package.
Testable Sync LogicUnit tests now mock hashContent and updateResourceHashBatch, ensuring the incremental‑sync path is exercised without hitting a real backend.

What Changed in the Latest Release (v0.4.0)

  • --verbose flag for pull – Previously only push had a verbose mode. The new flag gives you the same level of insight when pulling, making debugging network or decryption issues painless.

  • Hash‑based incremental push – The push pipeline now looks like:

    findLocal({ modifiedSinceLastSync }) → filter by stored hash
    → read() → hashContent() → encrypt()
    → backend.pushResource()
    → updateResourceHashBatch()
    

    This reduces bandwidth and speeds up sync dramatically, especially for large repositories.

  • Sync state tracking – After a successful push the CLI records the new hash in a local “sync state” file. The next run only uploads resources whose hash differs from the stored value.

  • CLI version handlingsrc/cli.ts now uses createRequire to import the version from package.json instead of a hard‑coded string.

  • Documentation updates – The README now clarifies that claude‑sync push only pushes modified resources, and it introduces the push --all shortcut to force a full upload.


Getting Started

  1. Install the CLI

    npm install -g @xxdesmus/claude-sync
    

    (If you use GitHub Packages you may need to add an npm token – the README walks you through that.)

  2. Initialize a backend

    claude-sync init --git https://github.com/yourusername/claude-sessions-private
    

    Replace the URL with the backend of your choice (--s3, --gcs, --r2, …). During this step you’ll generate an encryption key and store it locally (~/.claude-sync/key).

  3. Install the Claude Code hook

    claude-sync install --global
    

    This adds a small script that triggers a push after every Claude Code session ends.

  4. Sync your data

    Normal workflow: every time you finish a session the hook runs claude-sync push. Only the files that changed since the last successful push are uploaded.

    Force a full upload:

    claude-sync push --all
    

    Debug a problematic sync:

    claude-sync pull --verbose
    

    or

    claude-sync push --verbose
    

Behind the Scenes: A Quick Look at the Code

  • src/commands/push.ts – Imports hashContent and updateResourceHashBatch. After encrypting a resource it calls updateResourceHashBatch({ type, id, hash }) so the next run knows the file is up‑to‑date.
  • src/commands/pull.ts – Adds a verbose option, collects any pull‑time errors in pullErrors, and prints them when --verbose is set.
  • src/crypto/encrypt.ts – Exposes a pure hashContent(data: Buffer): string helper that returns a SHA‑256 hex digest used for sync‑state comparison.
  • src/cli.ts – Uses createRequire(import.meta.url) to pull the version from package.json, ensuring the --version flag is always accurate.
  • Testspush.test.ts now mocks hashContent and updateResourceHashBatch so the incremental‑sync logic can be unit‑tested without hitting a real backend.

Important Disclaimer

claude‑sync is a community‑built tool and is not affiliated with Anthropic. Please review Anthropic’s Terms of Service and your organization’s data‑handling policies before using this tool.


Looking Ahead

We’re actively iterating on reliability, performance, and UX. Upcoming ideas include:

  • Selective conflict resolution UI (graphical prompt instead of terminal text)
  • Automatic key rotation with forward‑compatible re‑encryption
  • Metrics dashboard to visualize sync latency and bandwidth usage

If you’re interested in contributing, feel free to open an issue or submit a PR on the GitHub repository. Your feedback helps shape the next release.

Happy coding—and never lose