> For the complete documentation index, see [llms.txt](https://weekly-essay.mikey.wang/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://weekly-essay.mikey.wang/zh-hant/2026/w32-a-builders-mac-also-needs-a-sweeper.md).

# W32-Builder 的 Mac，也需要一個 Sweeper

我有三臺 Mac。現在承擔主力工作的是一臺臺式 Mac Studio。這臺 Mac Studio 使用 M2 Max 芯片，配備 12 核 CPU 和 64GB 內存，外接一臺 5K 顯示器和一支舒爾 MV7+ 麥克風。

硬件資源比較充足，日常瓶頸更多來自軟件環境。Codex、Claude Code、ChatGPT、Antigravity 和 Multica 長期並行，背後還會啟動瀏覽器、MCP Server、sidecar、沙箱虛擬機和各種子進程。Node、Python、Rust、代理、Skills、啟動項和緩存也在持續變化。

最近一次環境整理從一個小錯誤開始。每天自動運行的 Skill 治理任務報了 `ModuleNotFoundError: No module named 'tomllib'`。排查後發現，交互式終端和定時任務調用了不同的 Python。Mac 上同時存在系統 Python、Homebrew Python、python.org 安裝的 Python 和 conda。類似問題也出現在 Node 和 Rust 上。

這些局部問題疊加後，環境會逐漸失去解釋性。命令偶爾指向舊版本，後臺進程的歸屬不清楚，同一個任務在終端裡成功，在定時任務裡失敗。Agent 執行得越快，環境漂移得也越快。

我現在把 Mac 看成 Builder 的生產系統。它需要持續治理。

### Builder 也需要承擔 Sweeper

Boris Cherny 最近把 Claude Code 團隊裡的工作歸納為五種角色，包括 Prototyper、Builder、Sweeper、Grower 和 Maintainer。Builder 把原型變成可用於生產的產品和基礎設施。Sweeper 清理界面、簡化系統、撤掉失去價值的功能，並優化性能。[Boris 的原帖](https://x.com/bcherny/status/2071379474277613732)給出了不同產品階段的角色組合，Sweeper 出現在每一個階段。

這很符合我最近的感受。

Agent 天然擅長增加。它可以安裝新工具、生成新代碼、添加新配置、創建新的 Skill。增加的邊際成本已經很低，刪除和收斂仍然需要判斷。哪些東西已經沒有價值，哪些副本應該合併，哪個運行時應該擁有最終入口，哪些自動化動作可能誤刪有效狀態，這些問題都需要 Sweeper。

對個人 Builder 來說，Sweeper 的對象也包括本地環境。進程、緩存、運行時、代理配置、啟動項、Skill 和 Agent 配置都是資源。它們存在依賴，也會隨著使用不斷漂移。

我對環境乾淨的定義有四點。關鍵入口有明確所有者，正在運行的東西可以解釋，漂移能夠被發現，系統能夠回到已知狀態。

### Mac 上有哪些資源

我的主要工作面包括 Codex、Claude Code、ChatGPT、Antigravity 和 Multica。終端側有 Ghostty 和 cmux。知識層主要使用 Basic Memory 和 Craft。Craft 保存適合人閱讀的筆記、文章與整理結果。Basic Memory 保存穩定結論、可複用流程和 Agent 可以持續檢索的上下文。

瀏覽器和自動化層會啟動 Chrome、Playwright 與 MCP Server。公司安全軟件、代理工具、輸入法、同步服務和應用更新器也會長期駐留。

一個桌面應用通常對應一組進程。Claude Desktop 會啟動自己的沙箱虛擬機，Codex 會啟動 sidecar，瀏覽器會拆出 Renderer 和 GPU 進程，Agent 工具會拉起 Node、Python、MCP 和瀏覽器子進程。只看活動監視器裡的單個進程，很難理解真實資源佔用。我的盤查方式會按應用家族聚合主進程和 Helper，再結合 `memory_pressure`、swap、CPU 增量和網絡連接判斷是否異常。

這些資源會發生四類漂移。

第一類是進程和存儲漂移。會話已經結束，子進程仍然存在。下載緩存、日誌和構建產物持續增長。宿主應用也可能反覆拉起已經回收的進程。

第二類是配置和網絡漂移。系統代理、shell 環境、GUI 啟動環境、應用自己的代理設置、DNS 和認證狀態可以各自變化。

第三類是運行時漂移。Homebrew、官方安裝器、版本管理器和舊項目會分別安裝 Node、Python 或 Rust，PATH 最終決定誰生效。

第四類是 Agent 能力資源漂移。Skills 被不同工具安裝到不同目錄，實體副本逐漸分叉，軟鏈斷掉，上游發生更新，frontmatter 或硬編碼路徑開始失效。

前三類影響程序能否穩定運行，第四類影響 Agent 能否調用正確能力。它們屬於同一個治理問題。

### 代理是分層環境

代理環境是我踩坑最久的一層。

macOS 上存在幾條相互獨立的代理路徑。系統網絡代理影響願意讀取 macOS 設置的應用。`~/.zshrc` 裡的代理變量只影響當前 shell 及其子進程。從 Finder、Dock 或桌面應用啟動的進程通常繼承用戶 `launchd` 的環境。部分瀏覽器和 CLI 還有自己的代理設置，TUN、DNS 與認證狀態又位於其他層。

我遇到過一個典型問題。終端裡的 Antigravity CLI 已經可以正常調用，Multica 中同一個 runtime 仍然返回區域不可用。最初的修復寫在 `.zshrc` 函數裡，所以只覆蓋了交互式終端。Multica Desktop 從 GUI 啟動 daemon，不讀取 `.zshrc`，流量最終走了直連。

真正有效的證據來自運行中的進程。Multica daemon 的環境裡沒有代理變量。直接請求和經本地代理請求得到的出口區域也不同。最後我把代理邏輯放到可執行文件入口的 wrapper 中，再用乾淨環境模擬非交互式啟動，確認實際調用路徑已經生效。

這次排查形成了一條穩定規則。我需要驗證目標進程，不能只驗證自己的配置印象。

同一個工具可能從終端、桌面應用、定時任務、MCP 或另一個 Agent 中啟動。名字相同，運行環境可能完全不同。

### 一個運行時只能有一個所有者

那次 `tomllib` 報錯最終暴露出四套 Python。conda 會自動激活 `base`，Agent 在用戶沒有意識到的情況下把包裝進了全局環境。python.org 安裝器向 `.zprofile` 寫入自己的 PATH，Homebrew 保留了其他 Python，非交互式任務又可能優先命中 macOS 自帶版本。

Rust 也存在兩套。Homebrew 安裝的 Rust 在 PATH 前面，rustup 管理的版本長期沒有更新。Node 的問題來自 npm global prefix。fnm 切換 Node 版本時，全局 npm 安裝目錄也會變化，但舊的 Claude Code wrapper 一直硬編碼到 Homebrew 路徑。執行入口和更新入口指向兩個地方，命令可以運行，卻收不到正確更新。

清理之後，我給三個核心運行時分別指定了唯一所有者。

| 運行時    | 所有者                                                    | 主要職責                           |
| ------ | ------------------------------------------------------ | ------------------------------ |
| Node   | [fnm](https://github.com/Schniz/fnm)                   | 管理 Node 版本，按項目切換               |
| Python | [uv](https://docs.astral.sh/uv/guides/install-python/) | 安裝 Python、固定項目版本、創建環境和管理依賴     |
| Rust   | [rustup](https://rust-lang.github.io/rustup/)          | 管理 stable、beta、nightly、指定版本與組件 |

系統自帶的運行時繼續保留。它們屬於 macOS，不進入我的日常 PATH，也不承載個人項目依賴。Homebrew 因其他 formula 依賴而安裝的語言運行時可以繼續作為內部依賴存在，但不應該搶佔用戶入口。

Homebrew 適合管理系統級軟件包、穩定 CLI、GUI App 和底層依賴，例如 `ripgrep`、`jq`、`ffmpeg`，以及 fnm、uv 這類版本管理器本身。一個工具只需要當前穩定版本，也沒有項目級切換需求，就適合交給 Homebrew。

以下場景應該直接使用 fnm、uv 或 rustup。

1. 多個項目需要不同的 major 或 minor 版本。
2. 項目需要通過版本文件固定運行環境。
3. Rust 需要 stable、beta、nightly 或指定日期的工具鏈。
4. Node 的全局包會隨著版本變化而改變 prefix。
5. Python 需要隔離項目依賴，避免汙染系統或全局環境。
6. Agent、定時任務和非交互式 shell 必須解析到同一個可驗證入口。

我的規則很簡單。Homebrew 管軟件包，版本管理器管語言，項目文件管版本，PATH 只暴露一個默認入口。

清理舊運行時前，先更新並驗證新的 owner。Rust 的遷移先完成編譯測試，再刪除 Homebrew Rust。Python 的遷移先確認 uv 的默認入口能在乾淨環境中工作，再處理 conda、python.org 和 Homebrew 的重複安裝。這個順序保證治理過程不會破壞當前工作能力。

### 兩個持續治理的 routines

Boris 還反覆強調，長時間運行的 Agent 必須能夠驗證自己的工作。對於很長的任務，可以讓後臺 Agent 負責驗證，也可以用 Stop hook 做確定性檢查，再把失敗結果交回 Agent 繼續處理。他把驗證反饋視為提升結果質量最重要的手段之一，並給出了兩到三倍的經驗判斷。[原帖](https://x.com/bcherny/status/2007179861115511237)

後來他把工作方式概括為從源碼到 Agent，再從 Agent 到持續運行的 loop。人的工作也從逐輪寫 prompt，轉向設計能夠自己推進的循環。[Boris 在 Meta @Scale 的對談](https://www.youtube.com/watch?v=Z47vatpsGPI)裡把 loops 稱為一次同等重要的躍遷。

一個有效的 loop 至少需要明確目標、當前狀態、驗證反饋和停止條件。Agent 每輪執行後讀取結果，驗證失敗就繼續，目標完成或觸發預算與風險邊界時停止。Sweeper 提供持續做減法的方向，Loop Engineering 讓這件事反覆發生。

我在 Claude 裡建立了兩個 routines，把前面的治理原則落到日常運行中。

第一個每天治理 Skills。所有可複用 Skill 進入同一個受 Git 管理的事實源，Claude Code 和 Codex 通過軟鏈引用。routine 自動修復斷鏈、空殼目錄、緩存垃圾和缺失軟鏈。遇到實體副本、孤兒 Skill、frontmatter 錯誤、上游更新或憑據風險時，它只分析和報告，最終決定留給我。

第二個每週治理 Mac 的基礎資源。它先採集內存、CPU、swap 和進程狀態，再按應用家族聚合資源，識別已經確認的殘留模式。進程回收需要同時滿足存活超過門檻、CPU 空轉和沒有網絡套接字。緩存清理只覆蓋可重建內容，應用私有數據和歸屬不清的資源只測量和報告。

兩個 routines 都遵循相同邊界。腳本處理無信息損失的確定性動作，模型分析需要判斷的項目，人負責刪除、覆蓋和擴大權限。

每輪執行後的新發現還會寫回 Skill、reference 和 Basic Memory。下一輪讀取更新後的事實源，治理能力因此持續積累。

### 持續乾淨是一種工程能力

過去我把 Mac 環境配置理解為一次性工作。安裝軟件，配好 shell 和代理，然後開始使用。

現在的變化頻率已經高得多。Agent 會安裝依賴、啟動服務、創建緩存、生成 Skill、修改配置。Node、Python 和 Rust 持續升級，桌面 App 和 CLI 擁有不同更新鏈，代理和認證也會沿著不同啟動路徑傳播。

Mac 需要自己的控制面。它要知道當前有哪些關鍵資源、誰擁有它們、目標狀態是什麼、如何發現漂移、哪些動作可以自動執行，以及哪些決策必須停下來。

Sweeper 負責做減法。Loop 負責讓減法持續發生。

這種工作短期看不到新功能，卻會降低未來每一次執行的不確定性。Agent 不再隨機命中舊版本，定時任務和終端更容易得到一致結果，故障可以快速定位到具體環境層，新的工具也知道應該接入哪個入口。

對 Builder 來說，這是一種會複利的基礎設施投資。環境越穩定，Agent loop 能運行得越久。所有權越清楚，自動化可以獲得的權限越大。治理記錄越完整，下一次排障需要重新發現的東西越少。

未來的生產力會同時來自更強的模型、更好的工具和一個長期可解釋、可收斂、可治理的本地環境。

Builder 負責創造。

Sweeper 讓創造不會被自己的殘留拖慢。

### 參考資料

* [Boris Cherny 關於 Claude Code 團隊五種角色的原帖](https://x.com/bcherny/status/2071379474277613732)
* [Boris Cherny 關於長時間任務與驗證反饋的原帖](https://x.com/bcherny/status/2007179861115511237)
* [Fireside Chat with Boris Cherny, Head of Claude Code](https://www.youtube.com/watch?v=Z47vatpsGPI)
* [Homebrew Formulae Versions](https://docs.brew.sh/Versions)
* [fnm（Fast Node Manager）](https://github.com/Schniz/fnm)
* [uv 的 Python 安裝與管理文檔](https://docs.astral.sh/uv/guides/install-python/)
* [uv 的 Python 版本文檔](https://docs.astral.sh/uv/concepts/python-versions/)
* [The rustup book](https://rust-lang.github.io/rustup/)
* [rustup 的 Toolchains 文檔](https://rust-lang.github.io/rustup/concepts/toolchains.html)
