Sync your Claude Code settings, skills, and config across machines
One command to sync your Claude Code skills, settings, agents, commands, and hooks to a private GitHub repo. One command to pull them on a new machine. Zero config. No encryption keys to manage. No cloud accounts to set up.
You use Claude Code on multiple machines. Every time you set up a new one, you have to:
- Reinstall all your custom skills
- Reconfigure settings.json (plugins, permissions, model preferences)
- Re-add all your MCP server definitions
- Copy over agents, commands, hooks, and keybindings
- Remember what you had and what you didn't
Or worse — you make a great skill on your laptop and forget to copy it to your desktop.
# On every machine — just run init
claude-sync init
# That's it. init detects whether to push or pull automatically.macOS / Linux:
curl -fsSL https://raw.githubusercontent.com/danielcregg/claude-sync/main/install.sh | bashWindows (PowerShell):
irm https://raw.githubusercontent.com/danielcregg/claude-sync/main/install.ps1 | iexManual (any platform — recommended if you prefer to audit the code first):
git clone https://github.com/danielcregg/claude-sync.git
node claude-sync/claude-sync.mjs version # verify it worksSecurity note: The one-liner installers download and execute code from GitHub. If you prefer to review the code before running it, use the manual install method above. The SHA256SUM file in the repo can be used for manual verification.
claude-sync initThat's it. init is smart — it detects your situation automatically:
| Scenario | What init Does |
|---|---|
| First machine (no sync repo exists) | Creates a private GitHub repo, pushes your config |
| New machine (fresh Claude Code install) | Detects the remote repo, pulls your config |
| Existing machine (has settings & skills) | Backs up your config, shows what's different, pulls remote config, tells you how to merge |
You never need to figure out whether to run clone, diff, or backup — init handles it all.
claude-sync push # After making changes
claude-sync pull # Before starting work on another machine
claude-sync status # Check what's changedSettings auto-sync on session end via a Stop hook (installed by init).
| Synced | Not Synced (excluded by default) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
The
.gitignoreis carefully tuned to sync everything useful while excluding everything sensitive or machine-specific. Credentials never leave your machine.
MCP server definitions from ~/.claude.json are automatically extracted, synced, and merged across machines:
claude-sync list # See your synced MCP serversOn push: MCP servers are collected from all projects in ~/.claude.json, deduplicated, and saved to mcp-servers-sync.json.
On pull/clone: MCP servers from the sync file are merged into your local ~/.claude.json — existing servers are never overwritten, only missing ones are added.
Note: MCP servers that use
npxcommands (like@playwright/mcp) work everywhere. Servers with local paths (like Python venvs) may need manual adjustment on each machine.
Paths in synced files are automatically normalized using git smudge/clean filters:
- In the repo: paths use
{{CLAUDE_SYNC_HOME}}placeholder - On your machine: paths use your real home directory (
/home/you,C:\Users\you, etc.) git status: shows clean — the translation is transparent
This means settings.json, marketplace config, and MCP server paths all work correctly when synced between Linux, macOS, and Windows.
| Command | What It Does |
|---|---|
claude-sync init |
First-time setup — creates repo, pushes, installs auto-sync hook |
claude-sync init --no-hook |
Setup without auto-sync hook |
claude-sync push |
Commit and push changes |
claude-sync push -m "msg" |
Push with custom message |
claude-sync pull |
Pull latest from GitHub |
claude-sync status |
Show changes and sync state |
claude-sync clone [user] |
Set up new machine from existing repo (auto-detects GitHub user) |
claude-sync diff / preview |
Preview what would change before cloning (safe, read-only) |
claude-sync backup |
Back up current config before syncing |
claude-sync list / ls |
Show local config (skills, commands, MCP servers, plugins) |
claude-sync list --remote |
Show what's on GitHub |
claude-sync devices |
Show all machines syncing with this config |
claude-sync doctor |
Check sync health, detect issues |
claude-sync reset |
Force-align local with remote (backs up first) |
claude-sync hook |
Install the auto-sync hook |
claude-sync version |
Show version |
| Flag | Works With | What It Does |
|---|---|---|
-m, --message |
push | Custom commit message |
-q, --quiet |
push, pull | Minimal output |
-n, --dry-run |
push, pull | Preview without changes |
--no-hook |
init | Skip auto-sync hook |
claude-sync init automatically installs a Stop hook that pushes your config to GitHub whenever a Claude Code session ends. Your settings stay in sync without you having to remember to run push.
To skip this during setup: claude-sync init --no-hook
To install it later: claude-sync hook
The hook adds this to your settings.json (with the absolute path to your install):
{
"hooks": {
"Stop": [{
"hooks": [{
"type": "command",
"command": "node /home/you/.local/bin/claude-sync.mjs push -q -m auto-sync",
"timeout": 30
}]
}]
}
}The path is detected automatically at install time — no manual editing needed.
Already have Claude Code set up on another machine with settings you want to keep? Don't blindly clone — preview first:
# 1. See what would change
claude-sync diff
# 2. Back up your current config
claude-sync backup
# 3. Clone the remote config
claude-sync clone
# 4. If you lost something, restore from backup
cp ~/.claude-backup-2026-03-24T23-30-00/skills/my-local-skill ~/.claude/skills/
claude-sync push -m "merged local skill"diff is completely read-only — it clones the remote repo to a temp directory, compares, and cleans up. Your local config is never touched.
- Private repo:
claude-sync initcreates a private GitHub repo. Only you can see it. - Credentials excluded:
.credentials.jsonand all secret files are in.gitignoreand never committed. - No encryption needed: Since the repo is private and credentials are excluded, there's nothing sensitive to encrypt.
- Doctor check:
claude-sync doctorverifies that no secrets are accidentally tracked. - No third-party services: Uses only
gitandgh(GitHub CLI) — tools you already have.
If you have API keys in settings.json or in MCP server env blocks (e.g., Twitter API keys, RapidAPI keys), they will be synced to your private repo. Options:
- The repo is private — only you can access it
- Move secrets to environment variables on each machine instead
- Use
settings.local.jsonfor machine-specific secrets (excluded from sync) - Use your OS keychain for sensitive values
┌──────────────────────────────────────────────────────────┐
│ Machine A Machine B │
│ ~/.claude/ ~/.claude/ │
│ ├── settings.json ├── settings.json │
│ ├── skills/ ├── skills/ │
│ ├── agents/ ├── agents/ │
│ └── ... └── ... │
│ │ │ │
│ │ claude-sync push │ claude-sync pull│
│ ▼ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ GitHub (private repo) │ │
│ │ yourname/claude-sync-config │ │
│ └─────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘
Under the hood, claude-sync is a single Node.js script that initializes a git repo inside ~/.claude/, adds a comprehensive .gitignore, and pushes to a private GitHub repo. It uses git smudge/clean filters for cross-platform path normalization and extracts MCP server definitions from ~/.claude.json. No magic. No daemons. No cloud services. Just Node.js and git.
- Node.js — you already have this (Claude Code requires it)
- git — you almost certainly have this
- gh (GitHub CLI) — install here if you don't have it
- A GitHub account — free tier works fine (unlimited private repos)
| Feature | claude-sync | dotfiles (manual) | tawanorg/claude-sync | FelixIsaac/claude-code-sync |
|---|---|---|---|---|
| One-command setup | Yes | No | Yes | Yes |
| PowerShell support | Yes | No | No | No |
| No compiled binary | Yes | Yes | No (Go) | No (Go) |
| No cloud account | Yes | Yes | No (R2/S3/GCS) | Yes |
| No encryption keys | Yes | Yes | No (passphrase) | No (age keypair) |
| Auto-sync hook | Yes | No | Yes | No |
| Smart .gitignore | Yes | Manual | Hardcoded | Hardcoded |
| Doctor/health check | Yes | No | No | Yes |
| Dependencies | Node.js, git, gh | git | npm + Go binary | Go binary |
| Platform | Status |
|---|---|
| macOS (bash/zsh) | Fully supported |
| Linux (bash/zsh) | Fully supported |
| Windows (PowerShell) | Fully supported |
| Windows (cmd) | Fully supported |
| Windows (Git Bash / WSL) | Fully supported |
Can I use this with an existing dotfiles repo?
Yes. If you already have a dotfiles repo with a .claude/ directory, you can either:
- Continue using your dotfiles repo and skip
claude-sync - Switch to
claude-syncwhich creates a dedicated repo just for Claude config
They solve the same problem differently. claude-sync is purpose-built for Claude Code and has a smarter .gitignore.
What happens if I change settings on two machines without syncing?
claude-sync pull uses git rebase by default. If there's a conflict, it will stash your local changes, pull, and try to re-apply them. If there's a merge conflict, it tells you and you resolve it like any git conflict.
Can multiple people share a sync repo?
This is designed for personal use (one person, multiple machines). For team config, use a project-level .claude/settings.json in your team's repo instead.
How do I stop syncing?
rm -rf ~/.claude/.git ~/.claude/.gitignoreThis removes the git repo from .claude/ without affecting your config.
Is my conversation history synced?
No. history.jsonl and projects/ are excluded by default. Conversations stay on the machine where they happened.
Contributions welcome. This is a single-file Node.js script — keep it simple, no npm dependencies.
- Fork this repository
- Create a feature branch
- Test on macOS, Linux, and Windows (PowerShell + Git Bash)
- Open a Pull Request