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

使用 AI Agent 開發 iOS 應用程式:實務指南

# 使用 AI Agent 開發 iOS 應用程式

words: 4537 read_time: 34m updated: 2026-04-14 23:57
$ less ios-agent-development.md

重點摘要:三個代理程式執行環境現已能為 iOS 產出程式碼:Claude Code CLI 搭配 MCP、Codex CLI 搭配 MCP,以及 Xcode 26.3 內建的 Intelligence 代理程式。兩個 MCP 伺服器(XcodeBuildMCP 提供 59 項工具,Apple 的 xcrun mcpbridge 提供 20 項工具)讓代理程式能結構化地存取建置、測試、模擬器與除錯功能。本指南涵蓋實際的 CLAUDE.md 模式、hook 設定,以及對哪些有效、哪些會出問題的誠實評估——資料來自 8 個正式上線的 iOS 應用程式,共 293 個 Swift 檔案。代理程式擅長 SwiftUI 視圖、SwiftData 模型、重構及建置錯誤診斷,但在 .pbxproj 修改、程式碼簽署和視覺除錯方面表現不佳。「代理程式能寫 Swift」到「代理程式能交付 iOS 應用程式」之間的鴻溝,靠的是設定來彌補,而非提示詞。

我用 AI 程式碼代理程式建構了 8 個 iOS 應用程式。這些不是原型——而是上架 App Store 的正式應用程式,包含 HealthKit 整合、Metal 著色器、SpriteKit 物理引擎、iCloud 同步、Live Activities、Game Center 排行榜,以及橫跨 iOS、watchOS 和 tvOS 的多平台目標。這些應用程式中的每一行 Swift 程式碼,不是由代理程式撰寫、我來審查,就是由我撰寫、代理程式來重構。以我的估算,比例大約是 85 比 15,代理程式佔多數。

本指南是我當初開始時希望能有的參考資料。內容涵蓋完整技術棧:該用哪個代理程式執行環境、如何設定 MCP 伺服器以進行結構化的建置存取、CLAUDE.md 該寫什麼、哪些 hook 能防止代理程式破壞您的 Xcode 專案,以及——最關鍵的——代理程式在哪些地方會失敗,需要您親自接手。

重點摘要

給初次接觸 AI 代理程式的 iOS 開發者:

  • 從 Claude Code CLI + XcodeBuildMCP 開始。這是目前最成熟的執行環境,擁有最完整的 MCP 工具覆蓋。安裝兩個指令、在專案中加入 CLAUDE.md,代理程式就能自主建置、測試和除錯,無需您手動複製錯誤訊息。
  • 絕對不要讓代理程式修改 .pbxproj。這是最重要的一條規則。設定一個 PreToolUse hook 來阻擋對 .pbxproj.xcodeproj/ 的寫入,能為您省下數小時的復原時間。
  • CLAUDE.md 是代理程式的新人指南。在 CLAUDE.md 上投入的每一小時,能為您省下十小時修正代理程式錯誤的時間。

給已有代理程式經驗、想將 iOS 加入工作流程的開發者:

  • MCP 徹底改變了 iOS 的建置迴圈。在 MCP 出現之前,代理程式能寫 Swift 卻無法驗證是否能編譯。有了 XcodeBuildMCP,代理程式能撰寫程式碼、執行建置、讀取結構化錯誤、修正問題並執行測試——全程自動化。
  • 三個執行環境各有所長。Claude Code CLI 適合深度代理程式工作階段,Codex CLI 適合無介面批次作業,Xcode 26.3 內建代理程式則適合不離開 IDE 的快速行內修正。
  • Hook 基礎架構可直接沿用。您現有的 PostToolUse 格式化工具、PreToolUse 阻擋器和測試執行 hook,在 iOS 專案中只需些微路徑調整即可正常運作。

給評估 AI 輔助 iOS 開發的技術主管:

  • 代理程式的成效取決於專案文件品質,而非專案規模。一個擁有詳盡 CLAUDE.md 的 63 個檔案專案,產出的代理程式結果優於一個沒有 CLAUDE.md 的 14 個檔案專案。
  • .pbxproj 的界線不可妥協。代理程式無法可靠地編輯 Xcode 專案檔。工作流程中必須保留手動將檔案加入 Xcode target 的步驟。
  • 誠實ROI:代理程式能處理 70-80% 的實作工作。剩下的 20-30%——視覺打磨、簽署、效能調校、App Store 上架——仍需要人的判斷。

選擇您的路徑

您的需求 前往
首次設定 MCP MCP 設定:完整組態指南——安裝兩個伺服器、驗證、設定代理程式
為 iOS 專案撰寫 CLAUDE.md iOS 專案的 CLAUDE.md 模式——來自 8 個應用程式的實際範例
比較三個代理程式執行環境 iOS 的三個代理程式執行環境——Claude Code vs. Codex vs. Xcode 原生
了解代理程式能做什麼、不能做什麼 代理程式的強項代理程式的弱項
設定 iOS 開發用的 hook iOS 開發的 Hook——儲存時格式化、.pbxproj 保護、測試執行器
深度參考(本頁) 繼續閱讀——從設定到進階模式一應俱全

如何使用本指南

這是一份超過 3,000 行的參考文件。請根據您的經驗程度選擇起點:

經驗程度 從這裡開始 接著探索
iOS 與代理程式皆為新手 先決條件MCP 設定您的第一次代理程式工作階段 CLAUDE.md 模式哪些有效/無效
iOS 開發者,初次使用代理程式 三個執行環境MCP 設定CLAUDE.md Hook架構模式
代理程式使用者,初次接觸 iOS 架構模式代理程式的弱項CLAUDE.md 框架專屬上下文進階工作流程
兩者皆有經驗 進階工作流程Hook多平台模式 執行環境比較矩陣作品集

目錄

  1. 作品集:8 個應用程式、293 個檔案
  2. 先決條件
  3. iOS 的三個代理程式執行環境
  4. MCP 設定:完整組態指南
  5. iOS 專案的 CLAUDE.md 模式
  6. 您的第一次代理程式工作階段
  7. 代理程式在 iOS 中的強項
  8. 代理程式在 iOS 中的弱項
  9. iOS 開發的 Hook
  10. 適合代理程式的架構模式
  11. 框架專屬上下文
  12. 多平台模式
  13. 進階工作流程
  14. 真實案例研究
  15. 代理程式輔助的專案生命週期
  16. 設定代理程式定義
  17. 代理程式輔助 iOS 的測試模式
  18. iOS 專案的上下文視窗管理
  19. 疑難排解
  20. 代理程式在 iOS 中的常見錯誤
  21. 誠實的評估
  22. 常見問題
  23. 快速參考卡
  24. 參考資料

相關資源

主題 資源
Xcode 的 MCP 設定(較短的部落格文章) 兩個 MCP 伺服器讓 Claude Code 成為 iOS 建置系統
Claude Code CLI 完整參考 Claude Code CLI:完整指南
Codex CLI 參考 Codex CLI:完整指南
Hook 系統深入解析 Claw 剖析:84 個 Hook 作為編排層
代理程式架構模式 代理程式架構指南

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

在深入設定之前,先介紹本指南的實務基礎。這些並非玩具專案——它們橫跨五個 Apple 框架、三個平台,涵蓋 iOS 開發的完整複雜度,從 14 個檔案的健身追蹤器到 63 個檔案的多平台冥想計時器。

App 技術堆疊 檔案數 複雜度
Banana List SwiftUI + SwiftData + iCloud Drive 同步 + MCP 伺服器供 Claude Desktop 使用 53 完整 CRUD、iCloud 同步、自訂 MCP 伺服器將 App 資料暴露給 Claude Desktop
Ace Citizenship SwiftUI 學習 App + FastAPI 後端 26 客戶端-伺服器架構、REST API 整合、測驗引擎
TappyColor SpriteKit 配色遊戲 30 遊戲迴圈、物理引擎、觸控處理、粒子特效
Return Zen 冥想計時器——iOS 26+、watchOS、tvOS 63 HealthKit、Live Activities、Watch 延長執行時間、TV 焦點導航、iCloud 工作階段同步
amp97 Metal 著色器 + 音訊視覺化 41 自訂 Metal 渲染管線、音訊分析、即時 GPU 計算
Reps SwiftUI + SwiftData 健身追蹤 14 最小可行 App、簡潔的 SwiftData 模式
Water SwiftUI + SwiftData + Metal + HealthKit 水分追蹤 34 Metal 流體模擬、HealthKit 飲水記錄、小工具
Starfield Destroyer SpriteKit + Metal 太空射擊遊戲 32 99 關卡、8 艘太空船、Game Center 排行榜、Metal 後製處理

為什麼檔案數量很重要: Agent 的效能取決於專案的可讀性,而非規模大小。Return(63 個檔案)比 amp97(41 個檔案)產出更好的 Agent 結果,因為 Return 擁有詳盡的 CLAUDE.md,包含檔案註解、架構圖和明確的模式說明。而 amp97 的 Metal 著色器無論文件品質如何,本質上就較難讓 Agent 推理。


先決條件

在為 iOS 開發設定任何 Agent 執行環境之前:

必要條件: - macOS 15+(Sequoia)或 macOS Tahoe - 已安裝並設定 Xcode 26.3+(已接受授權合約、已下載平台) - 至少安裝一個 iOS Simulator 執行環境 - Anthropic API 帳號(用於 Claude Code)或 OpenAI 帳號(用於 Codex)

建議條件: - 已安裝 SwiftFormatbrew install swiftformat)——用於儲存時自動格式化的 Hook - 已安裝 SwiftLintbrew install swiftlint)——非必要,但有助於風格規範 - 熟悉終端機操作——三種執行環境都需要從命令列操作或與其整合

驗證 Xcode 安裝:

# Check Xcode version
xcodebuild -version
# Expected: Xcode 26.3 or later

# 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

最適合: 深度實作工作——建置新功能、跨多檔案重構、除錯複雜問題、自主執行建置-測試-修復迴圈。Claude Code 的 1M 上下文視窗(搭配 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 生態系較小(經測試的社群伺服器較少) - Hook 系統可用(v0.119.0+),但成熟度不及 Claude Code——事件類型較少,且缺少條件式 if 欄位

何時選擇 Codex 而非 Claude Code 來開發 iOS:

當您需要模型多樣性時可選擇 Codex——讓第二個 Agent 審查第一個寫的程式碼,能捕捉到不同類別的錯誤。協作工作流程(Claude 建置、Codex 審查)對 iOS 開發特別有效,因為對一個模型家族看似正確的 SwiftUI 模式,可能存在另一個模型才能發現的細微問題。Metal 著色器和並行處理模式尤其受益於雙模型審查。

3. Xcode 26.3 原生 Agent

簡介: 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 僅操作當前檔案或選取範圍,無法跨整個專案運作 - 無子 Agent 委派——複雜的多步驟任務無法平行處理 - 無 MCP 伺服器設定——Agent 僅使用 Xcode 內建工具

何時使用 Xcode 原生 Agent:

適合快速、範圍明確的編輯,避免切換到終端機的額外負擔。例如「為這個 Model 新增一個計算屬性」、「為這個函式撰寫單元測試」、「將這個 View 重構為使用 @Observable」。這類任務只涉及一到兩個檔案,不需要建置-測試循環。

凡是需要建置、測試、多檔案重構或自主錯誤修正的任務,請使用搭配 MCP 的 CLI Agent。

執行環境比較矩陣

功能 Claude Code CLI Codex CLI Xcode 26.3 原生
MCP 支援 完整(79 個工具) 完整(79 個工具) 僅限 Xcode 內建工具
Hook 系統 有(成熟) 有(基礎,v0.119.0+)
CLAUDE.md / 專案設定 codex.md 等效方案
自主建置-測試-修復 有(透過 MCP) 有(透過 MCP) 部分(僅限行內)
子 Agent 委派 有(最多 10 個平行)
上下文視窗 1M Token(Opus 4.6) 依模型而異 依提供者而異
多檔案操作 完整程式碼庫存取 完整程式碼庫存取 當前檔案/選取範圍
.pbxproj 保護 透過 Hook 手動 不適用(原生使用 Xcode)
儲存時格式化 透過 PostToolUse Hook 外部工具 Xcode 設定
離線功能
計費模式 Anthropic API 用量 OpenAI API 用量 提供者 API 用量

建議做法: 以 Claude Code CLI 作為主要執行環境。Xcode 26.3 原生 Agent 用於快速行內編輯。Codex CLI 用於審查和批次操作。三者互補而非競爭。


MCP 設定:完整配置指南

MCP(Model Context Protocol)能將 AI 代理從「寫完 Swift 然後祈禱你去編譯」轉變為「寫完 Swift、自動編譯、讀取結構化錯誤、再自行修正」。本節比部落格文章更深入——涵蓋兩個伺服器、所有安裝方式、驗證流程,以及確保工具確實被使用的代理配置。

XcodeBuildMCP:59 個無頭 iOS 開發工具

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

完整工具清單(59 個工具,橫跨 8 大類別):

類別 工具 功能說明
專案探索 discover_projs, list_schemes, list_targets 尋找 .xcodeproj/.xcworkspace 檔案,列出可用的 scheme 和 target
建置 build_sim, build_device, build_mac 建置並輸出按檔案與行號分類的結構化 CLI 錯誤與警告
測試 test_sim, test_device 執行測試並回傳每個方法的通過/失敗結果
模擬器生命週期 list_sims, boot_sim, shutdown_sim, open_sim, session_set_defaults 建立、啟動、管理及設定模擬器
裝置管理 list_devices, install_device, launch_device 實機部署與管理
除錯 debug_attach_sim, debug_attach_device, debug_breakpoint, debug_stack, debug_variables, debug_eval, debug_continue, debug_step, debug_detach 完整 LLDB 整合,支援中斷點與變數檢視
UI 自動化 snapshot_ui, screenshot, tap, swipe, type_text 自動化互動與視覺擷取
專案鷹架 create_project, add_file, add_package 建立專案與新增相依套件

日常開發中最重要的工具:

  1. build_sim——這是您會呼叫數百次的工具。它回傳按檔案、行號和嚴重程度分類的 CLI 錯誤。代理讀取錯誤後,自動導航到對應檔案並修正,完全不需您動手。

  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:20 個橋接 Xcode 的工具

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 則沒有此限制。

工具清單(20 個工具,橫跨 5 大類別):

類別 工具 功能說明
檔案操作 XcodeRead, XcodeWrite, XcodeUpdate, XcodeGlob, XcodeGrep 在 Xcode 專案脈絡中讀寫檔案
建置與測試 BuildProject, GetBuildLog, RunAllTests, RunSomeTests 使用 Xcode 內部建置系統進行建置與測試
診斷 XcodeListNavigatorIssues, XcodeRefreshCodeIssuesInFile 即時程式碼診斷(不僅限於建置錯誤)
程式碼與文件 ExecuteSnippet, DocumentationSearch Swift REPL 執行與 Apple 文件搜尋
預覽 RenderPreview 無頭 SwiftUI 預覽渲染

Apple MCP 獨有的工具(XcodeBuildMCP 中不提供):

  1. DocumentationSearch——搜尋 Apple 開發者文件,包括 WWDC 議程。查詢 Apple API 問題時,比網路搜尋更快且更可靠。詢問「HKQuantityType(.dietaryWater) 是否有效?」即可從原始來源獲得確切答案。

  2. ExecuteSnippet——在專案脈絡中執行 Swift REPL。代理可驗證 API 行為、測試型別轉換、驗證表達式,無需建置完整應用程式。

  3. RenderPreview——以無頭模式渲染 SwiftUI 預覽。代理可檢查視圖是否能無錯渲染,但無法評估視覺正確性(渲染結果以資料形式回傳,並非視覺化檢視)。

  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(非結構化輸出,浪費上下文 token)或使用網路搜尋 Apple 文件(較慢且較不可靠)。

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

## 建置與測試——務必使用 MCP

所有建置操作請優先使用 MCP 工具,而非原始 shell 指令:

- **建置**`build_sim` / `build_device`(而非透過 Bash 執行 `xcodebuild`- **測試**`test_sim` / `test_device`(而非透過 Bash 執行 `xcodebuild test`- **模擬器**`list_sims``boot_sim``open_sim`(而非透過 Bash 執行 `xcrun simctl`- **除錯**`debug_attach_sim``debug_stack``debug_variables`
- **Apple 文件**`DocumentationSearch`(而非用 WebSearch 查詢 Apple API)
- **Swift 驗證**`ExecuteSnippet`(而非透過 Bash 執行 `swift`- **預覽**`RenderPreview` 可進行無介面的 SwiftUI 驗證

MCP 回傳結構化的 JSON。Bash 回傳的是非結構化文字。
結構化資料意味著消耗更少的 token,並能更精準地診斷錯誤。

這項指引確保代理程式優先選用 MCP 工具。若缺少此指引,您會觀察到代理程式透過 Bash 建構冗長的 xcodebuild 指令,耗費數千個上下文 token 來解析輸出,有時甚至會誤判實際錯誤。


iOS 專案的 CLAUDE.md 模式

CLAUDE.md 是專案中對代理程式輔助開發最重要的檔案。它是代理程式的入職文件——差別就在於一位讀過架構文件的新進人員,與一位只能憑猜測行事的新進人員。

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

必備章節

每份 iOS CLAUDE.md 都需要這六個章節,其餘皆為選配。

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

為何重要:代理程式在撰寫任何程式碼之前,必須先知道部署目標。針對 iOS 17 的代理程式會使用 NavigationView@ObservedObject;針對 iOS 26 的代理程式則會使用 NavigationStack@Observable。Bundle ID 對 entitlements 和 HealthKit 設定至關重要。Swift 版本決定了並行模型(async/await 或 completion handlers、嚴格並行或寬鬆模式)。

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


每個檔名後方的行內註解並非裝飾,而是您能撰寫的最高槓桿文件。當代理程式決定在哪裡新增功能時,這些註解能引導它在第一次嘗試就找到正確的檔案,而非逐一讀取每個檔案來理解專案架構。

反面模式: 列出檔案卻不加註解。TimerManager.swift 無法告訴代理程式它究竟負責狀態、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:

xcodebuild -scheme Return -destination 'platform=iOS Simulator,name=iPhone 16 Pro' test

Run tvOS tests:

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.

即使代理程式應優先使用 MCP,仍應保留原始指令。這些原始指令可作為備用文件,並明確標示 scheme 名稱與目標裝置。

#### 4. 關鍵模式與規則

```markdown

## 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

這些模式能防止代理程式引入不一致性。若缺少明確的模式文件,代理程式有時會在某個檔案使用 ObservableObject、在另一個檔案使用 @Observable,或者建立新的設定機制而非使用現有的 Settings.shared 單例。

5. 代理程式絕對不可做的事

## 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

明確的禁止事項比隱含的期望更為有效。代理程式對否定約束的遵循度高於正面建議,因為前者是二元判斷(做或不做),而非啟發式判斷(偏好這個、有時用那個)。

6. 框架特定上下文

此章節因應用程式而異。任何具有非顯而易見設定的框架都應包含此章節:

HealthKit 應用程式:

## 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 應用程式:

## 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 應用程式:

## 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 應用程式:

## 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)

以下是一個加了註解的範例,展示六個章節如何在一個中等複雜度的應用程式中協同運作。這是我為 Banana List 所使用的 CLAUDE.md 模式——一個擁有 53 個檔案的購物清單應用程式,具備 iCloud 同步功能以及自訂的 MCP 伺服器,將應用程式資料暴露給 Claude Desktop:

# 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

## 檔案結構

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 模型

### 關聯關係
- `GroceryList` 擁有多個 `GroceryItem`(級聯刪除)
- `GroceryItem` 屬於一個 `GroceryList`(必填)
- `GroceryItem` 可選擇性關聯 `Category`
- `Category` 擁有多個 `GroceryItem`(刪除時設為 null

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

查詢模式

  • 列表:@Query(sort: \GroceryList.name) var lists: [GroceryList]
  • 進行中項目:@Query(filter: #Predicate { !$0.isCompleted })
  • 依分類篩選:擷取後在記憶體中過濾(受限於 SwiftData 謂詞的限制)

建置與測試

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

建議優先使用 MCP 工具(build_simtest_sim),而非直接執行原始指令。

關鍵模式

Observable + SwiftData

  • SwiftData 的 @Model 類別自動具備 Observable 特性
  • 切勿在 @Model 類別上加入 @Observable(重複宣告,會產生警告)
  • 在表單中使用 @Bindable 進行模型屬性的雙向綁定
  • 視圖中使用 @Query,非視圖程式碼中則使用 modelContext.fetch()

iCloud 同步

  • 透過 SwiftData CloudKit 整合自動完成
  • 衝突解決:以最後寫入為準(CloudKit 預設行為)
  • 同步狀態透過 CloudSyncManager.shared.syncState 公開
  • 測試同步時,在兩台模擬器上使用相同 iCloud 帳號執行

MCP 伺服器架構

  • 以本機 WebSocket 伺服器形式運行於連接埠 8765
  • 提供 6 個工具:listAll、getList、createList、addItem、completeItem、deleteItem
  • Claude Desktop 透過 ~/.config/claude-desktop/config.json 中的 MCP 設定進行連線

規則

  • 絕對不要修改 .pbxproj 或 .xcodeproj 內容
  • 絕對不要在未更新 SampleData.swift 的情況下更改模型結構
  • 絕對不要使用 ObservableObject——SwiftData 模型已具備 Observable 特性
  • 絕對不要使用 @StateObject——搭配 @Observable 類別時請使用 @State
  • 絕對不要使用 NavigationView——一律使用 NavigationStack
  • 絕對不要在 @Model 類別上加入 @Observable 巨集
  • 務必使用 @Bindable 進行表單中模型屬性的綁定
  • 務必在兩台模擬器實例上測試 iCloud 同步變更
### 實際範例 CLAUDE.md:Reps(極簡 SwiftData 應用程式——14 個檔案)

小型專案的 CLAUDE.md 可以簡潔扼要。以下是 Reps 的範例,一款僅含 14 個檔案的健身追蹤器。請注意即使是簡短的 CLAUDE.md,仍涵蓋了全部六個必要章節:

```markdown
# 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
僅用 40 行 CLAUDE.md 便完整描述了一個 14 檔案的專案。撰寫只需 10 分鐘,卻能省下數小時的 Agent 困惑。

### 實際範例 CLAUDE.md:Starfield Destroyer(SpriteKit + Metal——32 個檔案)

遊戲專案需要更多框架相關的上下文資訊。Agent 必須理解場景圖、物理類別與遊戲狀態機:

```markdown
# 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

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

## 規則

- 絕對不要修改 .pbxproj
- 絕對不要修改 PhysicsCategory 位元遮罩(會破壞所有碰撞偵測)
- 在未理解算繪順序的情況下,絕對不要變更場景層級的 z-ordering
- 絕對不要在未同步更新 Swift  Metal 參照的情況下修改 ShaderTypes.h
- 新增敵人時應繼承 EnemyShip,而非直接修改它
- 子彈池化:透過 removeFromParent() + 重新加入來回收,絕不重新配置新物件
- Game Center:提交分數前務必檢查 isAuthenticated

實際的 CLAUDE.md:amp97(Metal + 音訊視覺化 — 41 個檔案)

Metal 專案需要最多框架專屬的上下文,因為代理程式無法驗證視覺輸出:

# 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 個檔案** | 身份識別 + 檔案清單 + 規則 | Reps14 個檔案):基本 SwiftData 模式建置指令禁止事項 |
| **中型20-40 個檔案** | + 框架上下文 + 關鍵模式 | TappyColor30 個檔案):SpriteKit 場景層級物理類別遊戲迴圈 |
| **大型40+ 個檔案** | + 架構圖 + 關係對應 + 多目標資訊 | Return63 個檔案):跨平台架構工作階段同步圖各平台差異 |
| **特化型Metal/GPU** | + 管線圖 + 共用型別定義 + 緩衝區配置 | amp9741 個檔案):算繪管線階段uniform 結構緩衝區管理 |

過度撰寫文件的成本幾乎為零代理程式會略過不需要的內容)。文件不足的代價卻很高代理程式會自行發明與程式碼庫相衝突的模式)。

### CLAUDE.md 檢查清單

在為 iOS 專案建立或審核 CLAUDE.md 請使用此檢查清單

- [ ] 已指定 Bundle ID 與部署目標
- [ ] 已標明 Swift 版本與架構模式
- [ ] 檔案結構附有用途說明
- [ ] 建置指令包含正確的 scheme  destination
- [ ] 測試指令包含正確的 scheme  destination
- [ ] 已註明 MCP 偏好(「優先使用 build_sim 而非 xcodebuild」)
- [ ] @Observable 規則絕不使用 ObservableObject
- [ ] NavigationStack 規則絕不使用 NavigationView
- [ ] .pbxproj 禁止修改
- [ ] 框架專屬上下文HealthKit 權限SwiftData 關聯SpriteKit 層級Metal 管線
- [ ] 平台可用性防護已記載#if canImport#if os
- [ ] 關鍵的單例與共用模式已記載
- [ ] 已知限制或陷阱已記載

---

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

在設定好 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 內容,請確認檔案位於專案根目錄(與 `.xcodeproj` 或 `Package.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 中規則發揮作用的結果若沒有該規則代理程式會嘗試修改專案檔案極可能導致檔案損毀

---

## AI 代理在 iOS 開發中的優勢

以下是代理能穩定產出正確可直接上線的成果且僅需極少人工審查的任務類型

### SwiftUI 視圖與修飾器

代理對 SwiftUI 宣告式語法具備深厚的模式識別能力視圖組合修飾器鏈狀態綁定與佈局——這些都能良好對應代理的訓練資料因為 SwiftUI  API 介面文件完善模式高度一致

**代理表現優異的領域**
- 根據描述建構新視圖(「建立一個包含 XYZ 開關的設定頁面」)
- 套用修飾器鏈(`.glassEffect()`、`.sensoryFeedback()`、`.navigationTitle()`)
- 轉換佈局模式VStack  LazyVGridList  ScrollView
- 實作 `@Bindable` 表單綁定至 SwiftData 模型
- 建立含範例資料的預覽提供者

**能產出優質結果的提示詞範例**

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.

具體程度至關重要。「建立一個設定視圖」只會產出通用結果;「建立一個符合 SettingsSheet.swift 現有模式的 SettingsView」則能產出與您程式碼庫一致的輸出。

### SwiftData 模型與查詢

代理能可靠處理 SwiftData  `@Model` 巨集、關聯與 `@Query` 模式。該框架的宣告式本質(類似 Django ORM  SQLAlchemy)與代理在眾多程式碼庫中學習到的模式高度契合。

**代理表現優異的領域:**
- 定義含關聯的 `@Model` 類別
- 撰寫含排序描述器與述詞的 `@Query`
- 透過 `modelContext` 實作 CRUD 操作
- 不同架構版本間的遷移計畫
- 預覽資料與測試固件

**代理需要引導的領域:**
- 複雜的 `#Predicate` 表達式(SwiftData 的述詞 DSL 有其限制,代理未必全然知曉——建議在 CLAUDE.md 中記錄已知限制)
- CloudKit 同步設定(透過 SwiftData 可自動完成,但代理可能嘗試手動實作同步)

### 單元測試

代理撰寫的 iOS 專案單元測試品質穩定優良。代理熟悉 XCTest 模式、非同步測試方法,以及 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()`、適當的斷言,以及針對計時器測試的非同步處理。

### 重構與模式套用

代理擅長機械式重構:將視圖抽取為元件、將 `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.

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

### 透過 MCP 診斷建置錯誤

藉由結構化的 MCP 輸出,代理診斷建置錯誤的速度往往超越多數開發者。代理讀取錯誤 JSON、精確定位檔案與行號、理解錯誤訊息並套用修復——通常一次互動即可完成。

**代理可自主修復的錯誤:**
- 缺少匯入
- 型別不匹配
- 協定遵循缺漏
- 已棄用的 API 用法(附替代方案)
- 缺少必要的初始化參數
- 存取控制違規

**代理需要協助的錯誤:**
- 模糊的型別解析(多個模組定義相同型別)
- 複雜的泛型約束失敗
- 巨集展開錯誤(代理無法檢視展開後的巨集輸出)

### 模擬器管理

代理透過 MCP 能妥善處理模擬器的生命週期:

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

代理會呼叫 `list_sims` 尋找可用的執行環境、`boot_sim` 啟動模擬器、`build_sim` 建置並安裝應用程式,以及 `screenshot` 擷取畫面——全部透過結構化的 MCP 呼叫完成。

---

## 代理工具在 iOS 開發中的不足之處

坦誠盤點代理工具力有未逮的領域。明確這些界限,能避免不必要的挫折與 token 浪費。

### .pbxproj 檔案修改——絕對禁止

這是 iOS 代理開發中最重要的一條規則。`.pbxproj` 檔案是 Xcode 的專案設定檔——一個包含 UUID 參照、建構階段列表及目標成員資訊的結構化文字檔。名義上可供人類閱讀,但實際上 AI 代理幾乎無法正確解析。

**代理工具為何無法處理 .pbxproj:**
- 該檔案採用自訂格式(非 JSON、非 YAML、非 XML),且位置具有語義意義
- 每筆項目皆透過 UUID 交叉參照——新增一個檔案需要同步更新 3  5 個不同區段
- 一個字元的錯位就會導致整個專案檔損毀
- Xcode  .pbxproj 的合併衝突解決機制本身已十分脆弱——代理的編輯只會雪上加霜

**當代理編輯 .pbxproj 時會發生什麼:**
1. 編輯看似成功(代理回報「檔案已更新」)
2. Xcode 拒絕開啟專案(「專案檔已損毀」)
3. 您花費 15  60 分鐘從 git 歷史記錄中復原
4. 您學會加上 PreToolUse hook(請參閱 [Hooks](#hooks-for-ios-development))

**正確的工作流程:** 代理負責建立 Swift 檔案,您手動將其加入 Xcode 專案(拖曳至 Xcode,或使用 File > Add Files)。每個檔案只需 5 秒,卻能省下數小時的復原時間。

**若使用 Swift Package Manager 專案:** 此限制的影響較小。`Package.swift` 是標準的 Swift 檔案,代理可以可靠地編輯。若您的專案完全採用 SPM(無 .xcodeproj),代理便能管理完整的專案結構。

### 複雜的 Interface Builder / Storyboard 編輯

若您的專案使用 Interface Builder(`.xib` 檔案)或 Storyboard(`.storyboard` 檔案),代理無法有效編輯這些檔案。它們是包含自動產生的 UUID、約束參照及 outlet 連接的 XML 檔案,設計上供視覺化編輯使用,並非為文字編輯而生。

**因應做法:** 新視圖一律使用 SwiftUI。若專案中有舊版 Interface Builder 檔案,維持原樣不動,新的 UI 全部以 SwiftUI 建構。

### 效能最佳化

代理能寫出正確的程式碼,但不一定是高效能的程式碼。代理無法對應用程式進行效能分析、找出瓶頸或量測影格率。效能最佳化需要:

1. 使用 Instruments 進行效能分析(視覺化工具,代理無法存取)
2. 了解特定裝置的 GPU/CPU 特性
3. 以量測數據驅動的迭代式調整

**常見問題情境:**
- Metal 著色器最佳化(代理能寫出有效的 Metal 程式碼,但無法量測 GPU 影格時間)
- SwiftUI 視圖本體複雜度(代理可能建立深層巢狀視圖,導致重繪開銷)
- Core Data / SwiftData 查詢最佳化(代理寫出的查詢語法正確,但在大型資料集上可能效能不佳)

**因應做法:** 讓代理負責實作,您使用 Instruments 手動分析效能,再請代理針對您已找出的具體問題進行最佳化。

### 程式碼簽署與佈建描述檔

代理除了讀取錯誤訊息之外,無法除錯程式碼簽署問題。佈建描述檔管理、憑證建立、權限設定及 App Store 提交,本質上都是需要人工操作的流程,涉及 Apple Developer 入口網站、鑰匙圈存取及 Xcode 的簽署介面。

**代理看到的是:**「Signing for 'Return' requires a development team.

**代理看不到的是:** 您的憑證是否已過期、佈建描述檔是否包含該裝置、Bundle ID 是否與 App ID 相符、權限檔案是否正確。

**因應做法:** 所有簽署作業都在 Xcode  Signing & Capabilities 分頁中處理。不要要求代理除錯簽署問題。

### 複雜的 Metal 著色器除錯

代理能寫出語法正確的 Metal Shading Language(MSL),但無法驗證視覺輸出或除錯 GPU 端的問題。Metal 著色器在 GPU 上執行——代理沒有任何回饋機制來判斷著色器是否產生正確的視覺結果。

**代理在 Metal 方面能做到的:**
- 根據描述撰寫頂點與片段著色器
-  Swift 設定 Metal 渲染管線
- 建立用於資料平行運算的計算著色器
- 修正 `.metal` 檔案中的編譯錯誤

**代理在 Metal 方面做不到的:**
- 驗證著色器輸出的視覺正確性
- 除錯 GPU 效能(影格時間、佔用率、記憶體頻寬)
- 診斷視覺瑕疵(色帶、精度問題、色彩空間錯誤)
- 在不同 GPU 架構上測試(A 系列與 M 系列的行為差異)

**因應做法:** 在實體裝置上測試 Metal 著色器。模擬器的 Metal 實作無法代表裝置 GPU 的實際行為。請使用 Xcode  GPU Frame Capture 進行視覺化除錯。

### 視覺版面驗證

代理看不到您應用程式的 UI。代理能撰寫 SwiftUI 版面程式碼並驗證其可編譯,但無法判斷畫面呈現是否正確。偏移 10 像素的視圖、錯誤的字重、重疊的元素——這些都不會產生建構錯誤,也能通過所有邏輯測試。

**因應做法:** 以目視方式檢查 UI 變更。在 Xcode 中使用 SwiftUI Previews(或透過 Apple MCP 使用 `RenderPreview` 進行無頭渲染)來驗證版面。亦可考慮使用 swift-snapshot-testing 等函式庫進行快照測試,以自動偵測視覺回歸問題。

---

## iOS 開發的 Hooks 設定

Hooks 是在代理工作流程中特定時間點確定性執行的 shell 命令。它們是強制執行機制——區別在於「請不要編輯 .pbxproj」(代理可能忽略的建議)和「你無法編輯 .pbxproj」(硬性阻擋)之間的差異。

關於 hook 系統的背景知識,請參閱 [Claude Code hooks 教學](/blog/claude-code-hooks-tutorial)。本節涵蓋 iOS 專屬的 hook 模式。

### PreToolUse:阻擋 .pbxproj 寫入

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

```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)$|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'"
      }
    ]
  }
}

這提供兩項保證: 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. 在視圖中使用 @Query 實現響應式資料:@Query var items: [GroceryItem] 4. 在非視圖程式碼中使用 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
}

代理的並行處理指引: - 所有視圖模型標記為 @MainActor(防止資料競爭警告) - 所有非同步工作使用 async/await(不使用完成處理器) - 值型別加上 Sendable 以支援跨 actor 傳遞 - 在視圖中使用 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 中導航列自動採用玻璃材質。請勿以自訂材質手動重建玻璃效果——使用系統修飾器即可。」


框架特定注意事項

每個 Apple 框架都有代理使用上的特殊考量。本節涵蓋 8 款應用程式所使用的框架。

HealthKit

使用此框架的應用程式: Return、Water

HealthKit 需要謹慎處理權限請求與平台判斷:

// 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() 進行防護檢查 - 切勿假設已取得授權——每次寫入前都要確認 - 多平台程式碼使用 #if canImport(HealthKit)(HealthKit 在 tvOS 上不可用) - 不要在本地儲存超出 HealthKit 所提供的健康資料 - 在 Info.plist 中同時包含 NSHealthShareUsageDescriptionNSHealthUpdateUsageDescription

SpriteKit

使用此框架的應用程式: 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 序列與群組 - 設定物理體與碰撞偵測 - 實作遊戲狀態機 - 構建 HUD 疊加層

代理在 SpriteKit 方面的弱點: - 效能敏感的遊戲迴圈(代理容易在每幀加入不必要的運算) - 複雜的物理模擬(自訂物理比 SKPhysicsBody 更精確) - 粒子效果調校(屬於視覺層面,需反覆迭代)

Metal

使用此框架的應用程式: amp97、Water、Starfield Destroyer

Metal 是代理最容易遇到困難的框架。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 結構體定義(Swift 與 MSL 共用) - 渲染管線狀態的建立模式 - Buffer 索引及其用途 - 現有著色器清單及各自功能 - 已知的精度問題(half 與 float)

Live Activities

使用此框架的應用程式: 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

使用此框架的應用程式: 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

代理指引:「使用平台專屬框架時,一律加上 #if canImport()#if os() 防護。切勿假設某個框架在所有目標平台皆可用。」

各平台 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.

子代理在獨立的上下文視窗中探索文件與程式碼模式,回傳摘要後,由主會話負責實作建議方案。如此可避免研究過程佔用主要上下文。

跨應用程式模式套用

當多個 iOS 應用程式採用一致的模式時,代理可將模式從一個應用程式套用到另一個:

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 著色器和並行模式尤其寶貴,因為在這些領域中微妙的錯誤極易引入。

雙重審查能發現單一審查遺漏的問題:

問題類型 Claude 優勢 Codex 優勢
SwiftData 關聯循環 中等 強(GPT-4o)
@MainActor 隔離漏洞 中等
Metal 緩衝區對齊 中等 中等
保留循環偵測 強(Opus) 強(o3)
API 棄用感知 強(較新訓練資料) 中等
並行競態條件 強(捕捉不同模式)

雙重審查的目的不在於找出更多錯誤,而在於找出不同的錯誤。每個模型家族在模式辨識上有各自不同的失敗模式。

跨多個應用程式的批次操作

當框架或模式變更影響多個應用程式時:

# 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-permissions 旗標在非互動模式下為必要,但會繞過所有安全檢查。請確保 PreToolUse 鉤子已就位,以保護 .pbxproj 檔案。


實際案例研究

抽象建議說來容易。以下是來自這8個應用程式的具體場景,展示代理輔助iOS開發在實務中的運作方式——包括失敗的案例。

案例研究 1:為 Return 新增 TV App(成功)

任務: 為 Return 新增 tvOS target。Return 是一款冥想計時器,已有 iOS 和 watchOS 版本。TV 應用程式需要支援 Siri Remote 導航、大螢幕 UI,以及與 iOS 應用程式的設定同步。

代理表現出色的部分: - 讀取現有的 iOS TimerManager,建立了 TVTimerManager,省略了 Live Activities 和 HealthKit(tvOS 上不可用) - 建立自訂按鈕樣式以支援 Siri Remote 焦點導航(TVCapsuleButtonStyleTVCircleButtonStyle) - 打造 TVStepper 元件,以 +/- 按鈕取代滾輪選擇器(Siri Remote 無法使用滾輪選擇器) - 透過 App Groups(group.com.941apps.Return)實作設定同步 - 在共用程式碼中加入 #if os(tvOS) 條件編譯 - 透過 MCP 以 platform=tvOS Simulator,name=Apple TV 進行建置與測試

需要手動處理的部分: - 在 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 應用程式,在代理輔助下約3小時完成。若完全手動實作,預估需要1至2天。代理處理了約80%的程式碼,我負責那20%需要 Xcode UI 操作與手動測試的部分。

案例研究 2:amp97 中的 Metal Shader 除錯(部分失敗)

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

經過: 1. 代理撰寫了有效的 Metal shader 修改,新增 uEnergy uniform 和 HDR 色調映射 2. 程式碼編譯無誤 3. 在裝置上,視覺化畫面完全變白——強度係數高出10倍(3.5 而非 0.30) 4. 代理看不到白色畫面,因此沒有任何回饋訊號 5. 我以肉眼發現問題,要求代理降低係數 6. 代理降低了係數,但整體能量狀態機過於複雜,以不同方式破壞了視覺化效果 7. 最終完全還原——兩個 commit(67959edcda4830)在 869d914 中被 revert

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

此後我在 CLAUDE.md 中加入的內容: 「未經極度謹慎的係數測試,請勿嘗試修改示波器著色器的能量狀態。先前的嘗試因係數高出10倍而導致視覺化效果崩壞。」

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

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

代理的做法: 1. 讀取現有的 V1 模型定義 2. 建立包含新欄位和關聯的 V2 模型定義 3. 撰寫符合 SchemaMigrationPlan 協定的 GroceryMigrationPlan 4. 實作 V1toV2 遷移階段:設定預設值 quantity: 1category: nil 5. 更新所有視圖以支援新欄位 6. 更新 SampleData.swift 以供預覽使用 7. 透過 MCP 建置並執行測試——全部通過 8. 建立遷移專用的單元測試

成功關鍵: 代理之所以成功,是因為 SwiftData 遷移遵循定義明確的協定模式,在 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 單例,管理 NSUbiquitousKeyValueStore 以進行 iCloud 同步 3. 實作合併衝突解決(基於 UUID 的去重機制) 4. 新增 SessionHistoryView,具備平台專屬適配(iOS 上滑動刪除,tvOS 上焦點操作) 5. 在 iPhone 端為來自其他裝置的工作階段串接 HealthKit 同步

需要反覆迭代的部分: 初始實作未處理 iPhone 應用程式在背景啟動的情況(沒有前景通知來觸發同步)。代理需要明確的指引:「使用 NSUbiquitousKeyValueStore.didChangeExternallyNotification 在背景 KV 變更時觸發同步。」給予提示後,實作即告正確。

教訓: 當架構描述清晰時,代理能妥善處理多平台架構模式。iCloud 同步模式並非一目了然,但它遵循 Apple 有文件記載的模式,代理能夠理解。邊界情況(背景同步)則需要人類的領域知識,因為相關文件並不充分。

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

任務: 為太空射擊遊戲新增 Game Center 排行榜和成就系統。

代理表現出色的部分: - 在應用程式進入點實作 GKLocalPlayer.local.authenticateHandler - 建立 GameCenterManager,包含分數提交和成就回報方法 - 在所有 Game Center 操作前加入驗證狀態檢查 - 優雅地處理離線情況(無 Game Center 時仍可遊玩,重新連線後提交) - 建立與8艘太空船進度系統對應的成就定義

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


專案生命週期與代理

啟動新的 iOS 專案

使用代理輔助啟動新專案的最佳工作流程:

第一階段:人工設定(15至30分鐘) 1. 建立 Xcode 專案(File > New > Project) 2. 設定簽署與功能權限 3. 設定部署目標與支援的目標裝置 4. 新增所需的 entitlement(HealthKit、Game Center 等) 5. 建立初始 CLAUDE.md,寫入專案身份識別與規則

第二階段:代理實作(數小時至數天) 1. 代理建立資料模型(SwiftData、Core Data 或純 struct) 2. 代理依照文件記載的模式建構視圖 3. 代理在 manager/service 類別中實作業務邏輯 4. 代理撰寫單元測試 5. 透過 MCP 進行建置-測試-修正迴圈(自主運作)

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

維護現有專案

針對已建立的應用程式進行持續開發:

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 反映專案現狀的程度成正比。當您新增重要功能、變更架構模式或引入新框架時,請更新 CLAUDE.md。

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

任務 使用代理? 原因
新的 SwiftUI 視圖 代理擅長宣告式 UI
SwiftData 模型變更 定義明確、可測試
單元測試 機械式、基於模式
重構 系統化、跨檔案
建置錯誤診斷 是(透過 MCP) 結構化的回饋迴路
新增 Xcode target 需要 Xcode UI 和 .pbxproj 變更
簽署與佈建 基於入口網站,代理無法存取
視覺微調 需要人類的美學判斷
Metal shader 調校 需要裝置上的GPU測試
App Store 提交 需要入口網站和 Xcode Organizer
效能分析 需要 Instruments
無障礙審核 部分 代理可新增標籤,人工驗證 VoiceOver

設定 Agent 定義

若您使用 Claude Code 的 agent 定義系統(.claude/agents/),可建立一個 iOS 專用的 agent:

---
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 工作階段中,可透過 @ios-developer 引用此 agent。


Agent 輔助 iOS 開發的測試模式

Agent 在獲得明確指引時,能撰寫出品質優異的單元測試。以下是能產出最佳成果的模式。

測試檔案組織

# 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.

為何有效: 編號的驗收條件為 agent 提供了一份檢核清單。引用現有測試檔案確立了撰寫模式。指定 setUp() 的用法則能避免 agent 產生糾結混亂的測試狀態。

無效的測試提示詞:

Write tests for TimerManager.

這只會產出泛泛而談、深度不足的測試,遺漏邊界情況,也未必遵循專案的慣例。

非同步測試模式

針對計時器相關與非同步程式碼的測試:

// 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)
    }
}

需要提醒 agent 注意的關鍵模式: - 測試 @MainActor 類別的方法需加上 @MainActor - 使用 Task.sleep 或非同步操作的測試需標記 async throws - 時間相關的斷言要留有容差(使用1.1秒而非精確的1.0秒) - 以乾淨的 setUp() / tearDown() 確保測試隔離

快照測試

若需偵測視覺回歸,可考慮導入 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.

Agent 能正確設定快照測試,但無法審閱參考影像。您負責檢視初始快照,之後 agent 的測試便能在後續變更中捕捉視覺回歸問題。


iOS 專案的上下文視窗管理

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

iOS 檔案的 Token 消耗

檔案類型 典型大小 約略 Token 數
SwiftUI 視圖(簡單) 50-100 行 500-1,000
SwiftUI 視圖(複雜) 200-400 行 2,000-4,000
SwiftData 模型 30-80 行 300-800
管理器/服務類別 100-300 行 1,000-3,000
Metal 著色器(.metal) 50-200 行 500-2,000
單元測試檔案 50-200 行 500-2,000
CLAUDE.md 100-300 行 1,000-3,000
MCP 回應(建置) 不定 200-2,000
MCP 回應(測試) 不定 500-5,000

50個檔案的專案: 讀取所有檔案約消耗50,000至100,000個 token——遠在1M視窗的範圍之內。Agent 可將整個專案納入上下文。

100個以上檔案的專案: 需要選擇性地讀取。Agent 先讀取 CLAUDE.md(參照檔案結構標註),再依需求讀取特定檔案。這正是 CLAUDE.md 中檔案標註至關重要的原因——它引導 agent 直達正確的檔案,無需逐一讀取。

大型專案的策略

  1. 詳盡的 CLAUDE.md 檔案標註 — Agent 讀取檔案地圖後,可直接導航至相關檔案
  2. 子 Agent 委派 — 將探索與研究工作交由子 agent 處理(乾淨的上下文,僅回傳摘要)
  3. 精準的提示詞 — 「修改 SettingsView.swift 以新增一個開關切換」優於「更新設定」
  4. 工作階段界線 — 處理不相關的功能時,開啟新的工作階段,而非延續冗長的對話
  5. 使用 /compact — Claude Code 的壓縮指令能摘要對話內容並釋放上下文空間

MCP 的 Token 效率

支持採用 MCP 的一大有力論點:結構化的 JSON 回應所消耗的 token 遠少於原始 xcodebuild 輸出。

情境 原始 Bash Token 數 MCP Token 數 節省幅度
建置成功 3,000-10,000 200-500 85-95%
建置失敗(1個錯誤) 3,000-10,000 300-800 90-92%
測試結果(20項測試) 2,000-5,000 500-1,000 75-80%
模擬器列表 500-2,000 200-400 60-80%

在一次典型的開發工作階段中,經過10至20次建置循環,MCP 相較於原始 xcodebuild 可節省30,000至150,000個 token——這些省下的 token 可用於實際的程式碼推理。


疑難排解

「build_sim 失敗 — 找不到 scheme」

Agent 猜測了 scheme 名稱。解決方法:

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

或者在 CLAUDE.md 中明確加入 scheme 名稱:

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

「xcrun mcpbridge — command not found」

您需要 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 中」

在工作階段進行中註冊的 MCP 工具可能需要重新啟動才會出現。退出 Claude Code 並開始新的工作階段:

# 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」

「建置成功但代理程式回報失敗」

XcodeBuildMCP 會解析 xcodebuild 的輸出。若建置產生看似錯誤的警告(棄用警告常有此情況),代理程式可能會誤判結果。請檢查 MCP 回應中的實際狀態欄位。

「模擬器在啟動時當機」

關閉所有模擬器並重新啟動:

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 規則僅是建議,Hook 才是強制措施。若您未設定 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'"
      }
    ]
  }
}

規則說的是「請不要」,Hook 說的是「你不能」。


常見問題

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

Claude Code CLI 搭配 XcodeBuildMCP。它擁有最深度的 MCP 整合、最成熟的 hook 系統,以及 1M context window(Opus 4.6),能將整個 iOS 專案保留在工作記憶體中。建議從這裡開始,待工作流程成熟後,再加入 Codex 進行程式碼審查,以及 Xcode 原生代理程式處理快速的行內編輯。

需要同時使用兩個 MCP 伺服器嗎?

對多數開發者而言,單獨使用 XcodeBuildMCP 即可涵蓋 90% 的需求(建置、測試、模擬器、除錯)。若需要文件搜尋、Swift REPL 驗證或 SwiftUI 預覽渲染,再加入 Apple 的 Xcode MCP。隨時都能新增——兩個伺服器彼此獨立。

代理程式能從零開始建立 Xcode 專案嗎?

XcodeBuildMCP 包含 create_project 工具,可建立新的 Xcode 專案骨架。然而,對於正式的應用程式,建議先在 Xcode 中建立專案(確保簽章、功能和目標設定正確),再讓代理程式負責所有程式碼實作。花 5 分鐘使用 Xcode 的新專案精靈,能省下數小時處理代理程式產生的專案設定問題。

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

處理得相當好。Package.swift 是標準的 Swift 檔案,代理程式能可靠地讀取和編輯。新增相依套件、更新版本範圍、設定目標都沒問題。限制在於基於 .xcodeproj 的相依管理(Xcode 的套件解析介面)——這由 Xcode 管理,不應由代理程式編輯。

代理程式能提交到 App Store 嗎?

不行。App Store 提交涉及 Xcode 的 Organizer、描述檔、截圖、中繼資料,以及 App Store Connect 入口網站。這些都無法透過 MCP 或命令列工具讓代理程式有效操作。代理程式負責封存之前的所有工作——實作、測試、除錯和文件撰寫。最後一哩的提交仍需人工完成。

不過,代理程式可以協助撰寫 App Store 的中繼資料。請代理程式根據最新的變更撰寫應用程式說明、關鍵字和版本更新內容。這類文字生成正是代理程式的強項。

在代理程式輔助的 iOS 開發中,如何處理密鑰和 API 金鑰?

絕對不要提交密鑰。對於需要連接後端 API 的 iOS 應用程式:

  1. 使用 .xcconfig 檔案處理環境相關的設定
  2. .xcconfig 檔案加入 .gitignore
  3. 透過 Info.plist 建置設定參照設定值
  4. 在 CLAUDE.md 中記載所需的密鑰,但不包含實際值
## 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`.

代理程式知道金鑰的存在及使用位置,但永遠看不到實際值。

SwiftUI 動畫方面——代理程式能撰寫嗎?

代理程式在語法上能正確撰寫動畫程式碼,但無法視覺化驗證結果。簡單動畫(.animation(.spring()).transition(.slide)withAnimation { })能產生正確的結果。複雜的多步驟動畫若需要精確的時序控制,則需要視覺化的反覆調整,這超出代理程式的能力範圍。

有效的提示:「Add a spring animation when the timer transitions between states.」

無效的提示:「Make the timer animation feel satisfying.」(主觀判斷,需要視覺調校。)

代理程式如何處理錯誤處理模式?

表現優異。代理程式理解 Swift 的 do/catchResultasync throws 模式:

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

代理程式能產生結構完善的錯誤處理,並附帶適當的使用者導向訊息。偶爾會過度處理錯誤(捕捉應該向上傳播的例外),因此建議審查 catch 區塊。

能否使用代理程式實作無障礙功能?

部分可以。代理程式能正確地加入無障礙標籤、提示和特徵:

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 的導覽順序是否正確、測試動態字級縮放,或評估色彩對比度。請使用 Xcode 的 Accessibility Inspector 進行驗證。

代理程式如何處理 Core Data 遷移(若未使用 SwiftData)?

代理程式能撰寫 Core Data 遷移對應和模型版本,但手動的 Xcode 步驟(建立新模型版本、選擇目前版本)無法自動化。若您仍在使用 Core Data 而非 SwiftData,請在 CLAUDE.md 中記載模型版本歷程:

## Core Data Model 版本
- V1:初始版本(GroceryList、GroceryItem)
- V2:新增 Category 模型(目前版本)
- 遷移:V1→V2 採用輕量級自動遷移

Agent 如何處理 SwiftUI 預覽?

有兩種方式: 1. Apple Xcode MCP 的 RenderPreview 工具可在無頭模式下渲染預覽並回傳結果。Agent 能驗證預覽是否可編譯且無錯誤地渲染,但無法評估視覺上的正確性。 2. 基於建置的驗證透過 build_sim 確認預覽提供者可正常編譯。若預覽在執行時崩潰,建置仍會成功——崩潰僅在 Xcode 嘗試渲染預覽時才會顯現。

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

visionOS 與 Apple Vision Pro 呢?

同樣的模式適用。XcodeBuildMCP 支援 visionOS 模擬器,架構模式(@Observable、NavigationStack、SwiftData)完全相同。RealityKit 特有的程式碼(3D 內容、沉浸式空間、手部追蹤)與 Metal 面臨相同的限制——Agent 能撰寫正確的程式碼,但無法驗證空間輸出。

專案規模多大時 Agent 會開始力不從心?

上下文視窗大小是決定性因素。以 Opus 4.6 的 1M token 視窗而言,Claude Code 可同時在工作記憶中容納約 50-70 個 Swift 檔案。對於更大的專案,Agent 會透過檔案搜尋與選擇性讀取來處理程式碼庫的子集。100 個以上檔案的專案運作正常——Agent 只是按需讀取檔案,而非將所有內容保留在上下文中。

實際的限制不在於檔案數量,而在於程式碼庫的一致性。一個有詳盡文件且配備完善 CLAUDE.md 的 200 個檔案專案,比一個缺乏文件的 30 個檔案專案能產出更好的結果。

使用 Agent 進行 iOS 開發需要懂 Swift 嗎?

您需要具備審查 Agent 輸出及做出架構決策的能力。不必親手撰寫每一行程式碼,但必須對 Swift 有足夠的理解,才能在 Agent 做出錯誤選擇時及時發現——特別是在並行處理、記憶體管理與框架特定模式方面。Agent 是現有技能的 10 倍放大器,而非替代品。

Agent 如何處理 Swift 檔案的合併衝突?

Agent 能可靠地解決 Swift 原始碼檔案的合併衝突。標準的衝突標記(<<<<<<<=======>>>>>>>)所有 Agent 執行環境都能理解。然而,.pbxproj 檔案的合併衝突仍需手動解決——請勿要求 Agent 處理 .pbxproj 衝突。

使用 Agent 進行 iOS 開發的成本為何?

以 Anthropic 的 Max 方案(Opus 4.6、1M 上下文)為例,一般的 iOS 開發工作階段約 30-120 分鐘,處理 200K-800K token。MCP 工具呼叫的額外負擔極低(結構化的 JSON 回應相較於原始建置輸出更為節省 token)。成本與在其他程式碼庫執行 Claude Code 相當——iOS 開發的費用與網頁開發並無顯著差異。

可以在 UIKit 專案中使用 Agent 嗎?

可以,但 Agent 在 SwiftUI 中更為得心應手。UIKit 需要更多樣板程式碼、宣告式結構較少,且常涉及 Agent 無法編輯的 Interface Builder 檔案。若您有 UIKit 專案,建議讓 Agent 處理模型層與業務邏輯,UI 部分手動處理,或逐步將視圖遷移至 SwiftUI。

Agent 如何處理本地化?

Agent 能有效建立與編輯 .xcstrings(Xcode 字串目錄)檔案,包括新增本地化鍵值、提供翻譯,並維持跨語言的一致性。.xcstrings 檔案的結構化 JSON 格式對 Agent 十分友善。對於 .strings 檔案(舊格式),Agent 同樣表現出色——鍵值對格式簡單明瞭。


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:在閉包中產生循環參考

現象: Agent 建立的閉包以強參考捕獲 self,尤其常見於 Timer.publishNotificationCenter 及完成處理器中。

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

## 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 建立 @Observable 類別時未加上 @MainActor 隔離,導致 Swift 6.2 並行警告或在主執行緒以外更新 UI 時發生執行時崩潰。

預防方式:

## Concurrency Rule
ALL @Observable classes MUST be @MainActor:
```swift
@Observable
@MainActor
final class SomeManager { }
### 錯誤 4:使用含目標閉包的 NavigationLink

**現象:** Agent 使用已棄用的 `NavigationLink(destination:label:)` 而非型別安全的 `NavigationLink(value:)` + `.navigationDestination(for:)` 模式。

**預防方式:**
```markdown

## 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:硬編碼模擬器名稱

**現象:** Agent 在建置指令中寫死特定模擬器名稱(如「iPhone 16 Pro」),而該模擬器可能不存在於您的系統上。

**預防方式:** MCP 可處理此問題——`list_sims` 會探索可用的模擬器。在 CLAUDE.md 中:
```markdown

## 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 將新的視圖檔案建在專案根目錄而非 Views/ 子目錄,或將模型放入錯誤的群組。

預防方式: CLAUDE.md 中的檔案結構標註可引導正確的檔案放置。此外:

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

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

現象: Agent 在共用程式碼中使用 HealthKit,而該程式碼需為 tvOS 編譯(HealthKit 在 tvOS 不可用),或在 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 行工具函式即可解決的需求,建立了協定、協定擴展、具體實作、工廠模式及依賴注入容器。

預防方式: 加入簡潔性原則:

## 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 Agent 交付 8 款 iOS 應用程式後,以下是總結:

Agent 帶來的變革: 實作速度。過去需要數天的工作現在數小時即可完成。SwiftUI 視圖、SwiftData 模型、單元測試、重構——這些現在主要由 Agent 產出、人工審查。

Agent 未能改變的: 架構決策、視覺設計、效能優化,以及 App Store 提交。這些仍由人主導。

效率倍增是真實的,但有其上限。 我估計對於文件完善、MCP 與 hook 設定妥當的專案,生產力可提升 3-5 倍。缺乏文件且未配置 hook 的專案大概只有 1.5-2 倍——Agent 花費太多時間猜測而非建構。

最值得的投資: 花在 CLAUDE.md、hook 與 MCP 設定上的時間。每一小時的前置作業,都能省下大量修正 Agent 錯誤的時間。設定本身就是產品——Agent 是執行引擎。

最令我意外的: MCP 伺服器徹底改變了開發動態。在 MCP 之前,Agent 不過是恰好懂 Swift 的進階文字編輯器。在 MCP 之後,它們成為能撰寫、建置、測試、除錯並迭代的開發夥伴。結構化的回饋循環,正是「寫程式碼的 Agent」與「交付程式碼的 Agent」之間的關鍵差異。

我想告訴過去的自己: 從最小的應用程式開始(Reps,14 個檔案),先把 MCP 和 hook 的設定做好,寫一份詳盡的 CLAUDE.md,然後再將這些模式擴展到更大的專案。不要從 63 個檔案的多平台應用程式起步。基礎設施的投入不因專案規模而異——在小專案上做一次,然後複製到所有其他專案即可。

展望未來: Xcode 26.3 的原生 Agent 整合是起點,而非終點。Apple 推出 MCP 支援,意味著工具鏈正朝 Agent 優先的開發模式邁進。現在就投資於 Agent 友善的專案結構——乾淨的 CLAUDE.md 檔案、可測試的架構、自動化 hook——這些投資將隨工具進步而持續複利成長。

快速參考卡

安裝(一次性設定)

# 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-04-13 首次發布。涵蓋 8 款應用程式、3 種執行環境、MCP 設定、CLAUDE.md 模式、hooks 及案例研究。

參考文獻


  1. XcodeBuildMCP 預設包含 Sentry 遙測功能。該專案的隱私文件詳述傳送的資料內容:錯誤訊息、堆疊追蹤,某些情況下還包括檔案路徑。設定 XCODEBUILDMCP_SENTRY_DISABLED=true 環境變數可完全停用。 

  2. Anthropic,「Model Context Protocol Specification」,modelcontextprotocol.io/specification。MCP 規範定義了 JSON-RPC 傳輸協定、工具探索機制及資源協定,XcodeBuildMCP 與 Apple 的 Xcode MCP 皆依此實作。 

  3. XcodeBuildMCP,github.com/getsentry/XcodeBuildMCP。由 Sentry 維護的開源專案,提供 59 項工具,涵蓋模擬器、實機裝置、除錯及 UI 自動化工作流程。採用語意化版本控制並附變更紀錄。 

  4. Apple 將 Xcode MCP 伺服器納入 Xcode 26.3 智慧開發者工具計畫,將 MCP 定位為 AI 程式碼助手與 Xcode 工具鏈之間的介面層。詳見 Xcode Release Notes 官方文件。 

  5. Rudrank Riyam,「Exploring Xcode Using MCP Tools」,rudrank.com/exploring-xcode-using-mcp-tools-cursor-external-clients,2026年。獨立驗證了 Apple MCP 的工具數量、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。具備結構化工具存取的代理程式,表現顯著優於僅能使用非結構化 shell 指令的代理程式。此研究結果驗證了結構化 MCP 介面對代理程式效能的重要性。 

  7. Claude Code CLI 文件,code.claude.com。涵蓋 Hook 系統、MCP 設定、子代理委派及代理定義。 

  8. SwiftFormat,github.com/nicklockwood/SwiftFormat。用於 PostToolUse hooks 的 Swift 格式化工具,確保程式碼風格一致。 

  9. XcodeBuildMCP 官方網站,xcodebuildmcp.com。透過 CLI 輸出範例確認 59 項 MCP 工具。工具類別包括:模擬器、實機裝置、除錯及 UI 自動化。支援透過 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 及 Codex 執行環境,可透過「設定 > Intelligence」啟用。經由 xcrun mcpbridge 提供 20 項 MCP 工具。 

  11. Blake Crosley,「Two MCP Servers Made Claude Code an iOS Build System」,blakecrosley.com/blog/xcode-mcp-claude-code,2026年2月。同一作者的 iOS 開發工作流程設定教學及實際成果分享。 

NORMAL ios-agent-development.md EOF