AiSyncing 拆解:三百行 bash 幫你把 Claude Code / Codex / Cursor 的記憶備進私有 GitHub(含金鑰外洩的坑)
本文大綱
你這半年最貴的資產,可能連一份備份都沒有
打開 ~/.claude 看一眼:全域 CLAUDE.md、自己寫的 skills/、調過無數次的 agents/、hooks/,還有 projects/*/memory/ 裡累積的長期記憶。再看 ~/.codex/AGENTS.md、~/.cursor/rules/*.mdc。
這些檔案有兩個共同點:一,它們是你用 coding agent 半年以上、一次次踩坑修出來的;二,它們不在任何一個 git repo 裡。你的專案有版控、你的 dotfiles 可能有版控,但 agent 的記憶與指令檔躺在家目錄,跟著這台機器一起活、一起死。
換電腦、重灌、手殘 rm -rf、或者某次 agent 自己改壞了 settings.json — 這些場景沒有一個是罕見的。而復原成本不是「重裝軟體」,是「重新累積半年的調校」。
Diego E. Salazar(GitHub DiegoSalazar,NY)在 2026 年 8 月 24 日開源了 AiSyncing,就是專門解這件事:每天固定時間,把四種 coding agent 的記憶與設定檔 rsync 進一個你自己的私有 GitHub repo,commit、push、跳通知。同一天他以 mastermindxs 這個帳號發到 Hacker News 的 Show HN——老實說沒紅,1 分 0 留言,寫這篇時 repo 也只有 1 顆星。
我把整包 shell 讀完之後的結論是:這東西的價值不在「它很紅」,而在它只有三百多行 bash,你完全讀得懂、也完全可以照抄改成自己的版本。 以下拆解它怎麼運作、預設清單有哪些坑(有一個是真的會外洩金鑰的坑),以及不是 macOS 的人怎麼自己搭一套。
它要解決的問題:agent 設定檔的「無主狀態」
先講清楚問題邊界,因為市面上同類工具解的其實不是同一件事。
Claude Code 的設定是分層的。依官方文件,優先序由高到低是 managed settings、claude --settings、.claude/settings.local.json、.claude/settings.json、~/.claude/settings.json。中間兩層在專案資料夾裡,跟著專案 repo 走,本來就有版控。真正沒人管的是最後一層:使用者層的 ~/.claude/。
同樣的結構在別的 harness 也成立:~/.codex/AGENTS.md 是全域指令、~/.gemini/GEMINI.md 是全域記憶、~/.cursor/rules/ 是全域規則。這些是「跟著你這個人走」而不是「跟著專案走」的資產,所以沒有天然的家。
AiSyncing 的定位很收斂:它不做同步、不做加密、不做多機即時一致,它只做「每天推一份到私有 repo」。這個定位決定了它的實作可以極簡——沒有 daemon、沒有伺服器、沒有 MCP、沒有資料庫。
運作原理:三百行 bash 幹完的事

核心是 sync.sh,流程五步,我按原始碼逐段講。
第一步:include 清單就是全部的設定介面
config.json 由 setup.sh 產生,長這樣(節錄預設值):
{
"schedule_hour": 15,
"sources": {
"claude": {
"enabled": true,
"source_dir": "~/.claude",
"include": [
"CLAUDE.md", "config.json", "settings.json",
"remote-settings.json", "package.json",
"projects/*/memory/**",
"agents/**", "commands/**", "hooks/**", "skills/**"
]
},
"codex": {
"enabled": false,
"source_dir": "~/.codex",
"include": ["AGENTS.md", "AGENTS.override.md", "config.toml", "*.config.toml", "memories/**"]
},
"gemini": { "enabled": false, "source_dir": "~/.gemini",
"include": ["GEMINI.md", "settings.json", "commands/**", "extensions/**"] },
"cursor": { "enabled": false, "source_dir": "~/.cursor",
"include": ["rules/**", "mcp.json", "permissions.json"] }
}
}
重點是這是 allow list 而不是 deny list。沒被 glob 點名的檔案一律不會被備份。這個選擇很關鍵,等一下講安全問題時會回來。
setup.sh 用最土的方式偵測你裝了什麼:[ -d "$HOME/.claude" ] && CLAUDE_ENABLED=true,四個目錄各測一次。所以 Claude Code 在你機器上、Codex 沒裝,產出的 config 就是 claude true、codex false。
第二步:現場生成 rsync filter(這段是全篇最值得抄的)
rsync 的 include/exclude 有個經典陷阱:你寫 --include='projects/*/memory/**' --exclude='*',結果什麼都沒複製到。因為 rsync 是逐層遞迴掃的,projects/ 這層目錄先被 - * 擋掉,就根本不會走進去看子目錄。
sync.sh 用一段內嵌 python 解掉:把每個 pattern 拆成路徑片段,逐層補上父目錄的 include 規則,最後補一條 - *。實際生成出來是這樣:
+ /projects/
+ /projects/*/
+ /projects/*/memory/**
+ /agents/
+ /agents/**
...
- *
然後餵給 rsync -av --delete --filter="merge $filter_file" "$source_dir/" "$dest/"。
這個「自動補父目錄」的小函式,是你要自己寫任何 rsync 選擇性備份時都會需要的東西,二十行不到,可以直接搬走。
第三步到第五步:rsync → commit → push → 通知
每個來源 rsync 進 data/<source>/,所以最後的 repo 結構是 data/claude/、data/codex/、data/cursor/ 各一包。來源目錄不存在只印 Skipping,不會讓整個腳本掛掉;全部來源都失敗才 exit 1 並發通知。
commit 訊息會標出這次真的有跑成功的來源:sync(claude,codex): 2026-08-24 15:00:00。沒有變動時它會先 git diff --quiet 檢查,直接跳過不做空 commit。
通知那層是一支 notifier.swift,setup.sh 會用 swiftc 編成 AiSyncing.app,Info.plist 裡設 LSUIElement=true 所以不佔 Dock,走 macOS UserNotifications 發橫幅,點一下開你備份 repo 的 commits 頁。沒編成功就退回 osascript 的 display notification(就沒有點擊開連結了)。
排程是 macOS LaunchAgent,label com.aisyncing.daily,StartCalendarInterval 設你選的整點、RunAtLoad 是 false——所以裝完不會立刻跑一次,這點值得注意,裝完請自己手動跑一次確認。
一個容易忽略的設計:備份 repo 就是 AiSyncing 本身
setup.sh 做了一件有點意思的事:它把你 clone 下來的 AiSyncing 目錄的 origin 改名成 upstream,再把 origin 指到剛用 gh repo create --private 開好的備份 repo,然後 git add -A 整包 push 上去。
意思是——你的備份 repo 裡同時裝著資料(data/)和還原工具(sync.sh、setup.sh、notifier.swift)。換機時你 clone 一個 repo 就同時拿到資料和工具,rsync 回去、再跑一次 setup.sh 就恢復排程。而 git fetch upstream && git merge upstream/main 可以拉作者後續的更新。
代價是你的私有備份 repo 會夾帶 AiSyncing 專案本身的 git 歷史,git log 會有點雜。這是可接受的 trade-off,但值得先知道。
五分鐘裝起來(macOS)
前置:brew install gh 並且 gh auth login 過。另外要 git、python3、rsync(macOS 都內建)。
git clone https://github.com/DiegoSalazar/AiSyncing.git ~/AiSyncing
cd ~/AiSyncing
bash setup.sh
setup.sh 會問你五件事:備份 repo 名稱(預設 ai-backup,不存在就自動用 gh 開一個 private)、commit 用的 git name / email(帶入你的 global 設定)、偵測到的工具確認、每天幾點跑(預設 15)、然後編 app、裝 LaunchAgent、推第一版。
裝完立刻做這件事——先手動跑一次,然後檢查它到底備了什麼:
bash ~/AiSyncing/sync.sh
find ~/AiSyncing/data -type f | head -50
du -sh ~/AiSyncing/data/*
進階招式
招式一:push 前先掃金鑰(強烈建議)
這是我認為最需要補的一塊。看預設 include 清單:~/.claude/settings.json、~/.cursor/mcp.json、~/.codex/config.toml、hooks/** — 這四個位置都是實務上很常出現 API key 的地方。Claude Code 的 settings.json 支援 env 區塊(官方文件明列的鍵),很多人把 provider key 直接寫在裡面;Cursor 的 mcp.json 和 Codex 的 config.toml 定義 MCP server 時,env 幾乎一定帶 token。
私有 repo 不等於安全:git 歷史是永久的,一旦某次 commit 寫進金鑰,之後把檔案刪掉也不會消失,得 rewrite history。加上這是一台每天自動 push 的機器人,你不會每次都盯著看。
所以在讓排程上線前,包一層檢查:
# 第一次上線前,人工掃一遍 data/
cd ~/AiSyncing && bash sync.sh # 先讓它 rsync + commit 一次
grep -rIE 'sk-ant-|sk-[A-Za-z0-9]{20,}|ghp_|github_pat_|AKIA[0-9A-Z]{16}|xox[baprs]-' data/
更乾淨的做法是裝 gitleaks,在備份 repo 裡放一個 .git/hooks/pre-commit:
#!/usr/bin/env bash
gitleaks protect --staged --redact --no-banner || {
echo "gitleaks 擋下這次 commit"; exit 1
}
如果你確定不想備這些檔案,最省事的是直接從 config.json 的 include 拿掉 settings.json / mcp.json / config.toml,只留純指令與記憶類的檔案。備份的價值 90% 在 CLAUDE.md、skills/、agents/、memory/ 這幾類純文字,不在設定檔。

招式二:加一個自訂來源
sync.sh 對來源數量沒有硬編碼,config.json 的 sources 加一個 key 就多一個來源。README 給的例子是 Windsurf:
"windsurf": {
"enabled": true,
"source_dir": "~/.codeium/windsurf",
"include": [".windsurfrules", "memories/**", "config.json", "prompts/**"]
}
同樣邏輯可以加 Aider(~/.aider.conf.yml 在家目錄,要把 source_dir 設成 ~ 並且 include 寫精準)、opencode、或你自己團隊的 prompt 目錄。
改完 include 之後,先用 dry-run 驗證 filter 有沒有寫錯,不要直接讓排程跑:
rsync -avn --delete --filter='+ /rules/' --filter='+ /rules/**' --filter='- *' \
~/.cursor/ /tmp/verify-cursor/
-n 是 dry run,只印不做。看印出來的清單對不對,再寫進 config.json。
招式三:不是 macOS 的人怎麼辦
sync.sh 本身是純 bash + rsync + git + python3,Linux 和 WSL 都能跑,跑不動的只有兩件事:swiftc 編通知 app(sync.sh 會 fallback 到 osascript,Linux 上這行也不存在,但它有 || true 兜住不會中斷),以及 LaunchAgent 排程。
排程自己補一個 systemd timer 就好:
# ~/.config/systemd/user/aisyncing.service
[Unit]
Description=AiSyncing daily backup
[Service]
Type=oneshot
ExecStart=/bin/bash %h/AiSyncing/sync.sh
# ~/.config/systemd/user/aisyncing.timer
[Unit]
Description=Run AiSyncing daily
[Timer]
OnCalendar=*-*-* 15:00:00
Persistent=true
[Install]
WantedBy=timers.target
systemctl --user daemon-reload
systemctl --user enable --now aisyncing.timer
systemctl --user list-timers aisyncing.timer
Persistent=true 這個旗標值得指出來:機器在 15:00 是關機狀態的話,開機後會補跑一次。macOS 那邊的 LaunchAgent 行為沒那麼確定,所以我不敢替它掛保證——想確認就手動跑。
另外注意 SSH 金鑰:sync.sh 有處理 LaunchAgent 環境下讀不到 SSH_AUTH_SOCK 的問題(用 launchctl getenv 撈回來)。換到 systemd user service 也會遇到同一類問題,如果你的 origin 是 SSH 協定,記得確認 agent socket 有傳進去,或乾脆用 HTTPS + gh 的 credential helper。
數據與限制:誠實版
先把數字講清楚,因為這是一個非常新的專案:
- repo 建立日期 2026-08-24,寫這篇時(8/25)star 數 1、fork 1、open issue 0。這不是「經過驗證的成熟工具」,是「一個乾淨的週末專案」。
- Show HN 那則(HN 帳號
mastermindxs,2026-08-24)目前 1 分、0 留言,等於沒有社群檢驗。 - 語言是 Shell,MIT 授權。repo 裡有
tests/run.sh的 e2e 測試腳本,README 掛了 Tests 與 ShellCheck 兩個 badge。
再講功能上的限制,這些是我讀完原始碼歸納的:
一、平台實質上綁 macOS。 README 直接標 platform-macOS,通知與排程都是 macOS 專屬。核心邏輯可攜,但你得自己接排程(見上一節)。
二、有些東西預設沒備,而且有些是「故意沒備才對」。 依 Claude Code 官方文件,~/.claude.json 存的是登入 session、MCP server 設定、以及每個專案的信任狀態。它在家目錄下、不在 ~/.claude/ 裡,所以 AiSyncing 碰不到。這是好事——你不會把登入 session push 上 GitHub;但代價是換機之後 MCP server 要自己重接。同理,~/.claude/projects/ 下的對話逐字稿(.jsonl)也沒被備份,只備 projects/*/memory/**。這個取捨我覺得是對的:逐字稿又大又敏感。
三、config.json 自己會被 commit 進備份 repo。 .gitignore 只擋 .DS_Store、AiSyncing.app/ 和兩個研究報告檔。你的 backup repo URL、git name、email 會進版控。私有 repo 的話影響不大,但知道一下。
四、rsync --delete 的語意要理解。 本機刪掉的檔案,下次 sync 會從 data/ 消失。但因為外面包了 git,歷史還在,git log -- data/claude/skills/foo.md 找得回來。所以它是「鏡像當下狀態 + git 保留歷史」,不是「累積式歸檔」。這其實是好設計,只是別誤以為 data/ 是全集。
五、doc 監控機制只是「提醒」不是「自動更新」。 repo 裡有個每週一 10:00 UTC 跑的 GitHub Action(Research AI Tools),用 scripts/research-tools.py 抓十個官方文件頁面、算 SHA-256 前 16 碼、跟 scripts/doc-hashes.json 的基準比對,變了就開 issue 或在既有 issue 留言,不會自動改 config。這個設計我很喜歡(自動改備份規則才是災難),但要指出它的覆蓋不平均:Codex 監了三個頁面(AGENTS.md guide、config、skills)、Gemini 監了五個,Claude Code 只監了 anthropics/claude-code 的 README.md 一個檔。Claude Code 的 settings 文件改了,這個機制看不到。
什麼時候該用、什麼時候別用
該用:你是單人開發者、主力機是 Mac、~/.claude 或 ~/.codex 裡有你調很久的 skills 和記憶、而且你目前備份策略是「沒有」。這種情況下裝它的期望值極高——成本十分鐘,避免的是幾個月的重建。
該用但要改:你在 Linux / WSL。核心腳本能跑,自己補 systemd timer。
別用:
- 你要的是多機即時同步。它一天一次、單向推送,兩台機器各自往同一個 repo push 會撞 non-fast-forward。要跨機同步的話,
memoir(camgitt)走 MCP + 端對端加密、agent_settings_backup_script(Dicklesworthstone)做 git 版控加尺寸輪替,方向都不同,值得比較過再選。 - 你的設定檔一定含金鑰而你不想做掃描。那就別自動化,或把 include 縮到只剩純文字指令檔。
- 你已經在用 dotfiles 管理器。
chezmoi、yadm這類工具本來就處理「家目錄檔案 + 版控 + 多機」,多裝一套 AiSyncing 只是多一個排程。這時候更划算的做法是把 AiSyncing 的 include 清單當成一份「該備哪些檔案」的參考答案抄進你既有的 dotfiles 設定——說真的,那份清單本身就值這趟。 - 團隊共用。這是個人備份工具,沒有多人、沒有權限模型。團隊要共用 skills 和 agent 定義,正解是開一個共用 repo 然後 symlink 或用 plugin marketplace,不是每人各備一份。
對工程團隊的實際意義
拉高一層看,這個小工具點出一件正在發生但還沒被制度化的事:coding agent 的設定檔已經變成生產資產,但大部分團隊還把它當暫存檔對待。
三個可以馬上做的動作:
- 盤點你的使用者層設定。 花十分鐘
find ~/.claude ~/.codex ~/.cursor -maxdepth 2 -type f | head -50,把「掉了會痛」的檔案列出來。多數人會驚訝於清單有多長。 - 把「個人層」和「專案層」分清楚。 專案層的
.claude/settings.json、CLAUDE.md、.claude/skills/應該進專案 repo 讓全隊共享——這件事很多團隊還沒做。個人層的才需要 AiSyncing 這種工具。 - 把金鑰從設定檔裡拿掉。 這件事跟備不備份無關,本來就該做。
settings.json的env區塊改用 shell export 或apiKeyHelper,mcp.json的 token 改讀環境變數。做完之後,備份這件事就從「有風險的操作」變成「無腦推上去就好」。
第三點才是重點。AiSyncing 只是把一個既有的衛生問題照亮了:如果你不敢把 ~/.claude 推到私有 repo,通常不是因為備份危險,而是因為那個資料夾本來就不乾淨。
來源
- AiSyncing repo(primary):https://github.com/DiegoSalazar/AiSyncing — 作者 Diego E. Salazar(GitHub
DiegoSalazar),MIT 授權,2026-08-24 建立。本文的機制描述全部來自sync.sh、setup.sh、config.example.json、scripts/research-tools.py、.github/workflows/research.yml原始碼。 - Show HN 討論串:https://news.ycombinator.com/item?id=49426934 — 「Show HN: AiSyncing – Back up your AI coding assistant memories to GitHub」,HN 帳號
mastermindxs,2026-08-24。 - Claude Code Settings 官方文件(Anthropic):https://code.claude.com/docs/en/settings — 設定檔優先序、
~/.claude.json的內容(登入 session/MCP 設定/專案信任狀態)、env區塊與apiKeyHelper皆依此文件。 - 同類專案(供比較,未逐一驗證實作):
camgitt/memoir、Dicklesworthstone/agent_settings_backup_script。
整理:DataAgent · Coding Agent 實戰教學


