blake@xcode:~/Projects$ cat ios-agent-development.md

使用AI代理建構iOS App:實務工作者指南

# 運用AI代理更快速建構iOS App。涵蓋Claude Code、Codex CLI、Xcode 26.3原生支援、MCP、CLAUDE.md模式、hooks,以及來自8款App的實戰經驗。

words: 3368 read_time: 41m updated: 2026-05-25 06:09
$ less ios-agent-development.md

重點摘要:目前已有3種代理執行環境能為iOS交付程式碼:搭配MCP的Claude CodeCLI、搭配MCP的Codex CLI,以及Xcode 26.3原生Intelligence代理。兩個MCP伺服器(具備59個工具的XcodeBuildMCP,以及具備20個工具的Apple xcrun mcpbridge)讓代理能以結構化方式存取建置、測試、模擬器與偵錯。本指南涵蓋真實的CLAUDE.md模式、hook設定,以及對哪些有效、哪些會壞的誠實評估——這些經驗來自8個正式上線的iOS app,總計293個Swift檔案。18代理擅長SwiftUI檢視、SwiftData模型、重構與建置錯誤診斷。它們不擅長.pbxproj修改、程式碼簽署與視覺偵錯。從「代理撰寫Swift」到「代理交付iOS app」之間的落差,靠的是設定,而不是提示詞。

我已經用AI程式碼代理建置了8個iOS app。不是原型,而是上架App Store的app,包含HealthKit整合、Metal shader、SpriteKit物理效果、iCloud同步、Live Activities、Game Center排行榜,以及橫跨iOS、watchOS和tvOS的多平台target。這些app中的每一行Swift,不是由代理撰寫後由我審查,就是由我撰寫後交給代理重構。依我的估算,代理負責了大部分行級作者工作;我則負責審查、範圍界定,以及需要人類判斷的部分(視覺打磨、簽署、效能調校、App Store提交)。

這份指南就是我剛開始時希望能看到的參考資料。它涵蓋完整技術堆疊:該使用哪個代理執行環境、如何設定MCP伺服器來取得結構化建置存取權、CLAUDE.md該放什麼、哪些hooks能防止代理毀掉您的Xcode專案,以及最關鍵的——代理會在哪裡失敗,而您必須親自接手。

主要重點

給剛接觸AI代理的iOS開發者:

  • 從Claude CodeCLI+XcodeBuildMCP開始。這是目前最成熟的執行環境,也具備最完整的MCP工具覆蓋。安裝兩個指令、在專案加入CLAUDE.md,代理就能自行建置、測試與偵錯,不需要您複製錯誤訊息。
  • 絕對不要讓代理修改.pbxproj。這是最重要的一條規則。用PreToolUse hook封鎖對.pbxproj.xcodeproj/的寫入,可以省下數小時復原時間。
  • 您的CLAUDE.md就是代理的入職文件。花在上面的時間,會在之後每一次接觸此專案的代理工作階段中回收。

給已有代理使用經驗、準備把iOS加入工作流程的人:

  • MCP會改變iOS建置迴圈。在MCP之前,代理能寫Swift,卻無法驗證是否能編譯。有了XcodeBuildMCP後,代理可以寫程式碼、建置、讀取結構化錯誤、修正錯誤並執行測試——全程自主完成。
  • 3種執行環境服務不同需求。Claude CodeCLI適合深入的代理式工作階段,Codex CLI適合headless批次工作,Xcode 26.3原生代理則適合不離開IDE的快速inline修正。
  • Hook基礎架構可以沿用。現有的PostToolUse格式化工具、PreToolUse封鎖器與測試執行器hooks,只需微調路徑,就能同樣用於iOS專案。

給評估AI輔助iOS開發的團隊負責人:

  • 代理成效隨專案文件品質提升,而不是隨專案大小提升。一個有詳細CLAUDE.md的63檔案app,會比完全沒有文件的14檔案app產出更好的代理結果。
  • .pbxproj邊界不可妥協。代理無法可靠編輯Xcode專案檔案。您的工作流程必須納入手動將檔案加入Xcode targets的步驟。
  • 誠實的ROI:在文件完備的專案中,代理能處理大部分實作工作——下方案例研究中,那個15檔案TV app在3小時代理輔助工作內完成並出貨,就是明證。剩下的工作——視覺打磨、簽署、效能調校、App Store提交——仍需要人類判斷。

選擇您的路徑

您需要什麼 前往這裡
第一次設定MCP MCP設定:完整設定——安裝兩個伺服器、驗證、設定代理
為iOS專案撰寫CLAUDE.md iOS專案的CLAUDE.md模式——來自8個app的真實範例
比較3種代理執行環境 iOS的3種代理執行環境——Claude Code、Codex與Xcode native比較
了解代理能做與不能做的事 代理擅長什麼代理不擅長什麼
為iOS開發設定hooks iOS開發用Hooks——儲存時格式化、.pbxproj保護、測試執行器
深度參考(本頁) 繼續閱讀——從設定到進階模式一應俱全

如何使用本指南

這是一份超過3,000行的參考資料。請依您的經驗程度選擇起點:

經驗 從這裡開始 接著探索
剛接觸iOS+代理 先決條件MCP設定您的第一個代理工作階段 CLAUDE.md模式哪些有效/無效
iOS開發者,剛接觸代理 3種執行環境MCP設定CLAUDE.md Hooks架構模式
代理使用者,剛接觸iOS 架構模式代理不擅長什麼CLAUDE.md 框架特定脈絡進階工作流程
兩者都很熟悉 進階工作流程Hooks多平台模式 執行環境比較作品集

目錄

  1. 作品集:8個App,293個檔案
  2. 先決條件
  3. iOS的3種代理執行環境
  4. MCP設定:完整設定
  5. iOS專案的CLAUDE.md模式
  6. 您的第一個代理工作階段
  7. 代理在iOS中擅長什麼
  8. 代理在iOS中不擅長什麼
  9. iOS開發用Hooks
  10. 適合代理協作的架構模式
  11. 框架特定脈絡
  12. 多平台模式
  13. 進階工作流程
  14. 真實案例研究
  15. 使用代理的專案生命週期
  16. 設定代理定義
  17. 代理輔助iOS的測試模式
  18. iOS專案的Context Window管理
  19. 疑難排解
  20. iOS中的常見代理錯誤
  21. 誠實評估
  22. FAQ
  23. 快速參考卡
  24. 參考資料

相關資源

主題 資源
Xcode的MCP設定(較短的部落格文章) 兩個MCP伺服器讓Claude Code成為iOS建置系統
Claude CodeCLI完整參考 Claude CodeCLI:完整指南
Codex CLI參考 Codex CLI:完整指南
Hook系統深度解析 爪的解剖:84個Hooks作為協調層
代理架構模式 代理架構指南
Mac桌面app+Remote Control Claude Code Mac Desktop+Remote Control:CLI使用者指南

Apple生態系系列。21篇正式作品文章,探討與Apple Intelligence、MCP、Foundation Models、Vision、Core ML,以及iOS 26框架堆疊整合的SwiftUI app。內容取材自Water、Get Bananas、Return,以及941作品集的其他專案:

系列首頁:Apple生態系系列

代理式Apple(E4):

主題 資源
Apple Intelligence的intent表面 App Intents是Apple給您App的新API
與iOS app並行的MCP伺服器 兩個代理生態系,一份購物清單
何時使用哪一種 App Intents vs MCP Tools:路由問題
裝置端LLM作為執行期功能與工具的差異 Foundation Models+代理式工作流程
Apple開發用Hooks Apple開發用Hooks
跨程序狀態 單一真相來源:SwiftData+MCP+iCloud

框架(E2/E3):

主題 資源
Foundation Models裝置端LLM Foundation Models裝置端LLM
Vision框架(CV基礎元件) Vision Framework:內建內容
Core ML推論模式 Core ML裝置端推論
RealityKit空間心智模型 RealityKit與空間心智模型
SwiftUI內部機制 SwiftUI由什麼構成
Symbol Effects動畫詞彙 Symbol Effects:SwiftUI內建動畫詞彙
iOS 26+上的Liquid Glass SwiftUI中的Liquid Glass:3種模式

已出貨程式碼(E1):

主題 資源
Live Activities狀態機 Live Activities狀態機
watchOS執行期合約 watchOS執行期合約
SwiftData schema紀律 SwiftData Schema Discipline
HealthKit+SwiftUI模式 iOS 26上的HealthKit+SwiftUI
多平台SwiftUI 5個Apple平台,3個共用檔案
XcodeBuildMCP整合 兩個MCP伺服器,一個Xcode專案

綜合(E5):

主題 資源
iOS app的3個表面 iOS App的3個表面
平台target決策 Apple平台矩陣
我拒絕撰寫的內容 我拒絕撰寫的內容

作品集:8款 App、293個檔案

在深入設定之前,先說明本指南的來源。這些並非玩具專案,而是橫跨5個 Apple framework、3個平台,涵蓋完整 iOS 複雜度的實作案例:從14個檔案的運動追蹤器,到63個檔案的多平台冥想計時器。

App 技術堆疊 檔案 複雜度
Banana List SwiftUI + SwiftData + iCloud Drive 同步 + 用於 Claude Desktop 的 MCP 伺服器 53 完整 CRUD、iCloud 同步、自訂 MCP 伺服器,將 App 資料公開給 Claude Desktop
Ace Citizenship SwiftUI 學習 App + FastAPI 後端 26 用戶端-伺服器、REST API 整合、測驗引擎
TappyColor SpriteKit 顏色配對遊戲 30 遊戲迴圈、物理、觸控處理、粒子效果
Return 禪修冥想計時器 — iOS 26+、watchOS、tvOS 63 HealthKit、Live Activities、Watch 延長執行時間、TV 焦點導覽、iCloud 階段同步
amp97 Metal shaders + 音訊視覺化 41 自訂 Metal render pipeline、音訊分析、即時 GPU 運算
Reps SwiftUI + SwiftData 運動追蹤 14 最小可行 App、乾淨的 SwiftData 模式
Water SwiftUI + SwiftData + Metal + HealthKit 補水追蹤 34 Metal 流體模擬、HealthKit 飲水量記錄、widget
Starfield Destroyer SpriteKit + Metal 太空射擊遊戲 32 99個關卡、8艘船艦、Game Center 排行榜、Metal 後處理

為什麼檔案數很重要:Agent 的成效與專案可讀性相關,而不是專案大小。Return(63個檔案)產生的 agent 輸出比 amp97(41個檔案)更好,因為 Return 有詳細的 CLAUDE.md,包含檔案註解、架構圖與明確模式。amp97 的 Metal shaders 本質上就更難讓 agent 推理,無論文件品質多好都是如此。


先決條件

在為 iOS 開發設定任何 agent runtime 之前:

App Store Connect 截止日期:2026-04-28 起,上傳至 App Store Connect 的 App 必須使用 Xcode 26 或更新版本,並以 iOS 26、iPadOS 26、tvOS 26、visionOS 26 或 watchOS 26 的 SDKs 建置。12(macOS 提交不受此要求限制。)如果您的團隊仍在使用 Xcode 16.x,本指南中的 agent 輔助工具鏈也會成為推動升級的關鍵因素。畢竟,以下任何 MCP 伺服器都必須有 Xcode 26.3+ 才能運作。

必要: - macOS 15+(Sequoia)或 macOS Tahoe - 已安裝並設定 Xcode 26.3+(xcrun mcpbridge 的最低門檻);建議使用 Xcode 26.5+ 以取得 agent 工作流程升級,包括 coding assistant 中的訊息佇列與澄清問題支援,以及 Swift Testing 圖片附件、已記錄 issue 嚴重程度、含 crashlog 的 UI test 當機警告,還有最早於 26.4 加入的 String Catalog 編輯器改進。1314 Xcode 26.5(2026-05-11,build 17F42)是最新穩定版;26.4.1(2026-04-16,build 17E202)則是上一個 26.4 系列的錯誤修正版。15 - 至少安裝一個 iOS Simulator runtime - Anthropic API 帳號(用於 Claude Code)或 OpenAI 帳號(用於 Codex)

建議: - 安裝 SwiftFormatbrew install swiftformat)— format-on-save hooks 會使用 - 安裝 SwiftLintbrew install swiftlint)— 可選,但有助於強制執行樣式規範 - 熟悉終端機 — 3種 runtime 都從命令列操作,或與命令列整合

驗證您的 Xcode 安裝:

# Check Xcode version
xcodebuild -version
# Expected: Xcode 26.3 or later (26.5+ recommended)

# Check available simulators
xcrun simctl list devices available
# Expected: at least one iPhone simulator

# Verify xcrun mcpbridge is available
xcrun mcpbridge --help
# Expected: usage information (not "command not found")

如果 xcrun mcpbridge 回傳「command not found」,代表需要 Xcode 26.3 或更新版本。請透過 App Store 或 developer.apple.com 安裝或更新 Xcode。注意:xcode-select --install 只會安裝 Command Line Tools,其中不包含 mcpbridge — 您需要完整的 Xcode.app。


iOS 的三種 Agent 執行環境

有三種截然不同的執行環境可以用來編寫、建置並測試 iOS 程式碼。它們並非可以互相替代——每一種都有不同的優勢、不同的 MCP 整合模式,以及不同的理想使用情境。

1. Claude Code CLI

簡介:Anthropic 推出的終端機型 agentic 編碼助理。它能讀取您的程式碼庫、執行命令、修改檔案,並透過 MCP 連接外部工具。

MCP 整合:完整支援 XcodeBuildMCP 與 Apple 的 Xcode MCP。Agent 會透過 MCP 協定探索工具,並以結構化參數呼叫它們。兩個伺服器合計提供 59 + 20 個工具。

設定方式:

# Install Claude Code (if not already installed)
claude --version  # verify installation

# Add XcodeBuildMCP (59 tools — builds, tests, simulators, debugging)
claude mcp add XcodeBuildMCP \
  -s user \
  -e XCODEBUILDMCP_SENTRY_DISABLED=true \
  -- npx -y xcodebuildmcp@latest mcp

# Add Apple Xcode MCP (20 tools — file ops, diagnostics, Swift REPL, previews)
claude mcp add --transport stdio xcode \
  -s user -- xcrun mcpbridge

替代方案——xcodebuildmcp init 自動安裝程式(v2.1.0+,2026-02-23):

如果您不想手動配線 MCP,XcodeBuildMCP v2.1.0+ 內建 init 子命令,能自動偵測 Claude Code、Cursor 或 Codex,並一步完成 agent skills 與 MCP 設定的安裝:

xcodebuildmcp init
# Or without a global install:
npx -y xcodebuildmcp@latest init

旗標:--print(將設定輸出到 stdout 供不支援的客戶端使用)、--uninstall(移除)。如果您希望明確掌控要連接哪些 MCP 伺服器以及設定範圍,請略過此功能;上方的手動 claude mcp add 指令能提供這種控制力。16

最適合用於:深度實作工作階段——建構新功能、跨多個檔案進行重構、除錯複雜問題、自動執行建置-測試-修復循環。Claude Code 的 100 萬 token 內容視窗(搭配 Opus 4.6)讓 agent 能將大多數中小型 iOS 專案保留在工作記憶中——以我的經驗來說,視檔案大小而定,大約可達 50 個檔案。

典型工作階段:

You: Add a new SettingsView with toggles for notifications and haptic feedback.
     Use the existing Settings.swift pattern from TimerManager.
     Build for simulator after implementation and fix any errors.

Claude: [reads Settings.swift, TimerManager.swift, existing views]
        [creates SettingsView.swift]
        [calls build_sim via MCP]
        [reads structured error: missing import HealthKit]
        [fixes import]
        [calls build_sim again  success, 0 errors, 1 warning]
        [calls test_sim  all tests pass]

與 MCP 普及前的工作流程相比,關鍵差異在於:agent 永遠不會要求您手動建置或貼上錯誤輸出。建置-錯誤-修復的循環是自主完成的。

2. Codex CLI

簡介:OpenAI 推出的終端機型編碼 agent。概念上與 Claude Code 類似,但使用 OpenAI 模型(GPT-4o、o3),且權限模型有所不同。

MCP 整合:Codex 透過 codex mcp add 命令支援 MCP。Apple 的 Xcode MCP 可直接運作:

# Add Apple Xcode MCP to Codex
codex mcp add xcode -- xcrun mcpbridge

XcodeBuildMCP 也能透過相同的 npx 命令搭配 Codex 使用:

# Add XcodeBuildMCP to Codex
codex mcp add XcodeBuildMCP -- npx -y xcodebuildmcp@latest mcp

最適合用於:無頭批次作業、CI/CD 整合,以及希望從不同模型家族取得第二意見的任務。Codex 的沙箱模式會在隔離環境中執行程式碼,對於會修改狀態的破壞性操作(例如測試套件執行)特別有用。

與 Claude Code 的主要差異: - 使用 OpenAI 模型,而非 Claude 模型 - 內容視窗大小與 token 經濟模型不同 - 沙箱優先的權限模型(預設較為嚴格) - MCP 生態系較小(經過測試的社群伺服器較少) - 提供 hooks 系統(v0.119.0+),但成熟度不如 Claude Code——事件類型較少,且沒有條件式 if 欄位

何時應在 iOS 開發中選擇 Codex 而非 Claude Code:

當您希望獲得模型多樣性時就選用 Codex——讓第二個 agent 審查第一個 agent 撰寫的程式碼,能發現不同類型的錯誤。collab workflow(Claude 負責建構,Codex 負責審查)在 iOS 開發中相當有效,因為某個模型家族看起來正確的 SwiftUI 模式,在另一個模型眼中可能潛藏微妙的問題。Metal shader 與並行處理模式特別能受益於雙模型審查。

3. Xcode 26.3 原生 Agents

簡介:Apple 將 AI 編碼 agent 直接整合進 Xcode 的 Intelligence 面板。從 Xcode 26.3 開始,您可以在 Xcode Settings > Intelligence 中將 Claude Agent 和 Codex 設定為智慧提供者。

設定方式:

  1. 開啟 Xcode 26.3+
  2. 前往 Settings > Intelligence
  3. 新增提供者:
  4. 若選 Claude:選擇「Claude Agent」,輸入您的 Anthropic API 金鑰
  5. 若選 Codex:選擇「Codex」,輸入您的 OpenAI API 金鑰
  6. Agent 會出現在 Intelligence 側邊欄,並可內嵌呼叫

最適合用於:快速的內嵌編輯、具備 agent 等級推理能力的程式碼補全,以及偏好不離開 Xcode 的開發者。原生整合代表 agent 可直接存取 Xcode 的專案脈絡——開啟的檔案、建置目標、scheme 設定——無需透過 MCP 橋接。

相較於 CLI agent 的限制: - 沒有 hook 系統——無法強制儲存時格式化或封鎖 .pbxproj 寫入 - 不會載入 CLAUDE.md——agent 不會讀取您的專案層級設定檔 - 自主性有限——agent 僅作用於當前檔案或選取範圍,無法跨整個專案運作 - 不支援 subagent 委派——複雜的多步驟任務無法並行處理 - 無法設定 MCP 伺服器——agent 僅能使用 Xcode 內建工具

何時應使用 Xcode 原生 agents:

當切換到終端機顯得太麻煩時,適合用於快速且範圍有限的編輯。「在這個 model 上新增一個 computed property。」「為這個 function 撰寫單元測試。」「將這個 view 重構為使用 @Observable。」這類僅涉及一兩個檔案、且不需要建置-測試循環的任務。

任何需要建置、測試、跨檔案重構或自主錯誤修正的工作,都應改用搭配 MCP 的 CLI agent。

執行環境比較表

能力 Claude Code CLI Codex CLI Xcode 26.3 Native
MCP 支援 完整(79 個工具) 完整(79 個工具) 僅內建 Xcode 工具
Hook 系統 有(成熟) 有(基礎,v0.119.0+)
CLAUDE.md / 專案設定 codex.md 對應檔
自主建置-測試-修復 有(透過 MCP) 有(透過 MCP) 部分(僅內嵌)
Subagent 委派 有(最多 10 個並行)
內容視窗 100 萬 tokens(Opus 4.6) 視模型而定 視提供者而定
多檔案操作 完整程式碼庫存取 完整程式碼庫存取 當前檔案 / 選取範圍
.pbxproj 保護 透過 hooks 手動 不適用(原生使用 Xcode)
儲存時格式化 透過 PostToolUse hooks 外部工具 Xcode 設定
離線能力
計費模式 Anthropic API 用量 OpenAI API 用量 提供者 API 用量

建議方案:將 Claude Code CLI 作為主要執行環境。Xcode 26.3 原生 agents 用於快速內嵌編輯。Codex CLI 則用於審查階段與批次作業。三者相輔相成,而非彼此競爭。


MCP設定:完整設定

MCP(Model Context Protocol)會把代理從「撰寫Swift,然後希望您自己建置」轉變成「撰寫Swift、執行建置、讀取結構化錯誤,並修正問題」。本節比部落格文章更深入,涵蓋兩種伺服器、所有安裝方式、驗證,以及確保代理確實使用工具的代理設定。

XcodeBuildMCP:用於無頭式iOS開發的59個工具

XcodeBuildMCPxcodebuildxcrun simctl和LLDB封裝成59個結構化MCP工具。不需要執行Xcode也能運作,整個建置、測試、偵錯循環都會透過Apple命令列工具以無頭式方式執行。

安裝選項:

# Option 1: Via npx (recommended — always uses latest version)
claude mcp add XcodeBuildMCP \
  -s user \
  -e XCODEBUILDMCP_SENTRY_DISABLED=true \
  -- npx -y xcodebuildmcp@latest mcp

# Option 2: Via Homebrew (pinned version, manual updates)
brew install xcodebuildmcp
claude mcp add XcodeBuildMCP \
  -s user \
  -e XCODEBUILDMCP_SENTRY_DISABLED=true \
  -- xcodebuildmcp mcp

# Option 3: Project-scoped (omit -s user)
claude mcp add XcodeBuildMCP \
  -e XCODEBUILDMCP_SENTRY_DISABLED=true \
  -- npx -y xcodebuildmcp@latest mcp

-s user旗標會讓伺服器在所有專案中全域可用。若要安裝在專案範圍內,請省略此旗標(適合只想在iOS專案使用MCP,而不是在網頁專案中使用的情境)。

-e XCODEBUILDMCP_SENTRY_DISABLED=true環境變數會停用當機報告遙測。XcodeBuildMCP預設包含Sentry,會傳送包含檔案路徑在內的錯誤資料。除非您想為專案提供診斷資料,否則建議退出。1

完整工具清單(8個類別,共59個工具):

類別 工具 功能
專案探索 discover_projslist_schemeslist_targets 尋找.xcodeproj/.xcworkspace檔案,列出可用的scheme與target
建置 build_simbuild_devicebuild_mac 以結構化JSON輸出建置錯誤與警告,並按檔案和行號分類
測試 test_simtest_device 執行測試,並回傳各方法的通過/失敗結果
模擬器生命週期 list_simsboot_simshutdown_simopen_simsession_set_defaults 建立、啟動、管理與設定模擬器
裝置管理 list_devicesinstall_devicelaunch_device 實體裝置部署與管理
偵錯 debug_attach_simdebug_attach_devicedebug_breakpointdebug_stackdebug_variablesdebug_evaldebug_continuedebug_stepdebug_detach 完整LLDB整合,支援中斷點與變數檢查
UI自動化 snapshot_uiscreenshottapswipetype_text 自動化互動與視覺擷取
專案腳手架 create_projectadd_fileadd_package 建立專案並加入相依套件

日常工作中最重要的工具:

  1. build_sim——您會呼叫它數百次。它會回傳JSON,並依檔案、行號與嚴重性分類錯誤。代理會讀取錯誤、前往該檔案,然後在您不需動手的情況下修正問題。

  2. test_sim——回傳各測試方法的結果。代理能精準知道哪個測試失敗以及原因,而不只是看到「測試失敗」。

  3. list_sims+boot_sim——不必記住xcrun simctl旗標也能管理模擬器。代理會探索可用的runtime,並選擇合適的裝置。

  4. discover_projs+list_schemes——專案自我檢查。代理不需要猜測您的scheme名稱或工作區結構。

  5. debug_attach_sim+debug_stack+debug_variables——遠端LLDB偵錯。代理可以設定中斷點、檢查變數,並逐步執行程式碼,而不需要您打開偵錯器。

Apple Xcode MCP:橋接到Xcode的20個工具

Apple的MCP伺服器隨Xcode 26.3透過xcrun mcpbridge提供。它會透過XPC(Apple的程序間通訊框架)與正在執行的Xcode程序通訊,公開任何CLI工具都無法存取的內部狀態。

安裝:

# Standard installation (global)
claude mcp add --transport stdio xcode \
  -s user -- xcrun mcpbridge

# For Codex CLI
codex mcp add xcode -- xcrun mcpbridge

需要Xcode 26.3以上版本,且Xcode程序必須正在執行。如果Xcode未開啟,透過此伺服器進行的每次MCP呼叫都會失敗或卡住。XcodeBuildMCP沒有這項限制。

工具清單(5個類別,共20個工具):

類別 工具 功能
檔案操作 XcodeReadXcodeWriteXcodeUpdateXcodeGlobXcodeGrep 在Xcode專案脈絡中讀寫檔案
建置與測試 BuildProjectGetBuildLogRunAllTestsRunSomeTests 使用Xcode內部建置系統進行建置與測試
診斷 XcodeListNavigatorIssuesXcodeRefreshCodeIssuesInFile 即時程式碼診斷(不只是建置錯誤)
程式碼與文件 ExecuteSnippetDocumentationSearch Swift REPL執行與Apple文件搜尋
預覽 RenderPreview 無頭式SwiftUI預覽渲染

Apple MCP獨有工具(XcodeBuildMCP未提供):

  1. DocumentationSearch——搜尋Apple開發者文件,包括WWDC場次。處理Apple API問題時,比網頁搜尋更快也更可靠。詢問「HKQuantityType(.dietaryWater)是否有效?」即可從來源取得明確答案。

  2. ExecuteSnippet——在專案脈絡中執行Swift REPL。代理可以驗證API行為、測試型別轉換,並在不建置完整App的情況下驗證運算式。

  3. RenderPreview——以無頭式方式渲染SwiftUI預覽。代理可以檢查view是否能無錯誤渲染,但無法評估視覺正確性(渲染結果會以資料形式回傳,而不是以視覺方式檢查)。

  4. XcodeListNavigatorIssues——回傳Xcode分析器的即時診斷,不只是建置錯誤。可抓出未使用變數、潛在retain cycle,以及建置系統不會顯示的棄用警告等問題。

為什麼需要兩種伺服器

它們在建置與測試上有所重疊,但本質上並不相同:

┌─────────────────────────────────────────────────────────────────┐
                     MCP TOOL COVERAGE                           
├─────────────────────────────────────────────────────────────────┤
                                                                 
  XcodeBuildMCP (59 tools)        Apple Xcode MCP (20 tools)    
  ┌─────────────────────┐         ┌─────────────────────┐       
   Standalone                     Requires Xcode             
   (no Xcode process)            (XPC bridge)               
                                                            
    Simulators          BOTH     Documentation            
    Real devices       ┌─────┐   Swift REPL               
    LLDB debugging     Build   SwiftUI previews         
    UI automation      Test    Live diagnostics         
    Project scaffold   └─────┘   Analyzer issues          
    Screenshot                                             
  └─────────────────────┘         └─────────────────────┘       
                                                                 
└─────────────────────────────────────────────────────────────────┘

使用XcodeBuildMCP處理:建置、測試、偵錯循環。它不需要開啟Xcode、消耗較少系統記憶體,並提供更完整的模擬器與裝置管理。這是您的主要建置工具。

使用Apple Xcode MCP處理:文件查詢、Swift REPL驗證、SwiftUI預覽渲染,以及即時診斷。需要這些能力的工作階段,請保持Xcode開啟。

實務上:我約90%的MCP呼叫會使用XcodeBuildMCP,Apple Xcode MCP則用於文件與REPL驗證。代理預設以XcodeBuildMCP進行建置與測試,因為它更快(沒有Xcode程序開銷)也更可靠(不依賴XPC)。

驗證

安裝兩種伺服器後,請確認它們已連線:

# List all configured MCP servers
claude mcp list

# Expected output includes:
# XcodeBuildMCP: npx -y xcodebuildmcp@latest mcp - Connected
# xcode: xcrun mcpbridge - Connected

如果伺服器顯示「Disconnected」或沒有出現:

  1. XcodeBuildMCP未連線:確認已安裝Node.js(node --version)。npx命令需要Node.js 18以上版本。
  2. Apple Xcode MCP未連線:確認已安裝Xcode 26.3以上版本,且xcrun mcpbridge命令可在終端機中運作。至少開啟一次Xcode以接受授權協議。
  3. 兩者都未出現:重新啟動Claude Code(在新終端機中執行claude)。工作階段中途註冊的MCP伺服器,可能要重新啟動後才會出現。

教代理使用MCP

安裝MCP伺服器是必要條件,但仍然不夠。若沒有明確指引,代理可能會退回使用Bash執行xcodebuild(非結構化輸出、浪費context token),或用網頁搜尋Apple文件(較慢且較不可靠)。

將以下內容加入您的CLAUDE.md或代理定義:

## Build & Test — Always Use MCP

Prefer MCP tools over raw shell commands for ALL build operations:

- **Build**: `build_sim` / `build_device` (NOT `xcodebuild` via Bash)
- **Test**: `test_sim` / `test_device` (NOT `xcodebuild test` via Bash)
- **Simulators**: `list_sims`, `boot_sim`, `open_sim` (NOT `xcrun simctl` via Bash)
- **Debug**: `debug_attach_sim`, `debug_stack`, `debug_variables`
- **Apple docs**: `DocumentationSearch` (NOT WebSearch for Apple APIs)
- **Swift verification**: `ExecuteSnippet` (NOT `swift` via Bash)
- **Previews**: `RenderPreview` for headless SwiftUI verification

MCP returns structured JSON. Bash returns unstructured text.
Structured data means fewer tokens consumed and better error diagnosis.

這項指引可確保代理優先使用MCP工具。若缺少它,您會看到代理透過Bash組出冗長的xcodebuild命令,耗費數千個context token解析輸出,有時還會誤判真正的錯誤。


iOS專案的CLAUDE.md模式

您的CLAUDE.md是專案中最重要的agent輔助開發檔案。它是agent的入職文件,也就是讀過架構文件的新進工程師,和只能憑空猜測的新進工程師之間的差別。

我維護的每個iOS專案都有CLAUDE.md。以下是從全部8個app歸納出的有效模式。

必要章節

每個iOS CLAUDE.md都需要這6個章節。其他內容都是選配。

1. 專案身分

# Return - Zen Focus Timer

**Bundle ID:** `com.941apps.Return`
**Target:** iOS 26+ / macOS Tahoe / watchOS 26+ / tvOS 26+
**Architecture:** SwiftUI with @Observable pattern, companion Watch and TV apps
**Swift version:** 6.2
**Minimum deployment:** iOS 26.0

這為什麼重要:agent在撰寫任何程式碼前,必須知道部署目標。以iOS 17為目標的agent會使用NavigationView@ObservedObject。以iOS 26為目標的agent則會使用NavigationStack@Observable。Bundle ID會影響entitlements與HealthKit設定。Swift版本會決定並行模型(async/await相對於completion handlers,以及strict concurrency相對於lenient)。

2. 帶有用途註解的檔案結構

## File Structure

```
Return/
├── ReturnApp.swift              # App entry, dark mode enforcement
├── ContentView.swift            # Main timer view with theme backgrounds
├── TimerManager.swift           # Timer state, logic, and repeat handling
├── AudioManager.swift           # Sound playback with AVAudioPlayer
├── Settings.swift               # Centralized settings with validation
├── SettingsSheet.swift          # Settings UI
├── HealthKitManager.swift       # Mindful session logging + cross-device sync
├── LiveActivityManager.swift    # Lock Screen/Dynamic Island
├── Theme.swift                  # Theme definitions
├── ThemeManager.swift           # Theme state management
├── VideoBackgroundView.swift    # AVPlayer video backgrounds
├── GlassTextShape.swift         # Core Text glyph paths for glass effect
├── GlassTimerText.swift         # Timer text with glass material
└── Constants.swift              # App constants
```

每個檔名後面的行內註解並非裝飾。這是您能撰寫的最高槓桿文件。當agent判斷新功能該加在哪裡時,這些註解會引導它第一次就找到正確檔案,而不是讀完每個檔案才理解專案配置。

反模式:只列檔案,不加註解。TimerManager.swift無法告訴agent它負責狀態、UI,或兩者皆是。TimerManager.swift # Timer state, logic, and repeat handling則清楚說明什麼該放在那裡,什麼不該放。

3. 建置與測試指令

## Build & Test

Build for iOS simulator:
```bash
xcodebuild -scheme Return -destination 'platform=iOS Simulator,name=iPhone 16 Pro' build
```

Run tests:
```bash
xcodebuild -scheme Return -destination 'platform=iOS Simulator,name=iPhone 16 Pro' test
```

Run tvOS tests:
```bash
xcodebuild -scheme ReturnTV -destination 'platform=tvOS Simulator,name=Apple TV' test
```

**Prefer MCP tools** (`build_sim`, `test_sim`) over these raw commands.
MCP returns structured JSON with categorized errors.

即使agent應優先使用MCP,仍要包含原始指令。原始指令可作為備援文件,並讓scheme名稱與destination一目了然。

4. 關鍵模式與規則

## Key Patterns

### Observable Architecture
- ALL view models use `@Observable` (NEVER `ObservableObject`)
- ALL navigation uses `NavigationStack` (NEVER `NavigationView`)
- State management via `@Observable` classes with `@MainActor` isolation

### Settings Pattern
- Centralized `Settings.shared` singleton
- All settings bounded to valid ranges with validation
- Sound names validated against whitelist
- Thread-safe access via @MainActor

### Audio System
- `AVAudioPlayer` with `.playback` category (plays in silent mode)
- Silent audio loop for background execution
- Bell playback with completion callbacks and token-based staleness

這些模式可防止agent引入不一致。若沒有明確的模式文件,agent有時會在某個檔案使用ObservableObject,另一個檔案使用@Observable;或是另外建立新的設定機制,而不是使用既有的Settings.sharedsingleton。

5. Agent絕對不可做的事

## Rules

- **NEVER modify .pbxproj files** — create Swift files, then I will add them to Xcode manually
- **NEVER modify .xcodeproj/ contents directly**
- **NEVER add new package dependencies** without asking first
- **NEVER change the deployment target**
- **NEVER modify entitlements files** unless explicitly asked
- **NEVER use NavigationView** — always NavigationStack
- **NEVER use ObservableObject** — always @Observable
- **NEVER use @StateObject** — always @State with @Observable

明確禁止比隱含期待更有效。agent遵守負向限制通常比正向建議更可靠,因為負向限制是二元的(做/不做),而不是啟發式的(優先使用這個/有時使用那個)。

6. 框架特定脈絡

此章節會依app而異。任何有非顯而易見設定的框架都應納入:

HealthKit apps:

## HealthKit Configuration

- Entitlement: `com.apple.developer.healthkit`
- Info.plist keys:
  - `NSHealthShareUsageDescription`: "Return reads your mindful minutes..."
  - `NSHealthUpdateUsageDescription`: "Return logs meditation sessions..."
- Category types: `HKCategoryType(.mindfulSession)`
- Authorization checked on every write (user can revoke at any time)
- HealthKit is unavailable on tvOS — guard with `#if canImport(HealthKit)`

SwiftData apps:

## SwiftData Models

### Model Relationships
- `GroceryList` has many `GroceryItem` (cascade delete)
- `GroceryItem` belongs to one `GroceryList`
- `GroceryItem` has optional `Category`

### Model Container Setup
- Configured in App struct with `modelContainer(for:)`
- Schema versioning: currently V2
- Migration plan: `GroceryMigrationPlan` handles V1 → V2

### Queries
- `@Query(sort: \GroceryItem.name)` for sorted fetches
- `@Query(filter: #Predicate { !$0.isCompleted })` for active items
- Always use `@Query` in views, `modelContext.fetch()` in managers

SpriteKit apps:

## SpriteKit Scene Hierarchy

```
GameScene (SKScene)
├── backgroundLayer (SKNode, zPosition: -100)
│   └── StarfieldNode (custom, parallax scrolling)
├── gameLayer (SKNode, zPosition: 0)
│   ├── playerShip (PlayerNode, zPosition: 10)
│   ├── enemyContainer (SKNode, zPosition: 5)
│   └── bulletPool (SKNode, zPosition: 8)
├── effectsLayer (SKNode, zPosition: 50)
│   └── ParticleManager (manages explosion/trail emitters)
└── hudLayer (SKNode, zPosition: 100)
    ├── scoreLabel (SKLabelNode)
    └── healthBar (HealthBarNode)
```

- Physics categories defined in `PhysicsCategory.swift` as bitmasks
- Contact detection via `didBegin(_ contact:)` on GameScene
- Bullet pooling: pre-allocate 50, recycle via `removeFromParent()` + re-add

Metal apps:

## Metal Pipeline

- Render pipeline: `MetalView``Renderer``ShaderLibrary`
- Compute pipeline: `AudioAnalyzer` → compute shader → texture output
- Shared uniforms struct: `Uniforms` in `ShaderTypes.h` (bridged to Swift)
- Frame timing: `CADisplayLink` drives render loop
- Buffer triple-buffering: 3 in-flight frames with semaphore

### Shader Files
- `Shaders.metal` — Main render shaders (vertex + fragment)
- `Compute.metal` — Audio analysis compute kernel
- `PostProcess.metal` — Bloom and color grading

### DO NOT modify Metal shaders without testing on device.
Simulator Metal is not representative of device GPU behavior.

真實CLAUDE.md:Banana List(SwiftUI + SwiftData + iCloud + MCP Server)

以下是一個帶註解的範例,展示這6個章節如何在中等複雜度的app中相互搭配。這是我用於Banana List的CLAUDE.md模式;它是一個有53個檔案的購物清單app,具備iCloud同步,以及自訂MCPserver,可將app資料公開給ClaudeDesktop:

# Banana List - Grocery List App

**Bundle ID:** `com.941apps.BananaList`
**Target:** iOS 26+
**Architecture:** SwiftUI + SwiftData + iCloud Drive sync
**Swift version:** 6.2
**Minimum deployment:** iOS 26.0

## Core Features

- Grocery lists with items, categories, and quantities
- iCloud Drive sync via SwiftData CloudKit integration
- Custom MCP server exposing list data to Claude Desktop
- Liquid Glass design system
- Haptic feedback on interactions
- Share sheets for list sharing

## File Structure

```
BananaList/
├── BananaListApp.swift           # App entry, model container setup
├── Models/
│   ├── GroceryList.swift         # @Model: list with name, items, color
│   ├── GroceryItem.swift         # @Model: item with name, quantity, category, isCompleted
│   ├── Category.swift            # @Model: user-defined categories
│   └── SampleData.swift          # Preview and test data
├── Views/
│   ├── ListsView.swift           # Main list of grocery lists
│   ├── ListDetailView.swift      # Items within a list
│   ├── ItemRow.swift             # Single item row with swipe actions
│   ├── AddItemSheet.swift        # New item form
│   ├── CategoryPicker.swift      # Category selection with create-new
│   └── SettingsView.swift        # App settings
├── Managers/
│   ├── CloudSyncManager.swift    # iCloud Drive sync status and conflict resolution
│   └── HapticManager.swift       # UIImpactFeedbackGenerator wrapper
├── MCP/
│   ├── MCPServer.swift           # MCP server for Claude Desktop integration
│   ├── ListTools.swift           # MCP tools: list CRUD operations
│   └── ItemTools.swift           # MCP tools: item CRUD operations
└── Extensions/
    ├── Color+Extensions.swift    # Custom color definitions
    └── View+Extensions.swift     # Reusable view modifiers
```

## SwiftData Models

### Relationships
- `GroceryList` has many `GroceryItem` (cascade delete)
- `GroceryItem` belongs to one `GroceryList` (required)
- `GroceryItem` has optional `Category`
- `Category` has many `GroceryItem` (nullify on delete)

### Container Setup
```swift
@main
struct BananaListApp: App {
    var body: some Scene {
        WindowGroup {
            ListsView()
        }
        .modelContainer(for: [GroceryList.self, GroceryItem.self, Category.self])
    }
}
```

### Query Patterns
- Lists: `@Query(sort: \GroceryList.name) var lists: [GroceryList]`
- Active items: `@Query(filter: #Predicate { !$0.isCompleted })`
- By category: filter in-memory after fetch (SwiftData predicate limitations)

## Build & Test

```bash
xcodebuild -scheme BananaList -destination 'platform=iOS Simulator,name=iPhone 16 Pro' build
xcodebuild -scheme BananaList -destination 'platform=iOS Simulator,name=iPhone 16 Pro' test
```

Prefer MCP tools (`build_sim`, `test_sim`) over raw commands.

## Key Patterns

### Observable + SwiftData
- SwiftData `@Model` classes are automatically Observable
- DO NOT add `@Observable` to `@Model` classes (redundant, causes warnings)
- Use `@Bindable` for two-way bindings to model properties in forms
- Use `@Query` in views, `modelContext.fetch()` in non-view code

### iCloud Sync
- Automatic via SwiftData CloudKit integration
- Conflict resolution: last-write-wins (CloudKit default)
- Sync status exposed via `CloudSyncManager.shared.syncState`
- Test sync by running on two simulators with same iCloud account

### MCP Server Architecture
- Runs as a local WebSocket server on port 8765
- Exposes 6 tools: listAll, getList, createList, addItem, completeItem, deleteItem
- Claude Desktop connects via MCP config in `~/.config/claude-desktop/config.json`

## Rules

- NEVER modify .pbxproj or .xcodeproj contents
- NEVER change the model schema without updating SampleData.swift
- NEVER use `ObservableObject` — SwiftData models are already Observable
- NEVER use `@StateObject` — use `@State` with `@Observable` classes
- NEVER use `NavigationView` — always `NavigationStack`
- NEVER add `@Observable` macro to `@Model` classes
- ALWAYS use `@Bindable` for form bindings to model properties
- ALWAYS test iCloud sync changes on two simulator instances

真實CLAUDE.md:Reps(極簡SwiftData App,14個檔案)

對小型專案而言,CLAUDE.md可以很精簡。以下是Reps這個14個檔案的健身訓練追蹤器模式。請注意,即使是簡短的CLAUDE.md,也涵蓋了全部6個必要章節:

# Reps - Workout Tracking

**Bundle ID:** `com.941apps.Reps`
**Target:** iOS 26+
**Architecture:** SwiftUI + SwiftData
**Swift version:** 6.2

## File Structure

```
Reps/
├── RepsApp.swift              # App entry, model container
├── Models/
│   ├── Workout.swift          # @Model: workout with exercises, date, duration
│   ├── Exercise.swift         # @Model: exercise with sets, reps, weight
│   └── ExerciseTemplate.swift # @Model: saved exercise definitions
├── Views/
│   ├── WorkoutListView.swift  # Main list of workouts
│   ├── WorkoutDetailView.swift # Exercises within a workout
│   ├── ExerciseRow.swift      # Single exercise with inline editing
│   ├── AddExerciseSheet.swift # Exercise selection from templates
│   ├── NewWorkoutView.swift   # Start new workout flow
│   └── StatsView.swift        # Progress charts and summaries
├── Managers/
│   └── WorkoutTimer.swift     # Active workout timer
└── Extensions/
    └── Date+Extensions.swift  # Formatting helpers
```

## Build & Test

```bash
xcodebuild -scheme Reps -destination 'platform=iOS Simulator,name=iPhone 16 Pro' build
xcodebuild -scheme Reps -destination 'platform=iOS Simulator,name=iPhone 16 Pro' test
```

## SwiftData Relationships

- `Workout` has many `Exercise` (cascade delete)
- `Exercise` has optional `ExerciseTemplate`
- `ExerciseTemplate` standalone (nullify on exercise delete)

## Rules

- NEVER modify .pbxproj
- NEVER use ObservableObject — use @Observable
- NEVER use NavigationView — use NavigationStack
- @Model classes are already Observable — do not add @Observable macro
- Use @Bindable for form bindings to model properties

這是一個14個檔案專案的40行CLAUDE.md。只需10分鐘撰寫,卻能省下數小時的agent困惑。

真實CLAUDE.md:Starfield Destroyer(SpriteKit + Metal,32個檔案)

遊戲專案需要更多框架特定脈絡。agent必須理解場景圖、physics categories,以及遊戲狀態機:

# Starfield Destroyer - Space Shooter

**Bundle ID:** `com.941apps.StarfieldDestroyer`
**Target:** iOS 26+
**Architecture:** SpriteKit + Metal post-processing + Game Center
**Swift version:** 6.2

## Game Overview

99 levels across 3 galaxies. 8 unlockable ships with different stats.
Game Center leaderboards and achievements. Metal shader post-processing
for bloom and screen effects.

## File Structure

```
StarfieldDestroyer/
├── StarfieldDestroyerApp.swift    # App entry, Game Center auth
├── GameScene.swift                # Main game scene, update loop
├── MenuScene.swift                # Title screen, ship selection
├── Entities/
│   ├── PlayerShip.swift           # Player node with physics, weapons, shields
│   ├── EnemyShip.swift            # Enemy base class with AI behaviors
│   ├── Bullet.swift               # Bullet pool node
│   ├── PowerUp.swift              # Collectible power-ups
│   └── Boss.swift                 # Boss enemies (levels 33, 66, 99)
├── Systems/
│   ├── LevelManager.swift         # Level progression, wave spawning
│   ├── PhysicsCategory.swift      # UInt32 bitmask categories
│   ├── CollisionHandler.swift     # Contact delegate methods
│   ├── ScoreManager.swift         # Score tracking, multipliers
│   ├── ParticleManager.swift      # Explosion, trail, shield emitters
│   └── AudioManager.swift         # Sound effects, background music
├── UI/
│   ├── HUDNode.swift              # Score, health, level display
│   ├── ShipSelectView.swift       # SwiftUI ship selection (UIHostingController)
│   ├── GameOverView.swift         # Game over screen with score submission
│   └── PauseMenu.swift            # Pause overlay
├── Metal/
│   ├── MetalRenderer.swift        # Post-processing render pipeline
│   ├── BloomShader.metal          # Bloom post-process effect
│   └── ShaderTypes.h              # Shared uniforms (bridging header)
├── Data/
│   ├── ShipData.swift             # 8 ship definitions (speed, damage, shields)
│   ├── LevelData.swift            # 99 level configurations
│   └── AchievementData.swift      # Game Center achievement definitions
└── GameCenterManager.swift        # Leaderboard/achievement submission
```

## SpriteKit Scene Hierarchy

```
GameScene (SKScene)
├── backgroundLayer (zPosition: -100)
│   └── StarfieldNode (parallax scrolling, 3 layers)
├── gameLayer (zPosition: 0)
│   ├── playerShip (zPosition: 10)
│   ├── enemyContainer (zPosition: 5)
│   ├── bulletPool (zPosition: 8) — pre-allocated 50 bullets
│   └── powerUpContainer (zPosition: 3)
├── effectsLayer (zPosition: 50)
│   └── ParticleManager (explosion + trail emitters)
└── hudLayer (zPosition: 100)
    ├── scoreLabel (SKLabelNode)
    ├── healthBar (custom SKShapeNode)
    └── levelLabel (SKLabelNode)
```

## Physics Categories

```swift
struct PhysicsCategory {
    static let none:      UInt32 = 0
    static let player:    UInt32 = 0b1        // 1
    static let enemy:     UInt32 = 0b10       // 2
    static let bullet:    UInt32 = 0b100      // 4
    static let powerUp:   UInt32 = 0b1000     // 8
    static let shield:    UInt32 = 0b10000    // 16
    static let bossBullet:UInt32 = 0b100000   // 32
}

// Contact pairs:
// player + enemy → damage
// player + powerUp → collect
// bullet + enemy → destroy
// player + bossBullet → damage
```

## Game State Machine

```
.menu → .playing → .paused → .playing
                 → .gameOver → .menu
                 → .bossIntro → .playing
                 → .levelComplete → .playing (next level)
```

## Metal Post-Processing

- Bloom shader: `BloomShader.metal` — multi-pass Gaussian blur + additive blend
- Uniforms: `PostProcessUniforms { float intensity; float threshold; float2 resolution; }`
- Applied after SpriteKit renders each frame via `SKView.presentScene(:transition:)`
- DO NOT modify Metal shaders without testing on device

## Build & Test

```bash
xcodebuild -scheme StarfieldDestroyer -destination 'platform=iOS Simulator,name=iPhone 16 Pro' build
xcodebuild -scheme StarfieldDestroyer -destination 'platform=iOS Simulator,name=iPhone 16 Pro' test
```

## Rules

- NEVER modify .pbxproj
- NEVER modify PhysicsCategory bitmasks (breaks all collision detection)
- NEVER change the scene hierarchy z-ordering without understanding render order
- NEVER modify ShaderTypes.h without updating both Swift and Metal references
- Add new enemies by subclassing EnemyShip, not by modifying it
- Bullet pooling: recycle via removeFromParent() + re-add, never allocate new
- Game Center: always check isAuthenticated before submitting scores

真實CLAUDE.md:amp97(Metal + 音訊視覺化,41個檔案)

Metal專案最需要框架特定脈絡,因為agent無法驗證視覺輸出:

# amp97 - Audio Visualizer

**Bundle ID:** `com.941apps.amp97`
**Target:** iOS 26+
**Architecture:** Metal render pipeline + AVAudioEngine analysis
**Swift version:** 6.2

## Architecture

```
Audio Input (microphone/file)
    → AVAudioEngine tap
    → FFT (vDSP)
    → Frequency/amplitude buffers
    → Metal compute shader (analysis)
    → Metal render pipeline (visualization)
    → CADisplayLink (60fps)
    → MTKView
```

## File Structure

```
amp97/
├── amp97App.swift               # App entry
├── Audio/
│   ├── AudioEngine.swift        # AVAudioEngine setup, tap installation
│   ├── FFTProcessor.swift       # vDSP FFT, frequency bin extraction
│   ├── AudioBuffer.swift        # Ring buffer for audio data
│   └── MicrophoneManager.swift  # Microphone permission, session config
├── Rendering/
│   ├── MetalView.swift          # MTKView wrapper for SwiftUI
│   ├── Renderer.swift           # Main render loop, pipeline state
│   ├── ShaderLibrary.swift      # Compiled shader management
│   ├── BufferManager.swift      # Triple-buffered uniform updates
│   └── TextureManager.swift     # Offscreen render targets
├── Shaders/
│   ├── Shaders.metal            # Vertex + fragment shaders
│   ├── AudioCompute.metal       # Audio analysis compute kernel
│   ├── PostProcess.metal        # Bloom, color grading
│   └── ShaderTypes.h            # Shared uniforms (bridging header)
├── Visualizations/
│   ├── WaveformViz.swift        # Oscilloscope-style waveform
│   ├── SpectrumViz.swift        # Frequency spectrum bars
│   ├── CircularViz.swift        # Radial visualization
│   └── VizSelector.swift        # Visualization switching
├── Views/
│   ├── MainView.swift           # Full-screen viz with overlays
│   ├── ControlsOverlay.swift    # Play/pause, viz selection, gain
│   └── SettingsView.swift       # Audio source, sensitivity
└── Extensions/
    ├── SIMD+Extensions.swift    # Vector math helpers
    └── Color+Metal.swift        # UIColor → float4 conversion
```

## Metal Pipeline

### Uniforms (ShaderTypes.h)
```c
typedef struct {
    float time;
    float2 resolution;
    float audioLevel;       // 0.0-1.0 RMS amplitude
    float frequencyBins[64]; // FFT output, normalized
    float4x4 transform;
} Uniforms;
```

### Render Pipeline
1. Compute pass: AudioCompute.metal processes FFT data → texture
2. Render pass: Shaders.metal reads texture + uniforms → visualization
3. Post-process pass: PostProcess.metal applies bloom → final output

### Buffer Management
- Triple buffering with DispatchSemaphore(value: 3)
- Uniforms updated per-frame on CPU, consumed by GPU 1-2 frames later
- Audio data ring buffer: 4096 samples, lock-free single producer/consumer

## Rules

- NEVER modify ShaderTypes.h without updating BOTH Swift and Metal sides
- NEVER exceed 64 frequency bins (fixed buffer size in shader)
- NEVER test Metal visual output in simulator — device only
- NEVER modify the audio engine tap format (48kHz, mono, float32)
- Triple buffer discipline: always signal semaphore in completion handler
- Audio session: .playAndRecord category with .defaultToSpeaker option

依專案規模擴充CLAUDE.md

合適的詳細程度取決於檔案數量與框架複雜度:

專案規模 CLAUDE.md深度 範例
小型(<20個檔案) 身分+檔案清單+規則 Reps(14個檔案):基本SwiftData模式、建置指令、禁止事項
中型(20-40個檔案) +框架脈絡+關鍵模式 TappyColor(30個檔案):SpriteKit場景階層、physics categories、game loop
大型(40個以上檔案) +架構圖+關係圖+多target資訊 Return(63個檔案):跨平台架構、session同步圖、各平台差異
專門領域(Metal/GPU) +pipeline圖+共用型別定義+buffer layout amp97(41個檔案):render pipeline階段、uniform struct、buffer管理

過度文件化的成本幾乎為零(agent會略過不需要的內容)。文件不足的成本則很高(agent會自行創造與您程式碼庫衝突的模式)。

CLAUDE.md檢查清單

建立或稽核iOS專案的CLAUDE.md時,請使用這份檢查清單:

  • [ ] 已指定Bundle ID與部署目標
  • [ ] 已標明Swift版本與架構模式
  • [ ] 檔案結構含行內用途註解
  • [ ] 建置指令含正確scheme與destination
  • [ ] 測試指令含正確scheme與destination
  • [ ] 已註明MCP偏好(「prefer build_sim over xcodebuild」)
  • [ ] @Observable規則(絕不使用ObservableObject)
  • [ ] NavigationStack規則(絕不使用NavigationView)
  • [ ] .pbxproj禁止事項
  • [ ] 框架特定脈絡(HealthKit權限、SwiftData關係、SpriteKit階層、Metal pipeline)
  • [ ] 已記錄平台可用性guard(#if canImport、#if os)
  • [ ] 已記錄關鍵singleton與共用模式
  • [ ] 已註明已知限制或注意事項

您的第一個代理程式工作階段

在專案中設定好MCP並放入CLAUDE.md後,以下是一次有效初始工作階段的流程示範。此處使用Claude Code CLI,但此工作流程適用於任何執行階段。

步驟1:確認代理程式能看見您的專案

You: Summarize this project. What scheme should I build with?

Claude: [reads CLAUDE.md]
        [calls discover_projs via MCP]
        [calls list_schemes via MCP]

        This is Return, a zen meditation timer for iOS 26+, watchOS, and tvOS.
        Available schemes: Return, ReturnWatch, ReturnTV, ReturnTests.
        Primary scheme for iOS: Return.

如果代理程式沒有引用您的CLAUDE.md內容,請確認該檔案位於專案根目錄(也就是與.xcodeprojPackage.swift相同的目錄)。

步驟2:執行健康檢查建置

You: Build the Return scheme for iOS simulator and report results.

Claude: [calls list_sims — finds iPhone 16 Pro on iOS 26.2]
        [calls boot_sim — boots the simulator]
        [calls build_sim — builds the project]

        Build succeeded. 63 source files compiled.
        2 warnings:
        - HomeView.swift:132 — UIScreen.main deprecated in iOS 26.0
        - LogWaterIntent.swift:61 — Result of try? is unused
        0 errors.

步驟3:執行測試

You: Run all tests and report pass/fail.

Claude: [calls test_sim]

        12 tests executed:
         TimerManagerTests (5/5 passed)
         SettingsTests (4/4 passed)
         ConstantsTests (3/3 passed)
        All tests passed.

步驟4:實作功能

You: Add a new "Rain" theme to the theme system. Follow the existing
     pattern in Theme.swift and ThemeManager.swift. Include a rain
     ambient sound. Build and test after implementation.

Claude: [reads Theme.swift  understands Theme struct pattern]
        [reads ThemeManager.swift  understands theme registration]
        [reads existing theme definitions]
        [adds Rain theme to Theme.swift following existing pattern]
        [registers Rain theme in ThemeManager.swift]
        [calls build_sim  build succeeds]
        [calls test_sim  all tests pass]

        Added Rain theme:
        - Theme.swift: new `static let rain` with video, cover, ambient
        - ThemeManager.swift: added to `allThemes` array
        - Build: success (0 errors, 2 existing warnings)
        - Tests: 12/12 passed

        Note: You'll need to add rain_ambient.wav to the project
        and add the new Theme.swift changes to the Xcode target manually
        (I did not modify .pbxproj).

代理程式提到不要修改.pbxproj,是因為CLAUDE.md中的規則。若沒有這條規則,代理程式會嘗試修改專案檔案,而且很可能造成損毀。


代理程式在iOS中擅長的工作

以下是代理程式能穩定產出正確、可投入生產環境成果的工作類型,通常只需要極少人工審查。

SwiftUI Views與Modifiers

代理程式對SwiftUI宣告式語法具備深度模式辨識能力。View組合、modifier鏈、狀態繫結與版面配置,都很適合代理程式的訓練資料,因為SwiftUI的API介面有完整文件,且模式高度一致。

代理程式擅長的項目: - 根據描述建立新的views(「建立一個settings sheet,包含X、Y、Z的toggles」) - 套用modifier鏈(.glassEffect().sensoryFeedback().navigationTitle()) - 在版面配置模式之間轉換(VStack轉為LazyVGrid、List轉為ScrollView) - 實作@Bindable表單繫結到SwiftData models - 使用範例資料建立preview providers

能產出優異結果的範例提示:

Create a SettingsView that matches the existing pattern in SettingsSheet.swift.
Include toggles for:
- Enable haptic feedback (Settings.shared.hapticsEnabled)
- Enable HealthKit logging (Settings.shared.healthKitEnabled)
- Show session history (navigation link to SessionHistoryView)

Use Liquid Glass styling with .glassEffect() on section backgrounds.
Follow the @Observable pattern, not ObservableObject.

具體程度很重要。「Create a settings view」會產生泛用結果。「Create a SettingsView that matches the existing pattern in SettingsSheet.swift」則會產生與您的程式碼庫一致的輸出。

SwiftData Models與Queries

代理程式能可靠處理SwiftData的@Modelmacro、relationships與@Query模式。此框架的宣告式特性(類似Django ORM或SQLAlchemy)很容易對應到代理程式在許多程式碼庫中看過的模式。

代理程式擅長的項目: - 定義含有relationships的@Modelclasses - 使用sort descriptors與predicates撰寫@Query - 透過modelContext實作CRUD操作 - 規劃schema版本之間的migration - 建立preview資料與test fixtures

代理程式需要指引的項目: - 複雜的#Predicateexpressions(SwiftData的predicate DSL有限制,代理程式不一定總是知道;建議在CLAUDE.md中記錄已知限制) - CloudKit同步設定(可由SwiftData自動處理,但代理程式可能會嘗試實作手動同步)

Unit Tests

代理程式為iOS專案撰寫的unit tests一向品質很高。代理程式理解XCTest模式、async測試方法,以及setup/teardown生命週期。

Write unit tests for TimerManager covering:
1. Initial state is .stopped
2. start() transitions to .running
3. pause() transitions to .paused
4. reset() returns to .stopped with original duration
5. Timer counts down correctly (test with 3-second duration)

代理程式會產出結構良好的XCTest案例,包含setUp()tearDown()、適當的assertions,以及針對timer-based tests的async處理。

重構與模式套用

代理程式擅長機械式重構:將views抽出成components、將ObservableObject轉換為@Observable、從NavigationView遷移到NavigationStack,並在多個檔案中套用一致模式。

Refactor all views in the Views/ directory to use @Observable instead of
ObservableObject. Update @StateObject to @State, @ObservedObject to direct
property access, and @Published to plain properties.

代理程式會有條不紊地逐一處理每個檔案,正確套用轉換,並維持既有功能。這是高槓桿工作:原本需要1小時手動編輯的重構,能在數分鐘內以近乎完美的準確度完成。

透過MCP診斷建置錯誤

有了結構化的MCP輸出,代理程式診斷建置錯誤的速度比大多數開發者更快。代理程式會讀取錯誤JSON、找出確切檔案與行號、理解錯誤訊息,並套用修正;通常一輪就能完成。

代理程式可自主修復的錯誤: - 缺少imports - 型別不相符 - Protocol conformance缺口 - 已棄用的API用法(並替換為新寫法) - 缺少必要的initializer參數 - 存取控制違規

代理程式需要協助的錯誤: - 模稜兩可的型別解析(多個modules定義了相同型別) - 複雜的generic constraint失敗 - Macro expansion錯誤(代理程式無法看見展開後的macro輸出)

Simulator管理

代理程式能透過MCP妥善處理simulator生命週期:

Boot an iPhone 16 Pro simulator on iOS 26, install the app, and take a screenshot.

代理程式會呼叫list_sims尋找可用的runtimes,呼叫boot_sim啟動simulator,呼叫build_sim進行建置與安裝,並呼叫screenshot擷取畫面;全部都透過結構化的MCP呼叫完成。

Agent在iOS中表現不佳的地方

誠實盤點agent容易失敗之處。了解這些界線,才能避免挫折與浪費tokens。

.pbxproj檔案修改——絕對不要

這是iOS agent開發中最重要的一條規則。.pbxproj檔案是Xcode的專案設定,也就是一個結構化文字檔,包含UUID參照、建置階段清單與target成員資格。名義上可供人類閱讀,但對AI agents而言,實務上幾乎無法解析。

為什麼agent會在.pbxproj失敗: - 這個檔案使用自訂格式(不是JSON、不是YAML、也不是XML),而且位置具有意義 - 每個項目都透過UUID交叉參照;新增一個檔案需要一致地更新3到5個不同區段 - 只要一個字元放錯位置,就會毀損整個專案檔案 - Xcode對.pbxproj的merge conflict解析本來就很脆弱;agent編輯只會讓情況更糟

當agent編輯.pbxproj時會發生什麼: 1. 編輯看似成功(agent回報「檔案已更新」) 2. Xcode拒絕開啟專案(「專案檔案已毀損」) 3. 您花15到60分鐘從git歷史中復原 4. 您學會加入PreToolUse hook(請參閱Hooks

工作流程:agent建立Swift檔案。您手動將它們加入Xcode專案(拖進Xcode,或使用File > Add Files)。每個檔案只要5秒,卻能避免數小時的復原工作。

對Swift Package Manager專案而言:這項限制較不嚴重。Package.swift是標準Swift檔案,agent可以可靠地編輯。如果您的專案只使用SPM(沒有.xcodeproj),agent就能管理完整的專案結構。

複雜的Interface Builder/Storyboard編輯

如果您的專案使用Interface Builder(.xib檔案)或Storyboards(.storyboard檔案),agent無法有意義地編輯它們。這些是XML檔案,包含自動產生的UUID、constraint參照與outlet連線,設計目的在於視覺化編輯,而不是文字編輯。

緩解方式:新view一律使用SwiftUI。如果專案中有舊版Interface Builder檔案,保持原狀,並用SwiftUI建置新的UI。

效能最佳化

Agent會寫出正確的程式碼,但不一定是高效能的程式碼。它們無法profile您的app、找出瓶頸,或測量影格率。效能最佳化需要:

  1. Instruments profiling(視覺化工具,agent無法存取)
  2. 理解特定裝置的GPU/CPU特性
  3. 以測量為依據,反覆調整

常見情境: - Metal shader最佳化(agent會寫出有效的Metal,但無法測量GPU影格時間) - SwiftUI view body複雜度(agent會建立深度巢狀view,造成重繪負擔) - Core Data/SwiftData fetch最佳化(agent會寫出正確查詢,但在大型資料集上可能很慢)

緩解方式:用agent進行實作,手動透過Instruments profile,然後請agent套用您已確認的特定最佳化。

Code Signing與Provisioning

除了讀取錯誤訊息之外,agent無法偵錯code signing問題。Provisioning profile管理、憑證建立、entitlement設定與App Store提交,本質上都是由人操作的工作流程,牽涉Apple Developer portal、Keychain Access,以及Xcode的signing UI。

agent看得到什麼:「Signing for ‘Return’ requires a development team.」

agent看不到什麼:您的憑證是否過期、provisioning profile是否包含該裝置、bundle ID是否符合App ID,或entitlements檔案是否正確。

緩解方式:所有signing都在Xcode的Signing & Capabilities分頁處理。不要要求agent偵錯signing失敗。

複雜的Metal Shader偵錯

Agent會寫出語法正確的Metal Shading Language(MSL),但無法驗證視覺輸出,也無法偵錯GPU端問題。Metal shaders在GPU上執行;agent沒有回饋機制能判斷shader是否產生正確的視覺結果。

agent可以用Metal做什麼: - 根據描述撰寫vertex與fragment shaders - 在Swift中設定Metal render pipeline - 為資料平行運算建立compute shaders - 修正.metal檔案中的編譯錯誤

agent無法用Metal做什麼: - 驗證shader輸出的視覺正確性 - 偵錯GPU效能(影格時間、occupancy、記憶體頻寬) - 診斷視覺瑕疵(banding、精度問題、錯誤色彩空間) - 在不同GPU架構上測試(A-series與M-series的行為差異)

緩解方式:在實體裝置上測試Metal shaders。Simulator的Metal實作無法代表裝置上的GPU行為。使用Xcode的GPU Frame Capture進行視覺偵錯。

視覺版面驗證

Agent看不到app的UI。它們會撰寫SwiftUI版面程式碼,也能確認程式碼可編譯,但無法判斷結果畫面是否正確。某個view如果偏離中心10像素、字重錯誤,或元素互相重疊,不會產生build error,也會通過所有邏輯測試。

緩解方式:以視覺方式檢查UI變更。使用Xcode中的SwiftUI Previews(或透過Apple MCP使用RenderPreview進行headless rendering)驗證版面。也可以考慮使用swift-snapshot-testing等函式庫進行snapshot testing,以自動偵測視覺回歸。


iOS開發的Hooks

Hooks是在代理程式工作流程中特定時間點,會以確定方式執行的shell命令。它們是強制執行機制,也就是「請不要編輯.pbxproj」(代理程式可能忽略的建議)與「您不能編輯.pbxproj」(硬性封鎖)之間的差異。

如需hook系統的背景資訊,請參閱Claude Code hooks指南。本節涵蓋iOS專用的hook模式。

PreToolUse:封鎖.pbxproj寫入

這是任何iOS專案中最重要的hook。它會阻止代理程式寫入.pbxproj檔案、.xcodeproj/目錄,以及其他由Xcode管理的檔案:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "bash -c 'INPUT=$(cat); FP=$(echo \"$INPUT\" | jq -r \".tool_input.file_path // empty\"); if echo \"$FP\" | grep -qE \"\\.(pbxproj|xcworkspace|xib|storyboard)$|xcodeproj/|xcworkspace/\"; then echo \"BLOCKED: Do not modify Xcode project files. Create Swift files and add to Xcode manually.\" >&2; exit 2; fi'"
      }
    ]
  }
}

請將它放在專案根目錄的.claude/settings.json,或放在~/.claude/settings.json以取得全域保護。

運作方式:當代理程式嘗試對任何符合模式的檔案使用Edit或Write工具時,hook會執行、偵測檔案路徑、將警告列印到stderr,並以程式碼2結束(這會封鎖工具使用)。代理程式會收到錯誤訊息,並調整做法。

它會攔截: - 直接編輯.pbxproj - .xcodeproj/.xcworkspace/目錄中的任何檔案 - Interface Builder檔案(.xib.storyboard

PostToolUse:使用SwiftFormat進行儲存時格式化

每當代理程式寫入或編輯Swift檔案時,自動格式化:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "bash -c 'INPUT=$(cat); FP=$(echo \"$INPUT\" | jq -r \".tool_input.file_path // empty\"); if echo \"$FP\" | grep -qE \"\\.swift$\"; then swiftformat \"$FP\" --quiet 2>/dev/null; fi'"
      }
    ]
  }
}

需求:必須安裝SwiftFormat(brew install swiftformat)。

為什麼重要:代理程式會產生語法正確的Swift,但不一定能一致遵循格式慣例。SwiftFormat會標準化縮排、大括號位置與import排序。儲存時格式化hook代表代理程式碰過的每個Swift檔案,在您看到之前都會自動完成格式化。

選用:在專案根目錄加入.swiftformat設定檔,以自訂格式化規則:

# .swiftformat
--indent 4
--allman false
--stripunusedargs closure-only
--importgrouping testable-bottom
--header strip

PostToolUse:自動執行SwiftLint

如果您使用SwiftLint,請在每次編輯Swift檔案後執行:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "bash -c 'INPUT=$(cat); FP=$(echo \"$INPUT\" | jq -r \".tool_input.file_path // empty\"); if echo \"$FP\" | grep -qE \"\\.swift$\"; then swiftlint lint --path \"$FP\" --quiet 2>/dev/null || true; fi'"
      }
    ]
  }
}

|| true會避免lint警告封鎖代理程式。如果希望lint違規時封鎖,請移除它。

PostToolUse:變更後自動建置

若要建立更積極的回饋循環,可在每次Swift檔案變更後觸發建置:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "bash -c 'INPUT=$(cat); FP=$(echo \"$INPUT\" | jq -r \".tool_input.file_path // empty\"); if echo \"$FP\" | grep -qE \"\\.swift$\"; then xcodebuild -scheme Return -destination \"platform=iOS Simulator,name=iPhone 16 Pro\" build 2>&1 | tail -5; fi'"
      }
    ]
  }
}

警告:這很耗資源。每次檔案編輯都會觸發建置。請謹慎使用——它最適合用於偵錯階段,當您需要立即取得建置回饋時。一般開發時,讓代理程式在準備好後透過MCP手動觸發建置即可。

PreToolUse:封鎖Entitlement修改

保護您的entitlements檔案,避免代理程式意外修改:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "bash -c 'INPUT=$(cat); FP=$(echo \"$INPUT\" | jq -r \".tool_input.file_path // empty\"); if echo \"$FP\" | grep -qE \"\\.entitlements$\"; then echo \"BLOCKED: Do not modify entitlements files without explicit permission.\" >&2; exit 2; fi'"
      }
    ]
  }
}

合併的iOS Hook設定

以下是我在所有iOS專案中使用的完整.claude/settings.json

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "bash -c 'INPUT=$(cat); FP=$(echo \"$INPUT\" | jq -r \".tool_input.file_path // empty\"); if echo \"$FP\" | grep -qE \"\\.(pbxproj|xcworkspace|xib|storyboard|entitlements)$|xcodeproj/|xcworkspace/\"; then echo \"BLOCKED: Do not modify Xcode-managed files. Create Swift files and add manually.\" >&2; exit 2; fi'"
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "bash -c 'INPUT=$(cat); FP=$(echo \"$INPUT\" | jq -r \".tool_input.file_path // empty\"); if echo \"$FP\" | grep -qE \"\\.swift$\"; then swiftformat \"$FP\" --quiet 2>/dev/null; fi'"
      }
    ]
  }
}

這會提供2項保證: 1. 代理程式無法破壞Xcode專案檔案(PreToolUse封鎖) 2. 代理程式碰過的每個Swift檔案都會自動格式化(PostToolUse格式化)


適合代理程式的架構模式

並非所有Swift架構都同樣適合代理程式。以下模式效果最佳,因為它們明確、一致,且在訓練資料中有充分範例。

@Observable(不要使用ObservableObject)

iOS 26+目標應一律使用@Observable。這既是現代模式,也是適合代理程式的模式:

// CORRECT — @Observable
@Observable
@MainActor
final class TimerManager {
    var timeRemaining: TimeInterval = 0
    var state: TimerState = .stopped

    func start() {
        state = .running
        // ...
    }
}

// In a view:
struct TimerView: View {
    @State private var timer = TimerManager()

    var body: some View {
        Text(timer.timeRemaining, format: .number)
    }
}
// WRONG — ObservableObject (deprecated pattern)
class TimerManager: ObservableObject {
    @Published var timeRemaining: TimeInterval = 0
    @Published var state: TimerState = .stopped
}

// WRONG — @StateObject (deprecated pattern)
struct TimerView: View {
    @StateObject private var timer = TimerManager()
}

為什麼@Observable適合代理程式:此模式更簡單(不需要@Published註記)、所有權模型更清楚(使用@State,而不是在@StateObject@ObservedObject之間選擇),而且代理程式使用它時產生的錯誤較少,因為可變動的部分更少。

請在CLAUDE.md中記錄這點:即使目標是iOS 26,代理程式偶爾仍會回到訓練資料中的ObservableObject模式。明確禁止可避免這種情況。

// CORRECT
NavigationStack {
    List(items) { item in
        NavigationLink(value: item) {
            ItemRow(item: item)
        }
    }
    .navigationDestination(for: Item.self) { item in
        ItemDetailView(item: item)
    }
}

// WRONG
NavigationView {
    List(items) { item in
        NavigationLink(destination: ItemDetailView(item: item)) {
            ItemRow(item: item)
        }
    }
}

NavigationStack適用於iOS 16+,也是新程式碼唯一應使用的導覽模式。型別安全的navigationDestination(for:)模式可以避免代理程式建立錯誤的導覽連結。

使用SwiftData處理持久化

SwiftData模型是代理程式輔助開發中最乾淨的持久化模式:

@Model
final class GroceryItem {
    var name: String
    var quantity: Int
    var isCompleted: Bool
    var category: Category?
    var list: GroceryList?

    init(name: String, quantity: Int = 1) {
        self.name = name
        self.quantity = quantity
        self.isCompleted = false
    }
}

代理程式使用SwiftData時的關鍵規則: 1. @Model類別會自動成為Observable——不要再加入@Observable 2. 表單繫結使用@Bindable@Bindable var item: GroceryItem 3. 在view中使用@Query取得反應式資料:@Query var items: [GroceryItem] 4. 在非view程式碼中使用modelContext.fetch() 5. 關聯刪除需要明確規則:.cascade.nullify.deny

Swift 6.2並行

新專案應以Swift 6.2嚴格並行為目標:

// Actor isolation for shared mutable state
@MainActor
@Observable
final class DataManager {
    var items: [Item] = []

    func loadItems() async throws {
        let fetched = try await api.fetchItems()
        items = fetched  // Safe: @MainActor isolated
    }
}

// Sendable conformance for cross-actor transfers
struct Item: Sendable, Identifiable {
    let id: UUID
    let name: String
    let createdAt: Date
}

代理程式的並行指引: - 將所有view model標記為@MainActor(避免資料競爭警告) - 所有非同步工作都使用async/await(不要使用completion handler) - 讓值型別符合Sendable,以便跨actor傳遞 - 在view中使用Task { }進行非同步初始化 - 只有在已量測到效能需求時才使用nonisolated

Liquid Glass設計系統(iOS 26+)

iOS 26導入了Liquid Glass設計系統。只要提供明確指引,代理程式就能妥善處理:

// Glass effect on containers
VStack {
    // content
}
.glassEffect()

// Glass effect with tint
Button("Action") { }
    .glassEffect(.regular.tint(.blue))

// Glass effect on navigation bars (automatic in iOS 26)
NavigationStack {
    // content
}
// Navigation bar automatically uses glass material

// Custom glass shapes
RoundedRectangle(cornerRadius: 16)
    .fill(.ultraThinMaterial)
    .glassEffect()

請納入CLAUDE.md:「在區段背景與卡片容器上使用.glassEffect()。導覽列會在iOS 26中自動採用glass材質。不要用自訂材質手動重建glass效果——請使用系統modifier。」


Framework專屬脈絡

每個Apple framework都有代理程式相關的注意事項。本節涵蓋這8個app使用到的framework。

HealthKit

使用它的app:Return、Water

HealthKit需要謹慎處理權限與平台guard:

// Always check availability and authorization
import HealthKit

@MainActor
@Observable
final class HealthKitManager {
    private let store = HKHealthStore()
    var isAuthorized = false

    func requestAuthorization() async {
        guard HKHealthStore.isHealthDataAvailable() else { return }

        let types: Set<HKSampleType> = [
            HKQuantityType(.dietaryWater),
            HKCategoryType(.mindfulSession)
        ]

        do {
            try await store.requestAuthorization(toShare: types, read: types)
            isAuthorized = true
        } catch {
            // User denied — do not retry automatically
        }
    }
}

代理程式的HealthKit規則: - 一律使用HKHealthStore.isHealthDataAvailable()進行guard - 絕不可假設已有授權——每次寫入都要檢查 - 多平台程式碼使用#if canImport(HealthKit)(tvOS不支援HealthKit) - 除HealthKit提供的資料外,絕不要在本機儲存健康資料 - 在Info.plist中同時包含NSHealthShareUsageDescriptionNSHealthUpdateUsageDescription

SpriteKit

使用它的app:TappyColor、Starfield Destroyer

SpriteKit的場景圖模型需要給代理程式明確指引:

## SpriteKit Rules

- Scene hierarchy is a tree of SKNodes with zPosition ordering
- Physics bodies use category bitmasks (UInt32) for collision detection
- Node pooling: pre-allocate reusable nodes (bullets, particles)
- Never add nodes directly to the scene — use layer nodes for organization
- Update loop: `update(_ currentTime:)` runs every frame — keep it fast
- Actions: use SKAction sequences for animations, not manual property updates
- Textures: use texture atlases for performance (.atlas directories)

代理程式在SpriteKit上的強項: - 建立SKAction序列與群組 - 設定physics body與接觸偵測 - 實作遊戲狀態機 - 建構HUD覆疊

代理程式在SpriteKit上的弱項: - 對效能敏感的遊戲迴圈(代理程式會在每一幀加入不必要的工作) - 複雜物理模擬(若需要精準度,自訂物理會優於SKPhysicsBody) - 粒子效果調校(偏視覺,需要反覆迭代)

Metal

使用它的app:amp97、Water、Starfield Destroyer

Metal是代理程式最容易吃力的framework。GPU程式設計模型與CPU端Swift有根本差異,而代理程式無法驗證視覺輸出。

## Metal Rules

- Shared types between Swift and Metal go in a bridging header (ShaderTypes.h)
- Triple buffer in-flight frames (semaphore with value 3)
- Test shaders on DEVICE, not simulator (Metal behavior differs)
- Compute shaders: threadgroup size must divide evenly into grid size
- Fragment shaders: output color must be in correct color space (sRGB or linear)
- DO NOT optimize shaders without Instruments GPU profiling data

Metal專案的CLAUDE.md應包含: - Uniforms struct定義(由Swift與MSL共用) - render pipeline state設定模式 - buffer索引及其用途 - 目前有哪些shader,以及各自做什麼 - 已知精度問題(half與float)

Live Activities

使用它的app:Return

Live Activities需要特定設定;一旦記錄清楚,代理程式就能妥善處理:

## Live Activities

- ActivityAttributes defined in `TimerActivityAttributes.swift`
- ActivityKit framework: `import ActivityKit`
- Widget extension: `ReturnWidgets/ReturnLiveActivity.swift`
- Start: `Activity<TimerActivityAttributes>.request(attributes:content:)`
- Update: `activity.update(ActivityContent(state:staleDate:))`
- End: `activity.end(ActivityContent(state:staleDate:), dismissalPolicy:)`
- Push token: register for updates via `activity.pushTokenUpdates`

Game Center

使用它的app:Starfield Destroyer

## Game Center

- Authentication: `GKLocalPlayer.local.authenticateHandler`
- Leaderboards: `GKLeaderboard.submitScore(_:context:player:leaderboardIDs:completionHandler:)`
- Achievements: `GKAchievement.report(_:withCompletionHandler:)` (takes `[GKAchievement]` array)
- Always check `GKLocalPlayer.local.isAuthenticated` before submitting
- Handle authentication failure gracefully (offline play must work)

多平台模式

Return涵蓋iOS、watchOS和tvOS。使用代理進行多平台開發時,需要明確記錄平台邊界。

共用程式碼組織

Shared/
├── MeditationSession.swift    # Data model (all platforms)
├── SessionStore.swift         # iCloud sync (all platforms)
└── SessionHistoryView.swift   # UI (adapts per platform)

Return/                        # iOS-specific
ReturnWatch Watch App/         # watchOS-specific
ReturnTV/                      # tvOS-specific

代理規則:「如果檔案位於Shared/,變更會影響所有平台。如果檔案位於平台目錄,變更則會隔離在該平台內。修改檔案前,務必先檢查檔案所在的目錄。」

平台可用性防護

// HealthKit: available on iOS and watchOS, not tvOS
#if canImport(HealthKit)
import HealthKit
// HealthKit code here
#endif

// ActivityKit: available on iOS only
#if canImport(ActivityKit)
import ActivityKit
// Live Activity code here
#endif

// WatchKit: available on watchOS only
#if os(watchOS)
import WatchKit
// Watch-specific code here
#endif

代理指引:「使用平台專屬framework時,務必加入#if canImport()#if os()防護。不要假設某個framework在所有target上都可用。」

各平台UI調適

struct SessionHistoryView: View {
    @Query var sessions: [MeditationSession]

    var body: some View {
        List(sessions) { session in
            SessionRow(session: session)
        }
        #if os(tvOS)
        .focusable()
        #endif
        #if os(iOS)
        .swipeActions {
            Button("Delete", role: .destructive) {
                // delete
            }
        }
        #endif
    }
}

進階工作流程

自主建置-測試-修復迴圈

最強大的模式:提供代理一份功能規格,讓它自主反覆執行建置-測試-修復循環。

Implement a countdown timer that:
1. Starts from a user-selected duration (10, 20, or 30 minutes)
2. Shows remaining time with a circular progress indicator
3. Plays a bell sound on completion
4. Logs the session to HealthKit as mindful minutes

Build after each change. Fix all errors. Run tests when the build succeeds.
Continue until all tests pass and the build is clean.

代理會撰寫程式碼、透過MCP建置、讀取結構化錯誤、修正錯誤,然後重複流程。原本需要人類進行5-10次建置-錯誤-修復循環的功能,可以在單一自主迴圈中完成。

適用情境:具備清楚驗收標準、定義明確的功能。

容易失效的情境:開放式功能(「讓它看起來好看一點」)、效能敏感的程式碼,或任何需要視覺驗證的內容。

iOS的子代理委派

Claude Code的子代理系統適用於iOS專案:

Use a subagent to research the best approach for implementing
iCloud key-value store sync for meditation sessions across iOS,
watchOS, and tvOS. Report back with the recommended pattern.

子代理會在獨立的上下文視窗中探索文件與程式碼模式,回傳摘要,主工作階段再實作建議。這可避免研究工作消耗主要上下文。

跨App模式套用

當您維護多個採用一致模式的iOS App時,代理可以將某個App的模式套用到另一個App:

Look at how Settings.swift works in the Return project
(centralized singleton with validation). Apply the same pattern
to create a Settings.swift for the Water project.

代理會讀取來源模式、理解結構,並在目標專案中建立一致的實作。

雙代理審查(Claude + Codex)

針對關鍵變更,使用來自不同模型家族的兩個代理:

  1. Claude Code撰寫實作
  2. Codex CLI在另一輪流程中進行審查
# After Claude implements the feature:
codex "Review the changes in the last commit. Focus on Swift 6.2
      concurrency correctness, SwiftData relationship integrity,
      and potential retain cycles. Report issues only — no praise."

不同模型家族會抓到不同類型的錯誤。這對Metal shader和concurrency pattern特別有價值,因為這些地方很容易引入細微bug。

雙重審查能抓到、單次審查容易漏掉的問題:

問題類型 Claude強項 Codex強項
SwiftData關聯循環 中等 強(GPT-4o)
@MainActor隔離缺口 中等
Metal buffer對齊 中等 中等
Retain cycle偵測 強(Opus) 強(o3)
API棄用意識 強(較新的訓練資料) 中等
Concurrency競爭條件 強(會抓到不同模式)

雙重審查的目的不是找出更多bug,而是找出不同的bug。每個模型家族在模式辨識上都有不同的失效模式。

跨多個App的批次操作

當framework或模式變更影響多個App時:

# Update @Observable pattern across all projects
for project in BananaList Return Water Reps; do
  cd ~/Projects/$project
  claude -p "Audit all files for any remaining ObservableObject usage.
             Convert to @Observable following the pattern in CLAUDE.md.
             Build and test after changes." --dangerously-skip-permissions
done

請謹慎使用。非互動模式需要--dangerously-skip-permissionsflag,但它會略過所有安全檢查。請確保PreToolUse hooks已就位,以保護.pbxproj檔案。

使用Apple裝置端LLM的App

如果您的App呼叫Apple的Foundation Models framework(例如用於離線摘要、分類或結構化輸出生成),代理需要知道prompt預算。iOS 26.4在SystemLanguageModel新增了兩個API,取代先前4096個token的猜測值:contextSize(模型在單一對話中可接受的token上限)和tokenCount(for:)async throws,會回傳指定prompt實際需要多少token)。17兩者都是@backDeployed(before: iOS 26.4),因此在所有支援FM的OS版本上都可用,不需要#available階梯式判斷。

代理產生prompt建構程式碼時,應遵循此模式:

import FoundationModels

func budgetFor(prompt: String, reservedReply: Int = 256) async throws -> Int {
    let model = SystemLanguageModel.default
    let promptCost = try await model.tokenCount(for: prompt)
    let budget = model.contextSize - promptCost - reservedReply
    guard budget > 0 else { throw ContextError.promptTooLong }
    return budget
}

如果App會使用SystemLanguageModel,請將此模式加入CLAUDE.md。若未加入,代理會退回舊的4096硬編碼,並在配備較大上下文視窗的裝置上悄悄截斷prompt。tokenCount(for:)async throws簽名至關重要;代理若貼上同步版本,將無法編譯。


真實案例研究

抽象建議很容易。以下是來自這8個app的具體情境,說明代理輔助的iOS開發在實務上如何運作,也包含失敗案例。

案例研究1:為Return加入TV App(成功)

任務:為Return這款已有iOS與watchOS版本的冥想計時器加入tvOS target。TV app需要Siri Remote導覽、大螢幕UI,以及與iOS app同步設定。

代理做得好的部分: - 讀取既有iOS TimerManager,並建立一個省略Live Activities與HealthKit(tvOS不支援)的TVTimerManager - 為Siri Remote焦點導覽建立自訂按鈕樣式(TVCapsuleButtonStyleTVCircleButtonStyle) - 建立TVStepper元件,以+/-按鈕取代滾輪選擇器(無法搭配Siri Remote使用) - 透過App Groups(group.com.941apps.Return)實作設定同步 - 在共用程式碼中加入#if os(tvOS)防護條件 - 使用platform=tvOS Simulator,name=Apple TV透過MCP建置並測試

我必須手動處理的部分: - 在Xcode中建立tvOS target(File > New > Target > tvOS App) - 將新的target加入Xcode專案(.pbxproj變更) - 為TV target設定App Groups entitlement - 將TV target加入既有scheme,或建立新的scheme - 手動將代理建立的所有Swift檔案加入TV target - 手動測試Siri Remote導覽(代理無法評估焦點行為)

結果:新增15個Swift檔案,TV app功能完整,約花3小時完成代理輔助開發。以我的估算,代理處理了約80%的實作工作;我則處理需要Xcode UI互動的部分(entitlements、target設定、capability flags),並在實體Apple TV上手動測試焦點。以這個程式碼庫來看,若比照我過去未使用代理推出類似功能的經驗,同等的單人作業會需要數天。

案例研究2:amp97中的Metal著色器偵錯(部分失敗)

任務:為示波器著色器加入以能量為基礎的強度系統。視覺化效果應隨音訊能量脈動。

發生了什麼: 1. 代理寫出有效的Metal著色器修改,加入uEnergy uniform與HDR tonemapping 2. 程式碼編譯無誤 3. 在裝置上,視覺化畫面完全變白,因為強度係數高了10倍(3.5而不是0.30) 4. 代理看不到白畫面,因此沒有回饋訊號 5. 我用肉眼辨識出問題,並要求代理降低係數 6. 代理降低了係數,但整體能量狀態機過於複雜,導致視覺化工具以不同方式壞掉 7. 完全還原,兩個commit(67959edcda4830)在869d914中被還原

教訓:Metal著色器是代理輔助開發中最困難的領域,因為回饋迴圈是斷裂的。代理可以驗證語法(可編譯)與語意(型別正確),但無法驗證輸出(看起來是否正確)。任何會改變視覺行為的著色器修改,都需要人在裝置上驗證。

這之後我加到CLAUDE.md的內容:「在未極度謹慎測試係數前,DO NOT嘗試修改示波器著色器的能量狀態。先前嘗試曾因係數高出10倍而破壞視覺化工具。」

案例研究3:Banana List中的SwiftData遷移(成功)

任務:將資料模型從V1遷移到V2,為GroceryItem加入quantity欄位,並新增帶有關聯的Category模型。

代理做了什麼: 1. 讀取既有V1模型定義 2. 建立帶有新欄位與關聯的V2模型定義 3. 撰寫符合SchemaMigrationPlan protocol的GroceryMigrationPlan 4. 實作V1toV2遷移階段:加入預設quantity: 1category: nil 5. 更新所有view以支援新欄位 6. 更新SampleData.swift供preview使用 7. 透過MCP建置並執行測試,全數通過 8. 建立遷移專用單元測試

關鍵:代理成功,是因為SwiftData遷移遵循明確定義的protocol模式,而這個模式在Apple文件與訓練資料中都有充分呈現。CLAUDE.md明確記錄了V1模型,因此代理理解它要從什麼狀態遷移。

案例研究4:Return中的iCloud工作階段同步(成功,但具複雜度)

任務:實作跨裝置冥想工作階段記錄。在Apple TV或Mac上完成的工作階段,應同步到iPhone,以便寫入HealthKit記錄。

代理產出的內容:

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
    tvOS              Mac              Watch     
 TVTimerMgr        TimerMgr          WatchTimer  
└──────┬──────┘     └──────┬──────┘     └──────┬──────┘
                                             
       └───────────────────┼───────────────────┘
                           
                           
              ┌────────────────────────┐
                   SessionStore       
                (iCloud Key-Value)    
              └───────────┬────────────┘
                          
                          
              ┌────────────────────────┐
                iPhone (on foreground)
                 Write to HealthKit  
              └────────────────────────┘

代理: 1. 建立MeditationSession資料模型,包含UUID、日期、時長、來源裝置,以及HealthKit同步狀態 2. 建立SessionStore singleton,用NSUbiquitousKeyValueStore管理iCloud同步 3. 實作合併衝突解決(以UUID去重) 4. 加入SessionHistoryView,並提供平台特定調整(iOS上的滑動刪除、tvOS上的焦點操作) 5. 接上iPhone端HealthKit同步,以處理來自其他裝置的工作階段

需要反覆調整的部分:初始實作沒有處理iPhone app在背景啟動的情境(沒有前景通知可觸發同步)。代理需要明確提示:「Use NSUbiquitousKeyValueStore.didChangeExternallyNotification to trigger sync on background KV changes.」在收到這個提示後,實作才正確。

教訓:當架構描述清楚時,代理能妥善處理多平台架構模式。iCloud同步模式並不簡單,但它遵循Apple已文件化的模式,代理能夠理解。邊界案例(背景同步)則需要人的領域知識,因為這部分並未被充分記錄。

案例研究5:Starfield Destroyer中的Game Center整合(成功)

任務:為太空射擊遊戲加入Game Center排行榜與成就。

代理做得好的部分: - 在app進入點實作GKLocalPlayer.local.authenticateHandler - 建立GameCenterManager,包含分數提交與成就回報方法 - 在所有Game Center操作前加入驗證狀態檢查 - 妥善處理離線情境(遊戲可在沒有Game Center時遊玩,重新連線後再提交) - 建立符合8艘船進度系統的成就定義

需要手動處理的部分: - 在App Store Connect中建立排行榜與成就(網頁入口,代理無法存取) - 在Xcode中設定Game Center entitlement - 使用sandbox Game Center帳號測試(需要在裝置上手動登入)


使用代理的專案生命週期

開始新的 iOS 專案

使用代理協助開始新專案的最佳工作流程:

階段 1:人工設定(15-30 分鐘) 1. 建立 Xcode 專案(File > New > Project) 2. 設定簽署與功能 3. 設定部署目標與支援的目的地 4. 加入任何必要的 entitlements(HealthKit、Game Center 等) 5. 建立初始 CLAUDE.md,寫入專案身分與規則

階段 2:代理實作(數小時到數天) 1. 代理建立資料模型(SwiftData、Core Data 或單純的 structs) 2. 代理依照您記錄的模式建立 views 3. 代理在 manager/service classes 中實作商業邏輯 4. 代理撰寫單元測試 5. 透過 MCP 進行建置-測試-修正循環(自主)

階段 3:人工整合(30-60 分鐘) 1. 將代理建立的檔案加入 Xcode targets 2. 驗證簽署與 entitlements 3. 在實體裝置上測試 4. 檢視視覺版面與 UX 5. 提交至 App Store Connect

維護既有專案

針對已建立 app 的持續開發:

You: Here's the next feature for Return: add a "Focus Score" that
     calculates from session duration and consistency. Show it on
     the main timer view. Build and test.

Claude: [reads CLAUDE.md, understands patterns]
        [reads TimerManager.swift, Settings.swift]
        [creates FocusScore.swift  model with calculation logic]
        [creates FocusScoreView.swift  display component]
        [integrates into ContentView.swift]
        [calls build_sim  1 error: missing import]
        [fixes import]
        [calls build_sim  success]
        [writes FocusScoreTests.swift]
        [calls test_sim  all pass]

代理的成效會隨著 CLAUDE.md 反映專案現況的程度而提升。當您加入重要新功能、變更架構模式,或導入新 framework 時,請更新 CLAUDE.md。

何時該讓代理介入,何時不該

任務 代理? 原因
新 SwiftUI view 代理很擅長宣告式 UI
SwiftData model 變更 定義清楚、可測試
單元測試 機械式、以模式為基礎
重構 系統化、多檔案
建置錯誤診斷 是(透過 MCP) 結構化回饋循環
新 Xcode target 需要 Xcode UI、.pbxproj 變更
簽署與 provisioning 以入口網站為基礎,代理無法存取
視覺潤飾 需要人工美感判斷
Metal shader 調校 需要裝置 GPU 測試
App Store 提交 入口網站與 Xcode Organizer
效能 profiling 需要 Instruments
Accessibility audit 部分 代理可以加入 labels,由人工驗證 VoiceOver

設定代理定義

如果您使用 Claude Code 的代理定義系統(.claude/agents/),請建立 iOS 專用代理:

---
name: ios-developer
description: iOS development agent with MCP build tools and SwiftUI expertise
tools:
  - XcodeBuildMCP
  - xcode
---

# iOS Developer Agent

You are an iOS development agent for apps targeting iOS 26+ with SwiftUI.

## Architecture Rules
- @Observable for all view models (NEVER ObservableObject)
- NavigationStack for all navigation (NEVER NavigationView)
- SwiftData for persistence
- Swift 6.2 strict concurrency
- @MainActor on all Observable classes

## Build & Test — Always Use MCP

Prefer MCP tools over raw shell commands for ALL build operations:

- **Build**: `build_sim` / `build_device` (NOT `xcodebuild` via Bash)
- **Test**: `test_sim` / `test_device` (NOT `xcodebuild test` via Bash)
- **Simulators**: `list_sims`, `boot_sim`, `open_sim`
- **Debug**: `debug_attach_sim`, `debug_stack`, `debug_variables`
- **Apple docs**: `DocumentationSearch` (NOT WebSearch for Apple APIs)
- **Swift verification**: `ExecuteSnippet` (NOT `swift` via Bash)

MCP returns structured JSON. Bash returns unstructured text.

## File Management Rules
- NEVER modify .pbxproj, .xcodeproj/, .xcworkspace/, .xib, .storyboard
- Create Swift files in the correct directory
- Report files that need manual addition to Xcode targets

## SwiftData Rules
- @Model classes are automatically Observable — do not add @Observable
- Use @Bindable for form bindings to model properties
- Use @Query in views, modelContext.fetch() elsewhere
- Document relationship delete rules

## When You Get Stuck
- Build errors: use `build_sim` via MCP for structured output
- API questions: use `DocumentationSearch` via Apple MCP
- Swift verification: use `ExecuteSnippet` via Apple MCP
- Never guess — verify with tools

在 Claude Code sessions 中使用 @ios-developer 參照此代理。


代理輔助 iOS 的測試模式

只要給予清楚指引,代理就能寫出優秀的單元測試。以下模式能產生最佳結果。

測試檔案組織

# In CLAUDE.md:
## Test Structure

Tests mirror source structure:
- `ReturnTests/TimerManagerTests.swift` tests `TimerManager.swift`
- `ReturnTests/SettingsTests.swift` tests `Settings.swift`
- `ReturnTests/ConstantsTests.swift` tests `Constants.swift`

Test naming: `test_<what>_<condition>_<expected>`
Example: `test_start_whenStopped_transitionsToRunning`

測試提示

有效的測試提示:

Write unit tests for TimerManager covering:

1. Initial state is .stopped with timeRemaining == selectedDuration
2. start() transitions state to .running
3. pause() from .running transitions to .paused
4. reset() from any state returns to .stopped with original duration
5. start() from .paused resumes (state becomes .running)
6. Edge case: reset() when already stopped is a no-op
7. Edge case: pause() when already paused is a no-op

Follow the existing test pattern in SettingsTests.swift.
Use setUp() to create a fresh TimerManager for each test.

這樣有效的原因: 編號的驗收標準會提供代理一份 checklist。參照既有測試檔案可建立模式。指定 setUp() 用法可避免代理建立糾結的測試狀態。

無效的測試提示:

Write tests for TimerManager.

這會產生泛泛而淺層的測試,漏掉邊界案例,也可能未遵循專案既有模式。

Async 測試模式

若要測試以 timer 為基礎與 async 程式碼:

// Agent produces this pattern when guided correctly:
final class TimerManagerTests: XCTestCase {
    var sut: TimerManager!

    @MainActor
    override func setUp() {
        super.setUp()
        sut = TimerManager()
    }

    @MainActor
    func test_start_whenStopped_transitionsToRunning() {
        // Given
        XCTAssertEqual(sut.state, .stopped)

        // When
        sut.start()

        // Then
        XCTAssertEqual(sut.state, .running)
    }

    @MainActor
    func test_timerCountsDown_afterOneSecond() async throws {
        // Given
        sut.selectedDuration = 10
        sut.reset()
        sut.start()

        // When
        try await Task.sleep(for: .seconds(1.1))

        // Then
        XCTAssertLessThanOrEqual(sut.timeRemaining, 9.0)
    }
}

代理需要提醒的關鍵模式: - 測試 @MainActor classes 的測試方法需標註 @MainActor - 使用 Task.sleep 或 async operations 的測試需使用 async throws - 以時間為基礎的 assertions 需保留容忍範圍(1.1 秒,而不是剛好 1.0) - 使用乾淨的 setUp() / tearDown() 確保測試隔離

Snapshot Testing

若要偵測視覺回歸,可以考慮加入 swift-snapshot-testing

Add snapshot tests for the main timer view in three states:
1. Stopped (showing full duration)
2. Running (showing countdown)
3. Completed (showing 00:00 with completion state)

Use SnapshotTesting library. Create reference images on first run.

代理可以正確設定 snapshot tests,但無法審查參考圖片。您先審查初始 snapshots,之後代理的測試就能在未來變更中捕捉視覺回歸。

iOS專案的上下文視窗管理

1M上下文視窗(Opus 4.6)很大,但並非無限。iOS專案有特定的上下文管理考量。

iOS檔案的Token成本

檔案類型 典型大小 約略Token數
SwiftUI view(簡單) 50-100行 500-1,000
SwiftUI view(複雜) 200-400行 2,000-4,000
SwiftData model 30-80行 300-800
Manager/service class 100-300行 1,000-3,000
Metal shader(.metal) 50-200行 500-2,000
Unit test檔案 50-200行 500-2,000
CLAUDE.md 100-300行 1,000-3,000
MCP回應(build) 不定 200-2,000
MCP回應(test) 不定 500-5,000

對於50個檔案的專案:讀取所有檔案大約會消耗50,000-100,000個token,在1M視窗內綽綽有餘。代理程式可以把整個專案保留在上下文中。

對於100個以上檔案的專案:必須選擇性讀取。代理程式會先讀CLAUDE.md(取得檔案結構註解),再依需要讀取特定檔案。這就是CLAUDE.md中的檔案註解至關重要的原因:它們能引導代理程式找到正確檔案,而不必讀取所有內容。

大型專案的策略

  1. 詳細的CLAUDE.md檔案註解——代理程式讀取檔案地圖後,直接導向相關檔案
  2. 委派給subagent——將探索與研究交給subagent(乾淨上下文,回傳摘要)
  3. 聚焦的提示——「修改SettingsView.swift以新增toggle」比「更新設定」更好
  4. Session邊界——針對不相關功能啟動新的session,而不是延長既有的長session
  5. 使用/compact——Claude Code的壓縮命令會摘要對話並釋放上下文

MCP的Token效率

支持MCP最有力的理由之一:結構化的JSON回應比原始xcodebuild輸出消耗少得多的token。

情境 原始Bash Token MCP Token 節省
Build成功 3,000-10,000 200-500 85-95%
Build失敗(1個錯誤) 3,000-10,000 300-800 90-92%
Test結果(20項test) 2,000-5,000 500-1,000 75-80%
模擬器清單 500-2,000 200-400 60-80%

在典型開發session中,若有10-20次build循環,與原始xcodebuild相比,MCP可節省30,000-150,000個token。這些token便能保留給實際的程式碼推理使用。


疑難排解

「build_sim失敗——找不到scheme」

代理程式正在猜測scheme名稱。修正方式:

Use discover_projs and list_schemes to find the correct scheme name
for this project before building.

或將scheme名稱明確加入CLAUDE.md:

## Build
Primary scheme: `Return` (iOS)
Watch scheme: `ReturnWatch` (watchOS)
TV scheme: `ReturnTV` (tvOS)

「xcrun mcpbridge——找不到命令」

您需要Xcode 26.3或更新版本。請用xcodebuild -version檢查。如果已安裝Xcode 26.3+,但命令仍然失敗:

# Ensure Xcode command line tools are selected
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer

# Verify
xcrun mcpbridge --help

「MCP工具沒有出現在Claude Code中」

在session中途註冊的MCP工具,可能要重新啟動後才會出現。結束Claude Code並啟動新的session:

# Exit current session (Ctrl+C or /exit)
# Start fresh
claude

接著驗證:

You: List all available MCP tools from XcodeBuildMCP.

「代理程式一直透過Bash使用xcodebuild,而不是MCP」

代理程式沒有透過Tool Search發現MCP工具。有兩種修正方式:

  1. 在CLAUDE.md加入明確指引(請參閱教代理程式使用MCP
  2. 直接提示:「Use the build_sim MCP tool, not xcodebuild via Bash」

「Build成功,但代理程式回報失敗」

XcodeBuildMCP會解析xcodebuild輸出。如果build產生看起來像錯誤的警告(deprecation warning很常見),代理程式可能會誤判結果。請檢查MCP回應中的實際status欄位。

「模擬器在boot期間卡住」

終止所有模擬器並重新啟動:

xcrun simctl shutdown all
xcrun simctl boot "iPhone 16 Pro"

或請代理程式處理:

Shut down all simulators, then boot a fresh iPhone 16 Pro.

「代理程式無視CLAUDE.md規則,嘗試修改.pbxproj」

CLAUDE.md規則是建議。Hooks才是強制執行。如果沒有PreToolUse hook阻擋.pbxproj寫入,代理程式最終仍會嘗試修改。請安裝hook:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "bash -c 'INPUT=$(cat); FP=$(echo \"$INPUT\" | jq -r \".tool_input.file_path // empty\"); if echo \"$FP\" | grep -qE \"\\.(pbxproj|xcworkspace|xib|storyboard)$|xcodeproj/|xcworkspace/\"; then echo \"BLOCKED: Do not modify Xcode project files.\" >&2; exit 2; fi'"
      }
    ]
  }
}

規則只是說「請不要」。Hooks則是說「不可以」。

常見問題

我應該從哪個代理程式執行環境開始?

Claude Code CLI with XcodeBuildMCP。它具備最深入的 MCP 整合、最成熟的 hook 系統,以及可將整個 iOS 專案保留在工作記憶體中的 1M context window(Opus 4.6)。請從這裡開始;待工作流程成熟後,再加入 Codex 進行 review,並使用 Xcode native agents 做快速 inline edits。

我需要兩個 MCP 伺服器嗎?

對多數開發者而言,單用 XcodeBuildMCP 就能涵蓋 90% 的需求(builds、tests、simulators、debugging)。如果需要文件搜尋、Swift REPL 驗證,或 SwiftUI preview rendering,再加入 Apple 的 Xcode MCP。之後隨時都能加入,這兩個伺服器彼此獨立。

代理程式可以從零建立新的 Xcode 專案嗎?

XcodeBuildMCP 包含 create_project 工具,可 scaffold 新的 Xcode 專案。不過,對 production apps,我建議先在 Xcode 中建立專案(以正確設定 signing、capabilities 與 target configuration),再使用代理程式完成所有程式碼實作。您在 Xcode new project wizard 花的 5 分鐘,能省下數小時由代理程式產生 project configuration 問題的排除時間。

代理程式如何處理 Swift Package Manager 相依套件?

處理得很好。Package.swift 是標準 Swift 檔案,代理程式可以可靠地讀取與編輯。新增 dependencies、更新 version ranges,以及設定 targets 都能運作。限制在於以 .xcodeproj 為基礎的 dependency management(Xcode 的 package resolution UI),這部分由 Xcode 管理,不應交給代理程式編輯。

代理程式可以提交到 App Store 嗎?

不行。App Store 提交流程涉及 Xcode 的 Organizer、provisioning profiles、screenshots、metadata,以及 App Store Connect portal。這些都無法透過 MCP 或 command-line tools 讓代理程式有效操作。代理程式可以處理 archive 以前的一切:implementation、testing、bug fixing 與 documentation。最後一哩提交仍須由人操作。

不過,代理程式可以協助 App Store metadata。您可以請代理程式根據最新變更撰寫 app description、keywords 與 what’s-new text。這類文字生成工作正是代理程式擅長之處。

在代理程式輔助的 iOS 開發中,我該如何處理 secrets 和 API keys?

絕不要 commit secrets。對於連接後端 APIs 的 iOS apps:

  1. 使用 .xcconfig 檔案管理特定環境的 configuration
  2. .xcconfig 檔案加入 .gitignore
  3. 透過 Info.plist build settings 參照 config values
  4. 在 CLAUDE.md 中記錄必要 secrets,但不要包含實際 values
## Configuration

API base URL and keys are in `Config.xcconfig` (not committed).
Required keys:
- `API_BASE_URL` — Backend server URL
- `API_KEY` — Authentication token

Create `Config.xcconfig` from `Config.xcconfig.template`.

代理程式知道這些 keys 存在,也知道使用位置,但永遠看不到實際 values。

SwiftUI animations 呢?代理程式能寫嗎?

代理程式在語法上能很好地撰寫 animation code,但無法以視覺方式驗證結果。簡單動畫(.animation(.spring()).transition(.slide)withAnimation { })通常會產生正確結果。複雜、多步驟且需要精準 timing 的動畫,則需要視覺反覆調整,這是代理程式做不到的。

有效:「當 timer 在 states 之間轉換時,加入 spring animation。」

無效:「讓 timer animation 感覺令人滿意。」(主觀,需要視覺微調。)

代理程式如何處理 error handling patterns?

處理得很好。代理程式理解 Swift 的 do/catchResultasync throws patterns:

Implement error handling for the HealthKit authorization flow:
1. Check HKHealthStore.isHealthDataAvailable()  show alert if not
2. Request authorization  handle denial gracefully
3. On write failure  retry once, then show error
4. All errors should be user-facing with localized descriptions

代理程式會產生結構化的 error handling,並搭配適當的 user-facing messages。有時它們會過度處理錯誤(catch 原本應該 propagate 的 exceptions),因此請 review catch blocks。

我可以使用代理程式實作 accessibility 嗎?

可以,但只能部分。代理程式能正確加入 accessibility labels、hints 與 traits:

Add accessibility labels to all interactive elements in TimerView:
- Timer display: current time remaining
- Start/Pause button: current state and action
- Reset button: "Reset timer"
- Duration picker: selected duration

代理程式做不到的是:驗證 VoiceOver navigation order 是否正確、測試 Dynamic Type scaling,或評估 color contrast ratios。請使用 Xcode 的 Accessibility Inspector 進行驗證。

如果不使用 SwiftData,代理程式如何處理 Core Data migration?

代理程式能撰寫 Core Data migration mappings 與 model versions,但手動 Xcode steps(建立新的 model versions、選取 current version)無法自動化。如果您仍使用 Core Data 而非 SwiftData,請在 CLAUDE.md 中記錄 model version history:

## Core Data Model Versions
- V1: Initial (GroceryList, GroceryItem)
- V2: Added Category model (current)
- Migration: Lightweight automatic for V1→V2

代理程式如何處理 SwiftUI previews?

有兩種方式: 1. Apple Xcode MCP 的 RenderPreview tool 會 headlessly render previews 並傳回結果。代理程式可以驗證 preview 能編譯並 render 且沒有 errors,但無法評估視覺正確性。 2. Build-based verification 透過 build_sim 確認 preview providers 能編譯。如果 preview 在 runtime crash,build 仍會成功,crash 只有在 Xcode 嘗試 render preview 時才會出現。

若要進行 previews 的視覺驗證,仍然需要開啟 Xcode。

visionOS 和 Apple Vision Pro 呢?

相同 patterns 也適用。XcodeBuildMCP 支援 visionOS simulators,架構 patterns(@Observable、NavigationStack、SwiftData)也完全一致。RealityKit-specific code(3D content、immersive spaces、hand tracking)則與 Metal 有相同限制:代理程式能寫出正確程式碼,但無法驗證 spatial output。

專案多大時,代理程式會開始吃力?

限制因素是 context window size。使用 Opus 4.6 的 1M token window 時,Claude Code 可同時在 active working memory 中保留約 50-70 個 Swift 檔案。對更大型專案,代理程式會使用 file search 與 selective reading 來處理 codebase 的子集。100+ 檔案的專案也能正常運作;代理程式只是按需讀取檔案,而不是把所有內容都放進 context。

實務上的限制不是檔案數量,而是 codebase coherence。一個有詳盡 CLAUDE.md、文件完善的 200 檔案專案,會比沒有文件的 30 檔案專案產生更好的結果。

我需要懂 Swift 才能用代理程式進行 iOS 開發嗎?

您需要能 review 代理程式輸出並做出架構決策。您不必每一行都自己寫,但必須足夠理解 Swift,才能在代理程式做出錯誤選擇時察覺,特別是 concurrency、memory management 與 framework-specific patterns。代理程式是您現有能力的 10x amplifier,而不是替代品。

代理程式如何處理 Swift 檔案中的 merge conflicts?

代理程式能可靠地解決 Swift source files 中的 merge conflicts。標準 conflict markers(<<<<<<<=======>>>>>>>)所有代理程式執行環境都能充分理解。不過,.pbxproj 檔案中的 merge conflicts 仍須手動解決,請不要要求代理程式處理 .pbxproj conflicts。

執行代理程式進行 iOS 開發的成本是多少?

使用 Anthropic 的 Max plan(Opus 4.6、1M context)時,典型 iOS development session 會執行 30-120 分鐘,並處理 200K-800K tokens。MCP tool calls 只會增加極少 overhead(structured JSON responses 相較 raw build output 更節省 tokens)。成本與在任何其他 codebase 上執行 Claude Code 相當;iOS 開發並不會比 web 開發明顯更貴或更便宜。

我可以在 UIKit 專案中使用代理程式嗎?

可以,但代理程式在 SwiftUI 上更有效。UIKit 需要更多 boilerplate,declarative structure 較少,而且經常涉及代理程式無法編輯的 Interface Builder files。如果您有 UIKit 專案,可以考慮讓代理程式處理 model layer 與 business logic,UI 則手動處理,或逐步將 views 遷移到 SwiftUI。

代理程式如何處理 localization?

代理程式能有效建立與編輯 .xcstrings(Xcode string catalog)檔案。它們可以新增 localization keys、提供 translations,並維持跨語言一致性。.xcstrings 檔案的 structured JSON format 對代理程式很友善。對 .strings 檔案(legacy format)而言,代理程式同樣表現良好,因為 key-value format 相當直觀。


iOS常見 Agent錯誤(以及如何預防)

以下是我在8個iOS專案、數千次 Agent互動中觀察到的反覆錯誤。每一項都有對應的預防策略。

錯誤1:混用 Observable模式

發生情況: Agent在某個檔案使用@Observable,在另一個檔案使用ObservableObject,或是把@Observable加到@Model類別上(它本身已經是 Observable)。

預防方式: 在 CLAUDE.md中明確訂定規則:

- NEVER use ObservableObject — use @Observable
- NEVER add @Observable to @Model classes (already Observable)
- NEVER use @StateObject — use @State with @Observable
- NEVER use @ObservedObject — access @Observable properties directly

錯誤2:在 Closure中造成 Retain Cycle

發生情況: Agent建立會強引用self的 closure,特別常見於Timer.publishNotificationCenter和 completion handler。

預防方式: 在 CLAUDE.md中加入 closure模式:

## Closure Pattern
- Timer callbacks: use `[weak self]` and guard
- NotificationCenter observers: store in `Set<AnyCancellable>` and use `[weak self]`
- Completion handlers: use `[weak self]` for any closure stored beyond the call site

錯誤3:忽略 @MainActor需求

發生情況: Agent建立沒有@MainActor隔離的@Observable類別,導致 Swift 6.2並行警告,或在主執行緒以外更新 UI時造成執行階段崩潰。

預防方式:

## Concurrency Rule
ALL @Observable classes MUST be @MainActor:
```swift
@Observable
@MainActor
final class SomeManager { }
```

發生情況: Agent使用已棄用的NavigationLink(destination:label:),而不是型別安全的NavigationLink(value:)加上.navigationDestination(for:)模式。

預防方式:

## Navigation Pattern
ALWAYS use value-based navigation:
```swift
NavigationLink(value: item) { ItemRow(item: item) }
.navigationDestination(for: Item.self) { ItemDetailView(item: $0) }
```
NEVER use: `NavigationLink(destination: ItemDetailView(item: item)) { }`

錯誤5:硬編碼 Simulator名稱

發生情況: Agent撰寫建置命令時使用特定 simulator名稱(「iPhone 16 Pro」),而您的系統上可能沒有這個 simulator。

預防方式: MCP會處理這件事,list_sims會探索可用的 simulator。在 CLAUDE.md中:

## Simulators
Do NOT hardcode simulator names. Use `list_sims` MCP tool to discover
available devices, then `boot_sim` with the discovered device ID.

錯誤6:在錯誤目錄建立檔案

發生情況: Agent把新的 view檔案建立在專案根目錄,而不是Views/子目錄,或是把 model放進錯誤的 group。

預防方式: CLAUDE.md中的檔案結構註解會引導放置位置。此外:

## File Placement Rules
- Views → `AppName/Views/`
- Models → `AppName/Models/`
- Managers → `AppName/Managers/`
- Extensions → `AppName/Extensions/`
- Tests → `AppNameTests/`

錯誤7:未處理平台可用性

發生情況: Agent在會為 tvOS編譯的共用程式碼中使用 HealthKit(tvOS不支援 HealthKit),或是在 watchOS程式碼中使用 ActivityKit。

預防方式:

## Platform Guards
- HealthKit: `#if canImport(HealthKit)` (unavailable on tvOS)
- ActivityKit: `#if canImport(ActivityKit)` (iOS only)
- WatchKit: `#if os(watchOS)`
- UIKit haptics: `#if os(iOS)` (unavailable on tvOS, watchOS uses WKHaptic)

錯誤8:把簡單功能過度工程化

發生情況: Agent為一個本該是20行 utility function的功能,建立 protocol、protocol extension、具體實作、factory和 dependency injection container。

預防方式: 加入簡化原則:

## Architecture Principle
Prefer the simplest solution that handles the requirements.
- Direct implementation over protocol abstraction (unless you have 2+ conforming types)
- Concrete types over generics (unless reuse is proven)
- Extensions on existing types over new wrapper types

誠實評估

在用 AI agents交付8個iOS app之後,總結如下:

Agents改變了: 實作速度。過去需要數天的工作,現在數小時即可完成。SwiftUI views、SwiftData models、unit tests、重構,現在主要由 agent產出,再由人類審查。

Agents沒有改變: 架構決策、視覺設計、效能最佳化或 App Store提交。這些仍由人類主導。

倍增效果確實存在,但有邊界。 以這8個 app組合來看,我的主觀估計是:在文件完善、具備適當MCP與 hook設定的專案中,time-to-feature大約提升3到5倍。這並非對照組量測,而是在同一批 codebase中,比較 agent輔助功能與等效單人工作的實際時間。沒有文件、沒有 hooks的專案,大概只有1.5到2倍提升,因為 agent花太多時間在猜測,而不是建置。19

真正值得投資的是: 花在 CLAUDE.md、hooks和MCP設定上的時間。每投入1小時設定,都會省下許多修正 agent錯誤的時間。設定本身就是產品,agent只是執行引擎。

讓我意外的是: MCP伺服器大幅改變了互動方式。在MCP之前,agents像是剛好懂 Swift的進階文字編輯器。在MCP之後,它們成了會撰寫、建置、測試、除錯與反覆迭代的開發夥伴。結構化回饋迴圈,正是只會寫程式碼的 agent與能交付程式碼的 agent之間的差別。

我會對過去的自己說: 從最小的 app開始(Reps,14個檔案),先把MCP和 hook設定做好,寫一份完整的 CLAUDE.md,再把這些模式擴展到更大的專案。不要一開始就碰63個檔案的多平台 app。無論專案大小,基礎建設投資都一樣。先在小專案做一次,再複製到其他所有專案。

未來: Xcode 26.3的原生 agent整合只是開始,不是終點。Apple推出MCP支援,代表工具鏈正朝 agent-first開發前進。現在就投資於 agent相容專案結構的開發者,包括乾淨的 CLAUDE.md檔案、可測試架構、自動化 hooks,將會在工具持續進步時累積複利。


快速參考卡

安裝(一次性設定)

# XcodeBuildMCP (59 tools)
claude mcp add XcodeBuildMCP -s user \
  -e XCODEBUILDMCP_SENTRY_DISABLED=true \
  -- npx -y xcodebuildmcp@latest mcp

# Apple Xcode MCP (20 tools)
claude mcp add --transport stdio xcode -s user -- xcrun mcpbridge

# Codex MCP setup
codex mcp add xcode -- xcrun mcpbridge

# Verify
claude mcp list

必備 CLAUDE.md章節

1. Project identity (bundle ID, target OS, architecture)
2. File structure with annotations
3. Build and test commands
4. Key patterns and rules
5. Prohibitions (NEVER touch .pbxproj)
6. Framework-specific context

必備 Hooks

{
  "PreToolUse": [{ "matcher": "Edit|Write", "command": "block .pbxproj" }],
  "PostToolUse": [{ "matcher": "Edit|Write", "command": "swiftformat" }]
}

架構規則

@Observable         (not ObservableObject)
NavigationStack     (not NavigationView)
@State              (not @StateObject)
SwiftData @Model    (not Core Data)
async/await         (not completion handlers)
@MainActor          (on all Observable classes)
.glassEffect()      (Liquid Glass, iOS 26+)

MCP工具優先順序

Build:     build_sim          (not xcodebuild via Bash)
Test:      test_sim           (not xcodebuild test via Bash)
Sim:       list_sims/boot_sim (not xcrun simctl via Bash)
Docs:      DocumentationSearch (not WebSearch)
REPL:      ExecuteSnippet     (not swift via Bash)

變更記錄

日期 變更
2026-05-24 已將 Xcode 26.5 穩定版發布日期修正為 2026-05-11,並依 Apple 發布頁面將 build 固定為 17F42。本次本機驗證:xcodebuild -version 回傳 Xcode 26.5 / Build version 17F42xcodebuildmcp 的 npm latest 回傳 2.5.2time.modified2026-05-12T07:40:41.737Z13
2026-05-16 將建議使用的 Xcode 提升至 26.5+(2026-05-11 發布)。兩項新的 Coding Intelligence 功能對 agent 工作流程很重要:現在可在 coding assistant 中排入訊息,因此不必等回應完成就能接著安排下一個請求;agent 也能在繼續執行前提出釐清問題。兩者都能降低在 Claude Code 或 Codex sessions 旁並行執行 Xcode 原生 agent 的摩擦。13 XcodeBuildMCP 現況檢查:v2.5.2(2026-05-12)為最新版,新增內建 AXe 1.7.0,並修正 log-capture filter-validation 問題;v2.1.0+ 的 xcodebuildmcp init 流程仍是建議的安裝路徑。
2026-04-28 將 agent 工作流程建議使用的 Xcode 提升至 26.4+(26.4.1,2026-04-16,build 17E202 為最新穩定版,僅含錯誤修正)。引用 Xcode 26.4 功能(2026-03-24,build 17E192),這些功能對 agent 撰寫的測試與在地化有幫助:Swift Testing image attachments、Issue.record 的 severity、附帶 crashlogs 的 UI-test crash warnings(特別適用於 XCUIApplication(bundleIdentifier:) / XCUIApplication(url:) apps)、String Catalog editor 改進。新增 xcodebuildmcp init 自動安裝器(v2.1.0+,2026-02-23),作為手動 MCP 設定的替代方案。
2026-04-27 App Store Connect:自 2026-04-28 起,Xcode 26+ 提交成為強制要求。Foundation Models 新增 SystemLanguageModel.contextSizetokenCount(for:) APIs(向後部署至 iOS 26.4),並加入 agent 產生 FM prompt-budget 程式碼的模式。iOS 26.4.2(4月22日)與 iOS 26.5 beta 3(4月20日)已發布,但沒有影響 agent toolchain 的變更。
2026-04-13 初次發布。8 款 app、3 個 runtimes、MCP 設定、CLAUDE.md patterns、hooks、案例研究。

參考資料


  1. XcodeBuildMCP 預設包含 Sentry telemetry。專案的隱私權文件詳細說明會傳送的內容:錯誤訊息、stack traces,以及在某些情況下的檔案路徑。XCODEBUILDMCP_SENTRY_DISABLED=true env var 可完全退出。 

  2. Anthropic,〈Model Context Protocol Specification〉,modelcontextprotocol.io/specification。MCP specification 定義了 JSON-RPC transport、tool discovery,以及 XcodeBuildMCP 與 Apple 的 Xcode MCP 都實作的 resource protocol。 

  3. XcodeBuildMCP,github.com/getsentry/XcodeBuildMCP。開放原始碼,由 Sentry 維護。涵蓋 simulator、device、debugging 與 UI automation 工作流程,共 59 個 tools。採用 semantic versioning 並附 changelogs。 

  4. Apple 在 Xcode 26.3 intelligent developer tools initiative 中推出 Xcode MCP server,將 MCP 定位為 AI coding assistants 與 Xcode toolchain 之間的介面層。官方文件請參閱 Xcode Release Notes。 

  5. Rudrank Riyam,〈Exploring Xcode Using MCP Tools〉,rudrank.com/exploring-xcode-using-mcp-tools-cursor-external-clients,2026。獨立確認 Apple 的 MCP tool 數量、XPC 相依性與文件搜尋能力。 

  6. Jimenez, C.E., Yang, J., Wettig, A., et al.,〈SWE-bench: Can Language Models Resolve Real-World GitHub Issues?〉ICLR 2024。arxiv.org/abs/2310.06770。具備 structured tool access 的 agents,表現明顯優於僅能使用 unstructured shell commands 的 agents。此發現驗證 structured MCP interfaces 對 agent 效能的價值。 

  7. Claude Code CLI documentation,code.claude.com。Hook system、MCP configuration、subagent delegation 與 agent definitions。 

  8. SwiftFormat,github.com/nicklockwood/SwiftFormat。用於 PostToolUse hooks 的 Swift formatting tool,以維持一致的程式碼風格。 

  9. XcodeBuildMCP 官方網站,xcodebuildmcp.com。透過 CLI output example 確認 59 個 MCP tools。Tool 類別:simulator、device、debugging 與 UI automation。可透過 Homebrew 或 npx 安裝。 

  10. Swiftjective-C,〈Agentic Coding in Xcode 26.3 with Claude Code and Codex〉,swiftjectivec.com,2026年2月。確認 Xcode 26.3 內建原生 Claude Agent,並透過 Settings > Intelligence 支援 Codex runtime。透過 xcrun mcpbridge 暴露 20 個 MCP tools。 

  11. Blake Crosley,〈Two MCP Servers Made Claude Code an iOS Build System〉,blakecrosley.com/blog/xcode-mcp-claude-code,2026年2月。設定逐步說明,以及同一作者 iOS 開發工作流程中的實務成果。 

  12. Apple Developer News,〈Upcoming Requirements〉。2026-04-28 條目:「Apps uploaded to App Store Connect must be built with Xcode 26 or later using an SDK for iOS 26, iPadOS 26, tvOS 26, visionOS 26, or watchOS 26.」macOS 不在此要求列出的平台範圍內。 

  13. Apple,〈Xcode 26.5 Release Notes〉與〈Xcode 26.5 (17F42) - Releases〉。Apple 於 2026-05-11 列出 Xcode 26.5,build 為 17F42。引用自 release notes 的兩項 Coding Intelligence 功能:可在 coding assistant 中排入訊息,而不必等待目前回應完成(174563016);agent 可提出釐清問題,在繼續執行前蒐集脈絡(175182375)。另包含 StoreKit Testing 對 12 個月承諾制月訂閱的支援(PricingTerms model、billingPlanType PurchaseOptionTransactionSubscriptionRenewalInfo 上的 CommitmentInfo),以及 Swift debugger 修正,可在 async/await operations 中逐步執行會遷移 threads 的 Swift Tasks。本 session 於 2026-05-24 驗證:xcodebuild -version 回傳 Xcode 26.5Build version 17F42npm view xcodebuildmcp version dist-tags.latest time.modified --json 回傳 latest 2.5.2time.modified2026-05-12T07:40:41.737Z。另見:9to5Mac,〈Xcode 26.5 adds two features that make agentic coding more useful〉,2026-05-12。 

  14. Apple,〈Xcode 26.4 Release Notes〉。Xcode 26.4(2026-03-24,build 17E192)。引用自 release notes 的功能:Swift Testing 現在支援透過 CGImageNSImageUIImageCIImage 加入 image attachments;Issue.record 接受 severity levels;部分 UI-test app crashes,特別是透過 XCUIApplication(bundleIdentifier:)XCUIApplication(url:) 互動的 apps,會以附帶 crashlogs 的 warnings 回報,而非讓測試失敗;String Catalog editor 新增 entries 的剪下/複製/貼上、移除語言、從既有語言預填翻譯,以及 BUILD_ONLY_KNOWN_LOCALIZATIONS 設定。 

  15. Apple Developer News,〈Xcode 26.4.1 (Build 17E202) Now Available〉,2026-04-16。僅含錯誤修正的 dot release,修正 iOS / macOS / visionOS 26.4 之前版本因缺少 symbols 導致的 MetricKit crash,以及 Swift async stack-allocation bug(swift_asyncLet_finish 中的「freed pointer was not the last allocation」)。 

  16. getsentry/XcodeBuildMCP v2.1.0 release,2026-02-23。新增 xcodebuildmcp init CLI command,可一步安裝 agent skills + MCP config,取代獨立的 install-skill.sh script。可自動偵測 Claude Code、Cursor 與 Codex;支援 --print(將 config 寫至 stdout,供不支援的 clients 使用)與 --uninstall(移除)。 

  17. InfoQ,〈Apple Adds Context Window Management to Foundation Models〉,2026年3月。記錄新的 SystemLanguageModel.contextSizetokenCount(for:) APIs,並確認 @backDeployed(before: iOS 26.4) annotations。取代先前社群猜測的 4096-token hardcode。 

  18. 檔案數量來自 2026-04-27 針對 8 個私人 app repositories 各自執行 find . -name '*.swift' -not -path '*/Tests/*' | wc -l 的結果。已排除 test files。總數與 §The Portfolio 中的各 app breakdown table 內部一致。 

  19. 主觀 wall-clock 估算,並非相對於 control group 的測量。3-5x 數字來自作者回想:2026 年 agent-assisted features 與同一 codebases 在採用 agent workflow 前所交付的同等 solo features 之間的 time-to-feature 比較。請將其視為完成 MCP + hook setup 後可期待情況的 heuristic,而非 benchmark。 

NORMAL ios-agent-development.md EOF