多台 Mac 之间即时同步 AI 工具配置:Syncthing + NAS 实战指南

作为一个同时使用 Claude Code、Cursor、OpenCode、Antigravity 等多种 AI 编码工具的开发者,我一直面临一个痛点:在家里 Mac 上调好的配置,到公司电脑上又得重新设置一遍

Skills、MCP Servers、Memory、各种自定义配置——每次都要手动同步,效率极低。

本文记录我如何用 Syncthing + 极空间 NAS 搭建了一套即时配置同步方案,实现”一台电脑改配置,另一台新开终端就是最新的”。

需求分析

需要同步的内容

工具 配置路径 内容
Claude Code ~/.claude.json MCP servers、主配置
Claude Code ~/.claude/settings.json 模型、环境变量
Claude Code ~/.claude/skills/ 自定义 Skills
cc-switch ~/.cc-switch/settings.json 切换配置
cc-switch ~/.cc-switch/skills/ 自定义 Skills
Cursor ~/.cursor/mcp.json MCP servers
Antigravity ~/.antigravity_tools/gui_config.json GUI 设置
OpenClaw ~/.openclaw/ Memory、Agents

核心要求

  • 即时同步:不是手动 push/pull,改了就自动同步
  • 离线可用:断网时本地有完整副本,联网后自动合并
  • 公司电脑友好:不能安装专有客户端(如极空间客户端)

方案选型

对比了几种方案:

方案 即时性 离线工作 安装要求 跨网络
iCloud + Symlinks 秒级 有本地副本 零安装 支持
Git + auto-push 分钟级 有本地副本 零安装 支持
Syncthing + NAS 秒级 有本地副本 brew install 支持
SMB 直连 实时 断网就挂 零安装 仅局域网

最终选择 Syncthing + NAS,原因:

  1. Syncthing 通过 brew install 安装,是个 CLI 工具,不算”客户端软件”
  2. 文件改动通过 macOS fsevents 检测,秒级同步
  3. NAS 作为 always-on 中枢,两台 Mac 不需要同时在线
  4. 本地保留完整文件副本,断网也能工作
  5. 支持冲突检测(生成 .sync-conflict 文件)

架构设计

1
2
3
4
5
6
7
8
9
10
Mac A (家里)                    极空间 NAS                    Mac B (公司)
│ │ │
│ ← Syncthing 双向同步 → │ ← Syncthing 双向同步 → │
│ │ │
~/ai-sync/ (symlinks) Docker Syncthing ~/ai-sync/ (symlinks)
│ (always-on) │
~/.claude.json → symlink ~/.claude.json → symlink
~/.claude/skills/ → symlink ~/.claude/skills/ → symlink
~/.cc-switch/ → symlink ~/.cc-switch/ → symlink
~/.cursor/mcp.json → symlink ~/.cursor/mcp.json → symlink

核心思路:

  • 所有配置文件实际存放在 ~/ai-sync/ 目录
  • 原位置全部变成 symlink 指向 ~/ai-sync/ 对应文件
  • Syncthing 负责 ~/ai-sync/ 目录的多机同步
  • NAS 作为中心节点,保证离线同步

实施步骤

Step 1:编写安装脚本

创建 ai-sync-setup.sh,支持两种模式:

  • init:首台机器,将配置文件迁移到 ~/ai-sync/ 并建立 symlink
  • join:后续机器,从已同步的 ~/ai-sync/ 建立 symlink
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/bin/bash
SYNC_DIR="$HOME/ai-sync"
BACKUP_DIR="$HOME/ai-sync-backup-$(date +%Y%m%d_%H%M%S)"

# 通用 symlink 函数
link_item() {
local src="$1" # 原路径 (如 ~/.claude.json)
local dst="$2" # 同步目录路径 (如 ~/ai-sync/claude/claude.json)

# 已经是正确的 symlink,跳过
if [ -L "$src" ] && [ "$(readlink "$src")" = "$dst" ]; then
return 0
fi

# 原文件存在,同步目录无文件 → 移动过去 (init 模式)
if [ -e "$src" ] && [ ! -e "$dst" ]; then
cp -R "$src" "$dst"
mkdir -p "$BACKUP_DIR"
cp -R "$src" "$BACKUP_DIR/$(basename "$src")"
rm -rf "$src"
ln -s "$dst" "$src"
return 0
fi

# 两边都有文件 → 备份本地,使用同步目录版本 (join 模式)
if [ -e "$src" ] && [ -e "$dst" ]; then
mkdir -p "$BACKUP_DIR"
cp -R "$src" "$BACKUP_DIR/$(basename "$src")"
rm -rf "$src"
ln -s "$dst" "$src"
return 0
fi

# 只有同步目录有文件 → 直接建 symlink
if [ ! -e "$src" ] && [ -e "$dst" ]; then
mkdir -p "$(dirname "$src")"
ln -s "$dst" "$src"
return 0
fi
}

建立所有 symlink:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Claude Code
link_item "$HOME/.claude.json" "$SYNC_DIR/claude/claude.json"
link_item "$HOME/.claude/settings.json" "$SYNC_DIR/claude/settings.json"
link_item "$HOME/.claude/settings.local.json" "$SYNC_DIR/claude/settings.local.json"
link_item "$HOME/.claude/statusline-command.sh" "$SYNC_DIR/claude/statusline-command.sh"
link_item "$HOME/.claude/skills" "$SYNC_DIR/claude/skills"

# cc-switch
link_item "$HOME/.cc-switch/settings.json" "$SYNC_DIR/cc-switch/settings.json"
link_item "$HOME/.cc-switch/skills" "$SYNC_DIR/cc-switch/skills"

# Cursor
link_item "$HOME/.cursor/mcp.json" "$SYNC_DIR/cursor/mcp.json"

# Antigravity
link_item "$HOME/.antigravity_tools/gui_config.json" "$SYNC_DIR/antigravity/gui_config.json"

Step 2:Mac 端安装 Syncthing

1
2
3
brew install syncthing
brew services start syncthing
# Web UI: http://localhost:8384

Step 3:极空间 NAS 部署 Syncthing

首先 SSH 登录 NAS 获取存储路径:

1
2
ssh -p 10022 你的账号@NAS-IP
# 极空间路径格式: /tmp/zfsv3/sata11/手机号/data

Docker Compose 配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
services:
syncthing:
image: syncthing/syncthing:latest
container_name: ai-sync-syncthing
hostname: zspace-nas
restart: unless-stopped
privileged: true
environment:
- PUID=0
- PGID=0
- STNODEFAULTFOLDER=true
ports:
- 38384:8384 # Web UI (高位端口避免冲突)
- 32000:22000/tcp # 同步协议 TCP
- 32000:22000/udp # 同步协议 QUIC
- 31027:21027/udp # 发现协议
volumes:
- /tmp/zfsv3/sata11/手机号/data/docker/syncthing/config:/var/syncthing/config
- /tmp/zfsv3/sata11/手机号/data/docker/syncthing/ai-sync:/var/syncthing/ai-sync
- /tmp/zfsv3/sata11/手机号/data/docker/syncthing/openclaw-backup:/var/syncthing/openclaw-backup

踩坑记录

  • 极空间的 volume 路径不是标准的 /volume1/...,需要通过 SSH 或 Compose 页面的”查询路径”获取实际路径
  • 需要设置 privileged: truePUID=0,否则会报 permission denied(极空间文件系统不允许容器内 chmod)
  • 建议使用高位端口(如 38384),低位端口容易与 NAS 内置服务冲突

Step 4:互联设备

  1. 获取 Device ID:两端 Syncthing Web UI → Actions → Show ID
  2. 互相添加设备:Mac 端添加 NAS 的 Device ID,NAS 端接受
  3. 共享目录:Mac 端添加 ~/ai-sync 为同步目录,勾选共享给 NAS

Step 5:.zshrc 冲突检测

.zshrc 中添加启动检查:

1
2
3
4
5
6
7
8
9
10
11
# AI Config Sync: 终端启动时检查 Syncthing 冲突文件
_ai_sync_check() {
local sync_dir="$HOME/ai-sync"
local conflicts=$(find "$sync_dir" -name "*.sync-conflict-*" 2>/dev/null)
if [ -n "$conflicts" ]; then
echo "⚠️ AI Config Sync 检测到冲突文件:"
echo "$conflicts"
echo "请手动解决后删除冲突文件。"
fi
}
_ai_sync_check

Step 6:第二台 Mac 加入

1
2
3
4
5
6
# 安装 Syncthing
brew install syncthing && brew services start syncthing

# 在 Web UI 中添加 NAS 设备,同步 ~/ai-sync 目录
# 等同步完成后运行:
./ai-sync-setup.sh join

OpenClaw 备份方案

OpenClaw 的记忆存储在 SQLite 中(~/.openclaw/memory/main.sqlite),不能直接通过文件同步——SQLite 并发写入会损坏数据。

解决方案是定时导出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
# backup-openclaw.sh
SYNC_DIR="$HOME/ai-sync/openclaw-backup"
OPENCLAW_DIR="$HOME/.openclaw"

# 导出 memory
openclaw memory export --output "$SYNC_DIR/memory-latest.json" 2>/dev/null

# 备份配置文件
cp "$OPENCLAW_DIR/openclaw.json" "$SYNC_DIR/openclaw.json" 2>/dev/null
cp -R "$OPENCLAW_DIR/agents/" "$SYNC_DIR/agents/" 2>/dev/null

# SQLite 安全导出
sqlite3 "$OPENCLAW_DIR/memory/main.sqlite" ".dump" > "$SYNC_DIR/memory-dump.sql" 2>/dev/null

加入 cron 每小时执行:

1
2
3
crontab -e
# 添加:
0 * * * * ~/ai-sync/openclaw-backup/backup-openclaw.sh

迁移到新机器时:

1
openclaw memory import ~/ai-sync/openclaw-backup/memory-latest.json

最终效果

同步完成后的目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
~/ai-sync/                     # Syncthing 同步目录
├── claude/
│ ├── claude.json # → ~/.claude.json
│ ├── settings.json # → ~/.claude/settings.json
│ ├── settings.local.json # → ~/.claude/settings.local.json
│ ├── statusline-command.sh
│ └── skills/ # → ~/.claude/skills/
├── cc-switch/
│ ├── settings.json # → ~/.cc-switch/settings.json
│ └── skills/ # → ~/.cc-switch/skills/
├── cursor/
│ └── mcp.json # → ~/.cursor/mcp.json
├── antigravity/
│ └── gui_config.json # → ~/.antigravity_tools/gui_config.json
└── openclaw-backup/
├── backup-openclaw.sh
├── memory-latest.json
└── memory-dump.sql

验证 symlink 是否正确:

1
2
ls -la ~/.claude.json
# lrwxr-xr-x djc staff /Users/djc/.claude.json -> /Users/djc/ai-sync/claude/claude.json

现在,在家里 Mac 上新建一个 Claude Code Skill,几秒后公司 Mac 新开终端就能用了。

注意事项

  1. 敏感信息安全~/.claude.jsongui_config.json 中包含 API Key,Syncthing 传输是加密的,但注意不要把 ~/ai-sync/ 加入公开 Git 仓库
  2. SQLite 不走同步cc-switch.dbopenclaw/memory/main.sqlite 等 SQLite 文件不能直接同步,需要用导出/导入方式处理
  3. 极空间 Docker 权限:需要 privileged: true + PUID=0,否则 Syncthing 无法写入文件
  4. 高位端口:极空间低位端口容易被内置服务占用,建议 Web UI 用 38384、同步协议用 32000
  5. 冲突处理:两台电脑同时改同一个文件会产生 .sync-conflict 文件,终端启动时会自动检测告警

社区替代方案

如果你的场景不同,以下社区项目也值得关注:

  • agents:用 .agents/agents.json 作为单一真相源,自动同步 MCP/Skills 到各工具
  • Memorix:跨 10 种 IDE 的 MCP 记忆桥
  • claude-brain:基于 Git 的 Claude Code 配置同步,带 LLM 语义合并
  • dotclaude:轻量级 Git 方案,同步 ~/.claude/ 配置

折腾了一晚上,终于实现了”改了就同步”的丝滑体验。如果你也在多台电脑间切换使用 AI 编码工具,希望这篇文章能帮到你。