怎麼清掉 Mac 上 AI 編碼工具留下的東西
一顆撐了兩年都很寬裕的磁碟,天天用編碼 agent 之後,幾個月就滿了。agent 本身很小,變的是這台機器編譯的頻率、CLI 在磁碟上把自己換掉的頻率,以及你自己的思考過程有多少已經以文字形式住在家目錄裡。增長幾乎全落在三類上,而這三類要下三種不同的決定,因為它們拿回來的代價差得非常遠。
模型權重是最明顯的嫌疑犯,對這個問題通常也是抓錯人。Ollama、LM Studio 和 Hugging Face 用的是內容定址的儲存區,只有它們自己的工具才修剪得安全,那件事單獨寫在清掉 AI 工具的殘留。這篇談的是你在工作的時候,AI 編碼 agent 一路留下的東西。
動手刪之前先量
兩條指令回答得了大半。第一條把各個 agent 的家目錄加總起來:
du -sh ~/.codex ~/.claude ~/.local/share/claude ~/.grok ~/.cache 2>/dev/null | sort -h
第二條把建置產物找出來,它們散在你開過的每個專案裡。把裡面的根目錄換成你放程式碼的地方:
find ~/www ~/Projects -maxdepth 3 -type d \
\( -name target -o -name node_modules -o -name .next -o -name dist -o -name build \) \
-prune -exec du -sh {} + 2>/dev/null | sort -h | tail -20
-prune 讓 find 不再往已經命中的資料夾裡鑽,這一點很關鍵:少了它,find 會把一個 24 GB 的 target/ 裡每個檔案都走一遍才往下走。寫這篇時我量的那台 Mac,前兩行是一個 24 GB 的 Rust target/ 和一個 Tauri 專案 9.8 GB 的 target/,而 node_modules 那幾棵從 134 MB 到 1.5 GB。重點在比例:那個看起來像是相依套件造成的問題,只佔真實數字的百分之二。
比起清單你更想看圖的話,Mole 的 Analyze 把同一批磁碟區畫成方塊圖,讓你一路點進最大的那個矩形,比起猜該把哪個根目錄餵給 find,這樣快得多。
第一類:被放大的建置產物
這一類不新,新的是量。人手動寫程式,一天編譯幾次。agent 在做一個任務時,幾乎每改一次就編譯一次,跑測試,換第二種做法,再編譯一次。原本幾個月才長起來的快取,現在一個下午就長出來了,而增量建置的資料夾,設計上就是拿磁碟換速度。
Rust 通常大得遙遙領先。一個 target/ 資料夾裝著編譯好的相依套件、增量編譯狀態和建置腳本的輸出,還按 profile 分開存,所以 debug 和 release 是兩份完整的複本。不帶參數的 cargo clean「會刪掉整個 target 資料夾」。先預覽一次:
cargo clean --dry-run
cargo clean --release
cargo clean -p <package> 只清點名的那幾個套件,問題出在 workspace 裡某一個成員時,用的就是它。
JavaScript 的產物攤得比較薄。除了 node_modules 本身,還有打包器和轉譯器在用的 node_modules/.cache、Next.js 建置的 .next,以及工具鏈寫出來的 dist 或 build。專門把那些快取找出來:
find ~/www -maxdepth 4 -type d -path '*/node_modules/.cache' -prune -exec du -sh {} + \
2>/dev/null | sort -h | tail
Python 在它匯入的每個套件旁邊留一個 __pycache__。單個很小,但數以千計。先數再刪,因為同樣一條指令後面接上 rm -rf,一旦根目錄寫錯就沒有回頭路:
find ~/www -type d -name __pycache__ -prune -print | wc -l
位元組碼快取下次匯入時就重新生成,完全不需要連網,所以這是整篇文章裡刪起來最安全的東西。
Go 用的是一份全域建置快取,不是每個專案一個資料夾。go env GOCACHE 印出它的位置,go clean -cache「會讓 clean 移除整份 go 建置快取」。go clean -testcache 讓快取的測試結果過期,但不丟掉編譯好的套件。我這台機器上建置快取是 183 MB,模組快取只有 38 MB,所以就算下載的模組不大,建置這一側還是值得看一眼。
Xcode 要另外處理,因為 DerivedData、封存檔、裝置支援檔和模擬器執行環境是四種東西,還原代價各不相同。這台 Mac 上的 DerivedData 資料夾量到 9.3 GB。清理 Xcode 佔用的空間講哪些可以刪、哪些要留著做符號還原。Gradle 和 Maven 也是同樣的分法,一邊是每個專案的 build/ 資料夾,一邊是 ~/.gradle 或 ~/.m2 底下的全域儲存區,全域那一側歸到清開發快取跟其他套件庫放在一起。
第二類:被取代的舊版 CLI
這一類幾乎沒有人會去找,而在同時跑好幾個 agent 的機器上,它常常比所有快取加起來還大。
agent CLI 自我更新的方式,是下載一整份帶版本號的新發行版,再把啟動器指過去。每份發行版都是自足的,和前一份不共用任何檔案。指標移過去了,舊的那份留在原地,沒有東西會去掃它,所以每更新一次就多一份,永遠不會停。
它們的擺法是同一套,差別只在表面:
- Codex 放在
~/.codex/packages/standalone/releases/<version>-<arch>/,上一層有一個current符號連結指著正在用的那份。 - Claude Code 放在
~/.local/share/claude/versions/<version>,每一項是單一個可執行檔而不是資料夾,~/.local/bin/claude是指向正在用的那個的符號連結。 - Grok 以檔案形式放在
~/.grok/downloads/grok-<version>-macos-<arch>,~/.grok/bin/grok和~/.grok/bin/agent指向目前這一版。 - Cursor Agent 放在
~/.local/share/cursor-agent/versions/<date>-<sha>/,啟動器是~/.local/bin/cursor-agent。 - GitHub Copilot CLI 透過 npm 安裝時是就地替換,但它的安裝腳本會在一個前綴底下寫一份帶版本號的套件,非 root 使用者預設是
$HOME/.local。Mole 會去~/.copilot/pkg/universal檢查同一種擺法。
一次全部量完:
du -sh ~/.codex/packages/standalone/releases/* \
~/.local/share/claude/versions/* \
~/.grok/downloads/* \
~/.local/share/cursor-agent/versions/* 2>/dev/null
寫這篇時我用的那台 Mac 印出來的是:五份 Codex 發行版,262 MB 到 310 MB;五個 Claude Code 執行檔,293 MB 到 306 MB;兩份 Grok 建置版;兩個 Cursor Agent 版本。合計約 3.5 GB,其中正在用的大約 920 MB,其餘全是已經被換掉的執行檔。Codex 自己的問題追蹤裡有一則還開著的請求,回報者量到的增長大約是每次更新 250 MB(openai/codex#22293)。
刪掉任何一個資料夾之前,先把啟動器解出來
誘人的捷徑是按日期排序、留最新的那份。別這樣做。兩種很平常的情況會讓這招失效:遇到回歸之後你刻意鎖了一個舊版本,或者一次更新已經把新資料夾放好、指標還沒翻過去。把正在用的那份刪掉,啟動器就指向空無一物。
改成問啟動器。它是一個符號連結,把它解開:
readlink -f "$(command -v codex)"
readlink -f "$(command -v claude)"
readlink -f "$(command -v grok)"
印出來的是真正的目標,比如 ~/.codex/packages/standalone/releases/0.147.0-aarch64-apple-darwin/bin/codex,而 ls -l "$(command -v codex)" 顯示的是每一跳,不是最終答案。印出哪一份,哪一份就是正在用的。不在那條路徑上的同層資料夾都已被取代,丟進垃圾桶是安全的。丟完先把 CLI 跑一次,確認啟動器仍然解得開,再清空垃圾桶。
第三類:agent 的工作狀態,不是垃圾
第三類是清理工具真的會造成傷害的地方,因為它看起來跟前兩類一模一樣。
工作階段的對話紀錄、記憶、計畫和產生的附件,住在 ~/.codex/sessions、~/.codex/archived_sessions、~/.codex/memories、~/.claude/projects 和 ~/.grok/sessions。它們是以工作階段 id 命名的 JSONL 檔,帶時間戳,只追加不修改,而且一直長。通用清理工具用的每一條啟發式規則都會說:這是日誌檔。我量的那台 Mac 上,~/.codex/sessions 是 9.8 GB,~/.claude/projects 是 2.7 GB、共 2362 個對話紀錄檔,~/.grok/sessions 是 1.3 GB,一個很大、很誘人的數字,掛在一堆看起來可以丟的檔案上。
它們不是日誌。一份對話紀錄記的是一個改動怎麼被想出來的:試過又被否決的做法、把某條路排除掉的那個限制、最後為什麼定成這樣。那些推理過程別的地方都沒有。commit message 記的是改了什麼,程式碼記的是活下來的那個選項,不是被丟掉的另外四個。它們安安靜靜累積好幾個月,而你第一次回頭問「這東西當初為什麼要這樣做」的時候,就會知道它的價值。
更大的風險其實不是第三方清理工具。Claude Code 自己就帶了一輪保留期清理:cleanupPeriodDays 預設 30 天,啟動時會刪掉 projects/ 底下超過這個天數的對話紀錄、計畫檔、file-history/ 裡編輯前的快照,以及每個工作階段的任務清單。它的 .claude 資料夾說明寫清楚了哪些路徑會被掃、哪些永久保留。你想留一年的紀錄,現在就把那個數字調大,不要事後才發現預設值是多少。同一頁也寫了反過來要用的 claude project purge,確實想把某個專案的狀態徹底清掉時用它。
Mole 一概不碰。上面那五條路徑,加上 ~/.claude/file-history、~/.claude/plans、~/.claude/tasks、~/.codex/attachments 和 ~/.codex/generated_images,放多久都在它的保護清單上。沒有年齡門檻,沒有「超過 90 天」的例外,也沒有哪個開關能把它打開。這幾條路徑的年齡例外做過一次,當天就被撤掉了,因為舊的對話紀錄不等於過期的對話紀錄。
一條判準:按還原代價排序,不按大小
這條規則讓三類都變得可判斷。每個候選都按「拿回來要花多少」排,不按它顯示幾 GB 排。
本機就能重生。 建置產物、增量編譯狀態、位元組碼快取、DerivedData。刪掉它們,代價就是眼前這台機器幾分鐘的 CPU,完全不牽涉網路。放心刪,最大的那幾個也不必多想。
重建代價高。 套件庫、node_modules、CocoaPods、Python 虛擬環境、vendor 資料夾、模型權重、iOS DeviceSupport。每一項都需要網路,需要套件庫到今天還供得出 lockfile 指名的那些版本,有時候還需要一套原生工具鏈。真正的代價不是網路好的時候那幾分鐘,而是你在火車上還能不能工作。這些要一項一項審。
不可替代。 對話紀錄、agent 的記憶、計畫檔、專案狀態、本機微調過的模型。再多 CPU 和頻寬都換不回來。它們永遠不該進批次刪除,也不該出現在你有機會勾錯的地方。
麻煩的是第一層和第二層長得一模一樣。target/ 和 node_modules/ 都是專案根目錄下的大資料夾,都塞滿相依套件的產物,都寫在 .gitignore 裡,也都是一行指令就能重新生成。按大小排序,它們就挨在一起。但 cargo build 是從磁碟上已經有的原始碼重建 target/,npm ci 卻要求套件庫還活著、lockfile 還解得開。一個是一杯咖啡的時間,另一個是一個下午的停擺,或者一個已經被撤下、你再也裝不回來的套件。把兩者混為一談是這一類裡最常見的錯誤,也是為什麼「刪最大的資料夾」即使釋放最多空間,仍然是壞建議。
在 Mole 裡做這件事
手動路線走得通,也不花錢。Mole 多做的一件事,是把三類東西收進同一份先審再清的清單,分層的界線已經套好,哪個點開頭的資料夾裝著對話紀錄,不必由你記。
打開 Clean 跑一次掃描。掃描免費,也不需要授權。每個候選都帶著精確路徑、所有者和量出來的大小,在你同意這份清單之前什麼都不會動。沒把握的一律預設不勾,所以預設動作永遠是比較小的那個。刪除走垃圾桶而不是直接解除連結,弄錯了是從垃圾桶拖回來,不是從備份還原,而批次操作除了報移除了什麼,也報略過了什麼、失敗了什麼。
舊版 CLI 這一項,上面那段啟動器解析是 Mole 幫你做的。它讀每個 agent CLI 的啟動器符號連結,解析到正在用的那份發行版,再把那一份排除在候選之外,所以刻意的降級會原封不動留著,不會被當成舊版本。這個行為是照著 Codex 量出來的情況做的:五份發行版共 1.2 GB,只有一份在用。
Mole CLI 免費、開源,在 shell 裡用 mo clean 做同一件事;每個具破壞性的指令都吃 --dry-run,所以任何東西動之前,你都讀得到完整的路徑清單。兩邊共用 ~/.config/mole/whitelist 這一份保護清單和 ~/Library/Logs/mole/operations.log 這一份操作日誌,全部在本機執行,不上傳,也不回傳遙測。
邊界講白了:Mole 不是備份,不處理惡意軟體,遇到帶驅動程式或系統延伸功能的軟體也取代不了原廠的解除安裝程式。它不刪模型權重,也不刪 AI 對話紀錄,連問都不會問。那些留給擁有它們的工具。
讓它不要再長回來
三個設定改一下,大部分東西就不會再長回來。
讓 Rust 全部寫進同一個建置資料夾。 CARGO_TARGET_DIR 設定的是「所有產生的產物放在哪裡」,這樣每個專案都寫進同一棵樹,你可以在同一個地方量、同一個地方清。取捨是真的:Cargo 會鎖住建置資料夾,所以共用同一個 target 的兩個專案只能一個一個建,不能平行。日常會同時跑多個建置的話,就讓它們各自分開,改成定期清一次。
全域儲存區交給既有機制定期修剪,不要手動刪。 現在的 Cargo 跑一般的 build 和 fetch 時,就會順手移除全域快取裡沒用到的條目,npm 則把自己的快取描述成可自癒,維護指令是 npm cache verify。讓這些機制自己跑,不要直接去刪家目錄底下那些點開頭的資料夾。清開發快取裡有各個工具的指令。
確認 agent CLI 會不會自己修剪舊發行版,而且先假設它不會。 寫這篇時,Codex 和 Claude Code 我都沒找到有正式文件說明的旗標或設定項,能清掉被取代的發行版執行檔,Codex 那則請求也還開著。Claude Code 的 cleanupPeriodDays 掃的是工作階段資料,不是版本執行檔,在這裡幫不上忙。在這件事改變之前,這是一份會重複出現的工作,也是清單上價值最高的一項,因為 agent 發版多快,它就長回來多快。
常見問題
AI 編碼工具實際上佔多少磁碟?
執行檔各自只有幾百 MB,重點在累積。這篇量的那台機器上,四個 agent CLI 的版本資料夾合計約 3.5 GB,其中正在用的只有 920 MB,工作階段的對話紀錄約 14 GB,而單單一個 Rust target/ 資料夾就是 24 GB。這些數字跟你用什麼語言的關係,遠大於跟你用哪個 agent 的關係,所以跑一次文章開頭那兩條 du 指令,不要相信任何人給的數字,包括這一份。
刪掉舊的 Claude Code 或 Codex 版本安全嗎?
只要先把啟動器解出來就安全。跑 readlink -f "$(command -v claude)" 或你那個 CLI 的對應指令,留下它印出來的那條路徑,其餘同層的丟進垃圾桶。不要按日期排序留最新的,刻意鎖住的降級版本和做到一半的更新,都會讓最新的資料夾成為錯的那個。刪完之後、清空垃圾桶之前,先把 CLI 跑一次。
Mac 清理工具會刪掉 agent 的對話紀錄嗎?
有些會,因為那些檔案看起來就是日誌,這正是這一類特有的風險。Mole 放多久都不碰 ~/.codex/sessions、~/.codex/archived_sessions、~/.codex/memories、~/.claude/projects 和 ~/.grok/sessions。跑任何清理工具之前,先看那些路徑有沒有出現在它的候選清單裡,而如果那個工具在動手之前不肯把清單給你看,那就是答案。
清掉建置快取會讓什麼變慢嗎?
下一次建置會慢一次,之後不會。增量編譯狀態存在的意義就是讓第二次比第一次快,所以刪掉它的代價剛好是每個專案一次冷建置。壞處就這麼多,這也是為什麼建置產物屬於「放心刪」那一層,而需要跟套件庫來回一趟的 node_modules 不屬於。
Ollama 模型和 Hugging Face 快取呢?
不在這篇範圍內,而且是刻意的。那些工具用的是內容定址的儲存區,兩個模型可以共用同一塊資料,所以手動刪檔案,可能讓一個還引用著它們的模型再也載入不起來。用每個工具自己的移除指令,這寫在清掉 AI 工具的殘留。
接下來看哪裡
按還原代價排序,刪發行版之前先解啟動器,對話紀錄別碰。量出來最大的那一行是套件儲存區,清開發快取有各個工具的修剪指令;是 Xcode,清理 Xcode 佔用的空間把可重建的資料夾和要留著的封存檔分開;是模型倉庫,清掉 AI 工具的殘留解釋為什麼刪除這件事必須由所屬工具來做。