# Show HN: Cc-session-migrate: Cross-node migration for Claude Code sessions

> Source: <https://github.com/bigwhite/cc-session-migrate>
> Published: 2026-07-24 12:13:20+00:00

Cross-node migration and backup tool for Claude Code sessions. Migrate session data between development machines and back up to any S3-compatible storage.

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.

```
                          ┌──────────────────────────┐
                          │    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.

**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
```

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-01
```

**Step 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:

```
csm cluster list
# 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
# 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).

| Flag | Default | Description |
|---|---|---|
`--config` |
`~/.csm/config.yaml` |
Config file path |
`--verbose` / `-v` |
`false` |
Verbose output |

| 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 |

| Subcommand | Description |
|---|---|
`leave` |
Leave the cluster (`--force` for forced leave) |
`list` |
List cluster nodes (`--format table|json` ) |

| 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) |

| 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) |

Prints version, build time, Go version, and OS/Arch.

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`

.

| 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 (with version info injection)
make build

# Run all tests
make test

# Clean build artifacts
make clean
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
```

**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 | Architecture |
|---|---|
| Linux | amd64, arm64 |
| macOS | amd64, arm64 |
| Windows | amd64, arm64 |

If you find `csm`

useful, consider buying me a coffee!

**WeChat Pay / Alipay**:

MIT
