Skip to content

Repository files navigation

claudeport

Sync your Claude Code configuration — settings, skills, agents, commands, plugin selections, CLAUDE.md, keybindings — across machines, through a git repo you own. No server, no accounts.

workstation ~/.claude  ⇄  your git repo  ⇄  notebook ~/.claude

Install

npm install -g claudeport

Requires Node ≥ 20 and git on your PATH.

Quickstart

Create an empty, private repo (GitHub/GitLab/anywhere), then on your first machine:

claudeport init git@github.com:you/claude-config.git   # seeds the repo from ~/.claude

On every other machine:

claudeport init git@github.com:you/claude-config.git   # adopts the config from the repo

Day to day:

claudeport status   # what's out of sync
claudeport diff     # exact changes
claudeport push     # publish this machine's config
claudeport pull     # apply the repo's config here

What syncs

The repo contains a claudeport.json manifest listing what to sync (relative to ~/.claude). The default:

{
  "version": 1,
  "paths": [
    "settings.json",
    "skills/",
    "agents/",
    "commands/",
    "CLAUDE.md",
    "keybindings.json",
    "plugins/installed_plugins.json",
    "plugins/known_marketplaces.json"
  ]
}

Edit it by hand (and push) to change what syncs everywhere, or run the interactive picker:

claudeport manifest   # choose paths — whole folders or individual files — then push

manifest discovers your top-level ~/.claude entries, lets you toggle each one (whole folder, specific files, or off), and writes claudeport.json for you. Denied paths never appear. Run claudeport push afterwards to sync the change.

Plugin code is never synced — only your selections travel. After a pull that changes plugins, restart Claude Code; if a plugin appears missing, reinstall it via /plugin.

What never syncs

A hardcoded denylist wins over the manifest, and these cannot be synced even if you add them to the manifest:

  • Secrets — anything matching *credentials*, *.pem, or *.key.
  • Machine-local state & noise — the projects, sessions, session-env, file-history, shell-snapshots, cache, paste-cache, plugins/cache, telemetry, backups, security, downloads, and todos directories.
  • Volatile fileshistory.jsonl, policy-limits.json, and remote-settings.json.

Safety

  • pull shows what will change and asks before touching anything (--yes to skip).
  • Files it overwrites or deletes are backed up first to ~/.claude/backups/claudeport-<timestamp>/.
  • push refuses when the repo moved ahead — pull first, git style. No silent clobbering.
  • Use a private repo: your settings may reveal hostnames, hook commands, and workflow details.

Trust model

Only sync a repo you fully control. pull writes the repo's settings.json, skills/, commands/, and agents/ into ~/.claude — and those can contain hooks and instructions that run arbitrary commands. Pulling from a repo someone else can write to is equivalent to running their code on your machine. The confirm prompt lists which files change; run claudeport diff first if you want to see their contents.

How it works

Your repo is cloned to ~/.claudeport. push copies manifest-tracked files from ~/.claude into the clone, commits, and pushes. pull fast-forwards the clone and copies files back. Plain files, plain git — you can inspect, revert, or recover anything with normal git commands in ~/.claudeport.

Configuration

By default claudeport reads ~/.claude and clones into ~/.claudeport. Override either with the config command, which persists to a file in your native config dir (~/.config/claudeport/config.json on Linux/macOS, %APPDATA%\claudeport\config.json on Windows):

claudeport config set claude-dir ~/custom/.claude   # where your Claude config lives
claudeport config set sync-dir  ~/custom/.claudeport   # where the repo is cloned
claudeport config get           # list current values
claudeport config unset claude-dir
claudeport config path          # print the config file location

Each dir is resolved as env var > config file > default, so the env vars still work as a per-shell / CI override:

Setting Env var Config key Default
Claude config dir CLAUDE_CONFIG_DIR claude-dir ~/.claude
Clone location CLAUDEPORT_DIR sync-dir ~/.claudeport

Not (yet) synced

MCP server configs (they often embed secrets and machine-specific paths), per-machine setting overrides, and project-level .claude/ dirs are deliberately out of scope for v1.

Development

Run the real claudeport command straight from a checkout, instead of node dist/index.js:

pnpm install
pnpm build          # compile src/ -> dist/ (the linked command runs the build output)
npm link            # symlink `claudeport` onto your PATH, pointing at this repo's dist/

Now claudeport <cmd> works from any directory and reflects your local code. While iterating, keep a rebuild running in a second terminal so edits go live on save:

pnpm build:watch    # tsc --watch; recompiles into dist/ on every change

Run the tests with pnpm test (or pnpm test:watch). When you're done, remove the global link:

npm unlink -g claudeport

Local two-machine testing

You can simulate two machines syncing through a repo on a single box, using two terminals and a throwaway local git "remote" — without touching your real ~/.claude. A sandbox under .local-test/ (gitignored) holds a bare remote.git plus isolated config/clone dirs for each simulated machine; environment variables redirect the CLI into it.

pnpm test:local:setup        # builds the CLI, creates .local-test/ with a seeded machine A

# Terminal 1 — machine A (the "workstation")
source scripts/local-test-env.sh a
claudeport init "$CLAUDEPORT_TEST_REMOTE"    # seeds the remote from A's config, pushes

# Terminal 2 — machine B (the "notebook")
source scripts/local-test-env.sh b
claudeport init "$CLAUDEPORT_TEST_REMOTE"    # clones the populated remote, applies it to B

Now iterate: edit files under .local-test/machineA/.claude, then claudeport push in terminal A and claudeport pull in terminal B. claudeport status and claudeport diff work on either side. Sourcing the env script also defines a claudeport shell function that runs node dist/index.js, so rebuild with pnpm build (or keep pnpm build:watch running) to pick up code changes.

Reset the sandbox to a clean seeded state with pnpm test:local:reset, and remove it entirely with pnpm test:local:teardown.

License

MIT

About

CLI utility to sync ~/.claude across machines.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages