Cross-node migration and backup tool for Claude Code sessions. Migrate session data between development machines and back up to any S3-compatible storage.
The Problem
Claude Code stores session data on local disk (~/.claude/). When you start a session on your MacBook and switch to an Ubuntu server to continue, the context is lost — the session is locked to the original machine.
csm solves this with a Consul-style cluster model, making session data portable across nodes.
Architecture
┌──────────────────────────┐
│ Server (Leader) │
│ │
│ · cluster topology │
│ · WebSocket hub │
│ · session relay │
│ · S3 backup │
│ HTTP + WS :9827 │
└─────┬──────────┬─────────┘
WS │ │ WS
┌───────────┘ └───────────┐
▼ ▼
┌───────────────┐ ┌───────────────┐
│ Agent A │ │ Agent B │
│ (MacBook) │ │ (SVR1) │
│ │ │ │
│ session ops │ │ session ops │
│ S3 backup │ │ S3 backup │
│ (no listen) │ │ (no listen) │
└───────────────┘ └───────────────┘
Cluster mgmt: agents → server (WebSocket)
Session migration: any node ↔ any node (relayed via server WebSocket)
S3 backup: per-node, independent storage
The server (Leader) runs an HTTP server with a WebSocket endpoint. All agents maintain persistent outbound WebSocket connections to the server — no inbound ports required on agent machines, solving NAT traversal issues.
- Server mode — Cluster leader. Manages topology, accepts agent WebSocket connections, relays session operations between nodes.
- Agent mode — Connects to the server via outbound WebSocket. Handles session commands relayed by the server. No port listening needed.
- S3 backup — Optional. Each node independently configures R2/MinIO/any S3-compatible storage.
Quick Start
Install
Linux (recommended for server node):
make build sudo ./scripts/install.sh --local ./bin/cc-session-migrate
This installs the binary to /usr/local/bin, sets up the csm alias, creates the systemd service, and generates a default config at /etc/cc-session-migrate/env.
macOS / Windows:
go install github.com/bigwhite/cc-session-migrate@latest
Then create a csm alias so the examples below work:
# macOS / Linux (add to ~/.zshrc or ~/.bashrc) alias csm='cc-session-migrate' # Windows PowerShell (add to $PROFILE) Set-Alias csm cc-session-migrate
Set Up a Cluster
Tip: Run the server (leader) node on a Linux server that is always online. Agent nodes on your laptop or other machines can join and leave freely.
Step 1 — Start the server node:
# Linux sudo sed -i 's/CSM_AGENT_ROLE=agent/CSM_AGENT_ROLE=server/' /etc/cc-session-migrate/env sudo systemctl enable --now cc-session-migrate cat ~/.csm/config.yaml # view the generated cluster-id and auth-token
# macOS / Windows (run in tmux or a dedicated terminal)
csm agent --server --name server-01Step 2 — On each agent machine, join the cluster:
# Linux make build && sudo ./scripts/install.sh --local ./bin/cc-session-migrate sudo sed -i 's/# CSM_CLUSTER_SERVER_ADDR=/CSM_CLUSTER_SERVER_ADDR=<server-ip>:9827/' /etc/cc-session-migrate/env sudo sed -i 's/# CSM_CLUSTER_AUTH_TOKEN=/CSM_CLUSTER_AUTH_TOKEN=<token>/' /etc/cc-session-migrate/env sudo systemctl enable --now cc-session-migrate
# macOS / Windows (run in tmux or a dedicated terminal) csm agent --server-addr <server-ip>:9827 --auth-token <token> --name my-macbook
Step 3 — Verify cluster status:
Migrate Sessions
# List sessions on a remote node csm session list --node macbook-pro # Pull a session (supports ID prefix matching, minimum 8 characters) csm session pull cebea1f8 --from macbook-pro --project /home/user/my-project # Push a session csm session push cebea1f8 --to server-01 # Batch migrate all sessions csm session pull --from macbook-pro --all # Resume development after migration # NOTE: claude --resume requires the FULL session ID (not a prefix). # Use `csm session list` to find the full ID from the SESSION ID column. claude --resume 47f57b56-48b3-4405-b01d-3b8591874fe2
S3 Backup
# Configure S3 storage csm backup config \ --endpoint https://xxx.r2.cloudflarestorage.com \ --bucket csm-backups \ --access-key $ACCESS_KEY \ --secret-key $SECRET_KEY # Back up all sessions csm backup create # List backups csm backup list # Restore a specific session csm backup restore --node server-01 --session <session-id> --project /home/user/project # Restore the latest backup csm backup restore --node server-01 --session <session-id>
In daemon mode, automatic scheduled backups are available (incremental, based on file mtime). Expired backups are cleaned up automatically (30-day retention by default, minimum 3 copies retained per session).
CLI Reference
Global Flags
| Flag | Default | Description |
|---|---|---|
--config |
~/.csm/config.yaml |
Config file path |
--verbose / -v |
false |
Verbose output |
csm agent — Run Daemon
| Flag | Default | Description |
|---|---|---|
--server |
false |
Run in server (leader) mode |
--server-addr |
Leader address for agent mode (host:port) | |
--auth-token |
Cluster auth token (agent mode) | |
--bind |
0.0.0.0:9827 |
HTTP listen address (server mode only) |
--name |
hostname | Node name |
--data-dir |
~/.claude |
Claude Code data directory |
csm cluster — Cluster Management
| Subcommand | Description |
|---|---|
leave |
Leave the cluster (--force for forced leave) |
list |
List cluster nodes (--format table|json) |
csm session — Session Operations
| Subcommand | Description |
|---|---|
list |
List sessions (--node for remote query, --format table|json) |
pull |
Pull a session (--from source node, --project path mapping, --all batch) |
push |
Push a session (--to target node, --project path mapping, --all batch) |
csm backup — Backup Management
| Subcommand | Description |
|---|---|
config |
Configure S3 storage (--endpoint + --bucket required) |
create |
Create backups (--session for single, all by default) |
list |
List backups (--node / --session filter, --format table|json) |
restore |
Restore a backup (--node + --session required, --timestamp optional) |
csm version — Version Info
Prints version, build time, Go version, and OS/Arch.
Configuration
Config file at ~/.csm/config.yaml, auto-generated on first run:
node: name: "server-01" data_dir: "~/.claude" agent: role: "server" bind: "0.0.0.0:9827" cluster: id: "a1b2c3d4-..." auth_token: "e5f6a7b8..." server_addr: "" s3: endpoint: "" bucket: "" region: "auto" access_key: "" secret_key: "" backup: auto_enabled: true interval: "0 3 * * *" retention_days: 30
All config values can be overridden via CSM_-prefixed environment variables (e.g., CSM_AGENT_ROLE=server). Config file permissions are automatically set to 0600.
Development
Dependencies
| Dependency | Purpose |
|---|---|
spf13/cobra |
CLI framework |
spf13/viper |
Configuration (YAML + env vars) |
gorilla/websocket |
WebSocket connections (hub-and-spoke) |
aws/aws-sdk-go-v2 |
S3 client (R2/MinIO compatible) |
robfig/cron/v3 |
Scheduled backup |
schollz/progressbar/v3 |
Transfer progress bar |
Build & Test
# Build (with version info injection) make build # Run all tests make test # Clean build artifacts make clean
Project Structure
cc-session-migrate/
├── cmd/ # CLI commands (cobra)
├── internal/
│ ├── agent/ # Daemon core (server / agent modes)
│ ├── cluster/ # Cluster topology management
│ ├── session/ # Session scanning, packing, path mapping, ID matching
│ ├── ws/ # WebSocket protocol, hub (server), agent client
│ ├── api/ # HTTP API types, server, and client
│ ├── store/ # S3 client wrapper
│ ├── backup/ # Backup create, restore, list, scheduler
│ ├── config/ # Configuration (viper)
│ └── log/ # Logging (slog)
├── scripts/ # Install script, systemd unit
└── doc/ # PRD, Feature Specs, Plan, Tasks
Design Highlights
- Session ID prefix matching — Git-style, minimum 8 characters, errors on ambiguity
- Atomic migration — Writes to staging directory first, atomic move after SHA256 verification
- Streaming transfer — 64KB chunked streaming, bounded memory usage
- Path mapping — Text replacement in JSONL content for cross-machine project path differences
- WebSocket keepalive — Persistent WebSocket connections with ping/pong, automatic reconnection with exponential backoff
- Hub-and-spoke relay — Session data relayed through the server, no direct node-to-node connections needed (NAT-friendly)
- Incremental backup — Based on file mtime, only backs up changed sessions
- Expiration cleanup — 30-day retention by default, minimum 3 copies per session
Platform Support
| Platform | Architecture |
|---|---|
| Linux | amd64, arm64 |
| macOS | amd64, arm64 |
| Windows | amd64, arm64 |
Donate
If you find csm useful, consider buying me a coffee!
WeChat Pay / Alipay:
License
MIT

