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

使用 AI 代理開發 iOS 應用程式:實戰指南

# 運用 AI 代理加速開發 iOS 應用程式。涵蓋 Claude Code、Codex CLI、Xcode 26.3 原生整合、MCP、CLAUDE.md 模式、hooks,以及 8 款應用程式的實戰心得。

words: 3518 read_time: 43m updated: 2026-04-28 22:55
$ less ios-agent-development.md

TL;DR: 現在有三種 agent runtime 可為 iOS 撰寫程式碼:Claude Code CLI(搭配 MCP)、Codex CLI(搭配 MCP),以及 Xcode 26.3 的原生 Intelligence agents。兩個 MCP 伺服器(XcodeBuildMCP 提供 59 個工具,Apple 的 xcrun mcpbridge 提供 20 個工具)讓 agent 能以結構化方式存取建置、測試、模擬器與除錯。本指南涵蓋實際的 CLAUDE.md 模式、hook 設定,以及對於什麼可行、什麼會壞掉的誠實評估——皆汲取自 8 個正式上架的 iOS App,共計 293 個 Swift 檔案。17 Agent 擅長 SwiftUI 視圖、SwiftData 模型、重構與建置錯誤診斷,卻在 .pbxproj 修改、程式碼簽署與視覺除錯上失靈。「agent 撰寫 Swift」與「agent 出貨 iOS App」之間的鴻溝,要靠設定來搭橋,而非靠 prompt。

我已用 AI 編碼 agent 打造了 8 個 iOS App。不是原型——而是上架 App Store 的應用,具備 HealthKit 整合、Metal shaders、SpriteKit 物理、iCloud 同步、Live Activities、Game Center 排行榜,以及橫跨 iOS、watchOS 與 tvOS 的多平台目標。這些 App 中的每一行 Swift,要嘛是 agent 撰寫、由我審閱,要嘛是我撰寫、由 agent 重構。據我估計,agent 處理了大部分行級的撰寫工作;我則負責審閱、範圍界定,以及那些需要人類判斷的部分(視覺打磨、簽署、效能調校、App Store 送審)。

這份指南正是當初我入門時希望存在的參考資料。它涵蓋完整堆疊:該選用哪個 agent runtime、如何設定 MCP 伺服器以取得結構化的建置存取、CLAUDE.md 該寫些什麼、哪些 hook 能避免 agent 摧毀您的 Xcode 專案,以及——更關鍵的——agent 在哪些地方會失靈,需要您親自接手。

重點摘要

對於剛接觸 AI agent 的 iOS 開發者:

  • 從 Claude Code CLI + XcodeBuildMCP 開始。 這是最成熟的 runtime,擁有最深入的 MCP 工具覆蓋率。安裝兩個指令、在專案中加入 CLAUDE.md,agent 就能建置、測試與除錯,不必您再複製貼上錯誤訊息。
  • 絕不讓 agent 修改 .pbxproj。 這是最重要的單一守則。一個阻擋寫入 .pbxproj.xcodeproj/ 的 PreToolUse hook,能為您省下數小時的修復時間。
  • 您的 CLAUDE.md 就是 agent 的入職文件。 在它身上花的時間,會在每一次接觸專案的 agent session 中回本。

對於將 iOS 加入工作流程的資深 agent 使用者:

  • MCP 徹底改變 iOS 建置迴圈。 在 MCP 之前,agent 能寫 Swift 但無法驗證是否能編譯。有了 XcodeBuildMCP,agent 能撰寫程式碼、建置、讀取結構化錯誤、修復、執行測試——全程自主。
  • 三種 runtime 服務不同需求。 Claude Code CLI 用於深度 agentic session,Codex CLI 用於無頭批次工作,Xcode 26.3 原生 agents 用於不離開 IDE 的快速行內修正。
  • Hook 基礎設施可直接沿用。 您現有的 PostToolUse 格式化器、PreToolUse 阻擋器與測試執行器 hook,只需微調路徑,即可同樣套用於 iOS 專案。

對於評估 AI 輔助 iOS 開發的團隊主管:

  • Agent 的成效隨專案文件擴展,而非隨專案規模擴展。 一個 63 檔的 App 配上詳盡的 CLAUDE.md,所產出的 agent 成果優於一個 14 檔但毫無文件的 App。
  • .pbxproj 邊界不可妥協。 Agent 無法可靠地編輯 Xcode 專案檔。您的工作流程必須將「手動將檔案加入 Xcode target」納入考量。
  • 誠實的 ROI:在文件齊備的專案上,agent 處理了大部分實作工作——這在一個 15 檔的 TV App 中具體可見,該 App 在 3 小時的 agent 輔助工作下出貨(下方有案例研究)。剩下的工作——視覺打磨、簽署、效能調校、App Store 送審——則需要人類判斷。

選擇您的路徑

您需要什麼 前往何處
首次設定 MCP MCP Setup: The Complete Configuration — 安裝兩個伺服器、驗證、設定 agents
為您的 iOS 專案撰寫 CLAUDE.md CLAUDE.md Patterns for iOS Projects — 來自 8 個 App 的實際範例
比較三種 agent runtime Three Agent Runtimes for iOS — Claude Code vs. Codex vs. Xcode 原生
了解 agent 能做什麼、不能做什麼 What Agents Do WellWhat Agents Do Poorly
為 iOS 開發設定 hooks Hooks for iOS Development — 存檔自動格式化、.pbxproj 保護、測試執行器
深度參考(本頁) 繼續閱讀——從設定到進階模式,一應俱全

如何使用本指南

這是一份逾 3,000 行的參考資料。請從符合您經驗等級的位置開始:

經驗等級 從這裡開始 然後探索
iOS 與 agent 雙雙新手 PrerequisitesMCP SetupYour First Agent Session CLAUDE.md PatternsWhat Works/Doesn’t
iOS 開發者,新接觸 agent Three RuntimesMCP SetupCLAUDE.md HooksArchitecture Patterns
Agent 使用者,新接觸 iOS Architecture PatternsWhat Agents Do PoorlyCLAUDE.md Framework-Specific ContextAdvanced Workflows
兩者皆有經驗 Advanced WorkflowsHooksMulti-Platform Patterns Runtime ComparisonThe Portfolio

目錄

  1. The Portfolio: 8 Apps, 293 Files
  2. Prerequisites
  3. Three Agent Runtimes for iOS
  4. MCP Setup: The Complete Configuration
  5. CLAUDE.md Patterns for iOS Projects
  6. Your First Agent Session
  7. What Agents Do Well in iOS
  8. What Agents Do Poorly in iOS
  9. Hooks for iOS Development
  10. Architecture Patterns That Work with Agents
  11. Framework-Specific Context
  12. Multi-Platform Patterns
  13. Advanced Workflows
  14. Real-World Case Studies
  15. Project Lifecycle with Agents
  16. Configuring Agent Definitions
  17. Testing Patterns for Agent-Assisted iOS
  18. Context Window Management for iOS Projects
  19. Troubleshooting
  20. Common Agent Mistakes in iOS
  21. The Honest Assessment
  22. FAQ
  23. Quick Reference Card
  24. References

相關資源

主題 資源
Xcode 的 MCP 設定(較短的部落格文章) Two MCP Servers Made Claude Code an iOS Build System
Claude Code CLI 完整參考 Claude Code CLI: The Complete Guide
Codex CLI 參考 Codex CLI: The Complete Guide
Hook 系統深度解析 Anatomy of a Claw: 84 Hooks as an Orchestration Layer
Agent 架構模式 Agent Architecture Guide

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

在深入設定之前,先看看本指南的素材來源。這些並非玩具專案——它們橫跨五個 Apple 框架、三個平台,涵蓋從 14 個檔案的健身追蹤工具到 63 個檔案的跨平台冥想計時器,完整呈現 iOS 開發的各種複雜度。

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 shader + 音訊視覺化 41 自訂 Metal 渲染管線、音訊分析、即時 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 後製處理

為什麼檔案數很重要: 代理的成效取決於專案的可讀性,而非專案規模。Return(63 個檔案)產出的代理結果比 amp97(41 個檔案)更出色,因為 Return 擁有詳盡的 CLAUDE.md,包含檔案註解、架構圖與明確的模式。amp97 的 Metal shader 本身就難以讓代理推理,無論文件品質多高都一樣。


先決條件

為 iOS 開發設定任何代理執行環境之前,請先準備以下項目:

App Store Connect 截止日期:2026-04-28 起,上傳至 App Store Connect 的 App 必須使用 Xcode 26 或更新版本,搭配 iOS 26、iPadOS 26、tvOS 26、visionOS 26 或 watchOS 26 的 SDK 進行建置。12(macOS 提交不在此要求範圍內。)若您的團隊仍停留在 Xcode 16.x,本指南介紹的代理輔助工具鏈正好可以作為推動升級的契機——下方提到的任何 MCP 伺服器在 Xcode 26.3+ 之前都無法運作。

必要條件: - macOS 15+(Sequoia)或 macOS Tahoe - 已安裝並設定 Xcode 26.3+(xcrun mcpbridge 的最低需求);建議使用 Xcode 26.4+,可享有 Swift Testing 圖片附件、已記錄問題的嚴重性分級、含 crashlog 的 UI 測試當機警告,以及 String Catalog 編輯器改進。13 Xcode 26.4.1(2026-04-16,build 17E202)是目前最新的穩定版本——僅修正錯誤。14 - 至少安裝一個 iOS 模擬器執行環境 - 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 (26.4+ 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 指令能提供這種控制力。15

最適合用於:深度實作工作階段——建構新功能、跨多個檔案進行重構、除錯複雜問題、自動執行建置-測試-修復循環。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: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、而不在 Web 專案中使用,這會很實用)。

-e XCODEBUILDMCP_SENTRY_DISABLED=true環境變數會停用當機回報遙測。XcodeBuildMCP預設包含 Sentry,會傳送包含檔案路徑的錯誤資料。除非您願意為該專案貢獻診斷資料,否則建議選擇退出。1

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

類別 工具 功能說明
專案探索 discover_projslist_schemeslist_targets 尋找 .xcodeproj/.xcworkspace 檔案,列出可用的 schemes 與 targets
建置 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旗標即可管理模擬器。代理會探索可用的執行環境,並挑選合適的裝置。

  4. discover_projs + list_schemes——專案內省。代理無需猜測您的 scheme 名稱或 workspace 結構。

  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 行為、測試型別轉換、驗證表達式,完全不需建置整個應用程式。

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

  4. XcodeListNavigatorIssues——回傳 Xcode 分析器的即時診斷,而非僅是建置錯誤。可捕捉到未使用的變數、潛在的循環引用、棄用警告等建置系統不會顯示的問題。

為何兩個伺服器都需要

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

┌─────────────────────────────────────────────────────────────────┐
                     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**:`build_sim` / `build_device`(不要透過 Bash 執行 `xcodebuild`)
- **Test**:`test_sim` / `test_device`(不要透過 Bash 執行 `xcodebuild test`)
- **Simulators**:`list_sims``boot_sim``open_sim`(不要透過 Bash 執行 `xcrun simctl`)
- **Debug**:`debug_attach_sim``debug_stack``debug_variables`
- **Apple 文件**:`DocumentationSearch`(不要使用 WebSearch 查詢 Apple API)
- **Swift 驗證**:`ExecuteSnippet`(不要透過 Bash 執行 `swift`)
- **Previews**:`RenderPreview` 用於無頭 SwiftUI 驗證

MCP 會回傳結構化的 JSON,而 Bash 回傳的是非結構化的文字。
結構化資料代表消耗的 token 更少,錯誤診斷也更精確。

這份指引能讓代理優先選用 MCP 工具。少了它,您會看到代理透過 Bash 拼湊出冗長的 xcodebuild 命令,耗費數千個 context token 解析輸出,有時甚至誤判實際的錯誤所在。


iOS 專案的 CLAUDE.md 模式

CLAUDE.md 是專案中對代理輔助開發最重要的檔案。它就是代理的入職文件 — 是「讀過架構文件的新進員工」與「全憑猜測的新進員工」之間的差別。

我維護的每一個 iOS 專案都有 CLAUDE.md。以下是經過 8 款 App 驗證、實際可行的模式。

必備章節

每一份 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 handler、嚴格併發對比寬鬆模式)。

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:
```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.

即使代理應該優先使用 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

這些模式能避免代理引入不一致。若沒有明確記錄模式,代理有時會在某個檔案使用 ObservableObject,在另一個檔案改用 @Observable,或者另起爐灶寫一套設定機制,而不沿用既有的 Settings.shared singleton。

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. 框架專屬的脈絡資訊

這個章節會因 App 而異。只要某個框架存在不直觀的設定,就應該寫入:

HealthKit App:

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

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

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

## 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 伺服器)

以下是一份附註解的範例,展示這六個章節如何在一款中等複雜度的 App 中協同運作。這就是我為 Banana List 採用的 CLAUDE.md 模式 — 一款由 53 個檔案構成的雜貨清單 App,具備 iCloud 同步,並配有自訂的 MCP 伺服器,將 App 的資料開放給 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 述詞限制)

## 建置與測試

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

建議優先使用 MCP 工具(`build_sim`、`test_sim`)而非原始指令。

## 關鍵模式

### Observable + SwiftData
- SwiftData 的 `@Model` 類別自動具備 Observable 特性
- 切勿在 `@Model` 類別上加 `@Observable`(重複,會產生警告)
- 在表單中對模型屬性進行雙向綁定時請使用 `@Bindable`
- 在 view 中使用 `@Query`,在非 view 程式碼中使用 `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 App——14 個檔案)

對於小型專案,CLAUDE.md 可以寫得簡潔。以下是 Reps 的範本,這是一款 14 個檔案的健身追蹤器。請注意,即使是簡短的 CLAUDE.md,也涵蓋了全部六個必要章節:

# 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 分鐘,卻能省下數小時的代理人混亂。

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

遊戲專案需要更多特定於框架的脈絡。代理人必須理解場景圖、物理類別與遊戲狀態機:

# 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

## 規則

- 絕不修改 .pbxproj
- 絕不修改 PhysicsCategory bitmasks(會破壞所有碰撞偵測)
- 在未理解渲染順序之前,絕不變更場景階層的 z-ordering
- 修改 ShaderTypes.h 時,必須同步更新 Swift 與 Metal 兩端的引用
- 新增敵人時請繼承 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 個檔案) 識別資訊 + 檔案清單 + 規則 Reps(14 個檔案):基本 SwiftData 模式、建置指令、禁令
中型(20-40 個檔案) 加上框架脈絡 + 關鍵模式 TappyColor(30 個檔案):SpriteKit 場景階層、physics categories、遊戲迴圈
大型(40 個以上檔案) 加上架構圖 + 關係對應 + 多 target 資訊 Return(63 個檔案):跨平台架構、session 同步圖、各平台差異
特殊類型(Metal/GPU) 加上管線圖 + 共用型別定義 + 緩衝區配置 amp97(41 個檔案):渲染管線階段、uniform struct、緩衝區管理

過度撰寫文件的成本趨近於零(代理會略過用不到的內容),但文件不足的代價則相當高(代理會發明出與您程式碼庫互相衝突的模式)。

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)
  • [ ] 已記錄關鍵 singleton 與共用模式
  • [ ] 已註明已知限制或陷阱

您的第一次代理 session

當 MCP 設定完成且專案中已備妥 CLAUDE.md,以下是有效的第一次 session 演練。本範例使用 Claude Code CLI,但流程同樣適用於任何 runtime。

步驟 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檢視與修飾符

代理對SwiftUI宣告式語法有深刻的模式識別能力。檢視組合、修飾符鏈、狀態綁定與版面配置——這些都與代理的訓練資料高度契合,因為SwiftUI的API介面文件完整,且模式高度一致。

代理表現出色之處: - 根據描述建構新檢視(「建立一個設定表單,包含X、Y、Z的切換開關」) - 套用修飾符鏈(.glassEffect().sensoryFeedback().navigationTitle()) - 在不同版面配置模式之間轉換(VStack轉為LazyVGrid、List轉為ScrollView) - 對SwiftData模型實作@Bindable表單綁定 - 使用範例資料建構預覽提供者

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

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.

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

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,找出確切的檔案與行號,理解錯誤訊息,並套用修復——通常一輪對話就能完成。

代理可自主修復的錯誤: - 遺失的imports - 型別不符 - 協定一致性缺漏 - 已棄用的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呼叫完成。

Agent在iOS開發中的不足之處

以下誠實盤點Agent失敗的場景。了解這些邊界能避免挫折感並節省Token浪費。

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

這是iOS Agent開發中最重要的一條規則。.pbxproj檔案是Xcode的專案設定檔——一個包含UUID參照、建置階段清單和目標成員資訊的結構化文字檔。它名義上可供人類閱讀,但對AI Agent而言實際上無法解析。

為何Agent在.pbxproj上會失敗: - 此檔案使用自訂格式(非JSON、非YAML、非XML),且具有位置敏感性 - 每個條目都透過UUID交互參照——新增一個檔案需要一致地更新3至5個不同區段 - 單一字元位置錯誤就會導致整個專案檔案損毀 - Xcode對.pbxproj的合併衝突解決原本就脆弱——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無法對其進行有意義的編輯。這些是包含自動產生的UUID、約束參照與outlet連線的XML檔案,設計上是為了視覺化編輯,而非文字編輯。

緩解方式: 新檢視一律使用SwiftUI。若您的專案有舊有的Interface Builder檔案,請保持原樣,並以SwiftUI建立新的UI。

效能最佳化

Agent能寫出正確的程式碼,但不一定是高效能的程式碼。它們無法剖析您的應用程式、找出瓶頸或測量幀率。效能最佳化需要:

  1. Instruments剖析(視覺化工具,Agent無法存取)
  2. 對特定裝置的GPU/CPU特性的理解
  3. 以測量為基礎的迭代式變更

這在哪些地方會浮現: - Metal shader最佳化(Agent能寫出有效的Metal,但無法測量GPU幀時間) - SwiftUI view body的複雜度(Agent建立深度巢狀的view,導致重繪開銷) - Core Data / SwiftData查詢最佳化(Agent寫出的查詢正確,但在大型資料集上可能緩慢)

緩解方式: 用Agent進行實作,以Instruments手動剖析,然後請Agent套用您所識別出的具體最佳化。

程式碼簽署與配置

Agent無法在閱讀錯誤訊息之外,進一步偵錯程式碼簽署問題。配置描述檔管理、憑證建立、權限設定與App Store提交,本質上都是由人類操作的工作流程,牽涉到Apple Developer入口網站、Keychain Access與Xcode的簽署UI。

Agent能看到的: 「Signing for ‘Return’ requires a development team.」

Agent看不到的: 您的憑證是否已過期、配置描述檔是否包含該裝置、bundle ID是否與App ID相符,或您的entitlements檔案是否正確。

緩解方式: 所有簽署作業都在Xcode的Signing & Capabilities頁籤中處理。請勿要求Agent偵錯簽署失敗。

複雜的Metal Shader偵錯

Agent能寫出語法正確的Metal Shading Language(MSL),但無法驗證視覺輸出或偵錯GPU端的問題。Metal shader在GPU上執行——Agent沒有任何回饋機制可得知shader是否產生正確的視覺結果。

Agent能用Metal做的事: - 根據描述撰寫vertex與fragment shader - 在Swift中設定Metal渲染管線 - 為資料平行運算建立compute shader - 修正.metal檔案中的編譯錯誤

Agent無法用Metal做的事: - 驗證shader輸出的視覺正確性 - 偵錯GPU效能(幀時間、佔用率、記憶體頻寬) - 診斷視覺瑕疵(色帶、精度問題、不正確的色彩空間) - 在不同GPU架構上測試(A系列與M系列的行為差異)

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

視覺版面驗證

Agent看不到您應用程式的UI。它們撰寫SwiftUI版面程式碼,並能驗證其是否可編譯,但無法判斷產生的畫面是否看起來正確。一個渲染偏離中心10像素、使用錯誤字重或元素重疊的view,既不會產生建置錯誤,也能通過所有邏輯測試。

緩解方式: 以視覺方式檢視UI變更。使用Xcode中的SwiftUI Previews(或透過Apple MCP使用RenderPreview進行無頭渲染)來驗證版面。可考慮使用swift-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'"
      }
    ]
  }
}

這提供您兩項保證: 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中會自動採用玻璃材質。請勿以自訂材質手動重建玻璃效果——請使用系統內建的modifier。」


框架專屬情境

每個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)(tvOS不支援HealthKit) - 切勿在本地儲存超出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之間共用) - render pipeline state設定模式 - buffer索引及其用途 - 存在哪些shader,以及各自的功能 - 已知的精度問題(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 hooks 已就位,以保護 .pbxproj 檔案。

使用 Apple 裝置端 LLM 的應用程式

若您的應用程式呼叫 Apple 的 Foundation Models 框架(例如用於離線摘要、分類或結構化輸出生成),代理需要知道提示詞預算。iOS 26.4 在 SystemLanguageModel 中新增了兩個 API,取代了先前 4096 token 的猜測值:contextSize(模型在單次對話中可接受的最大 token 數)以及 tokenCount(for:)(async throws,回傳指定提示詞實際耗費的 token 數)。16 兩者皆為 @backDeployed(before: iOS 26.4),因此可在所有支援 FM 的 OS 版本中使用,無需 #available 階梯式判斷。

代理在生成提示詞構建程式碼時應遵循的模式:

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
}

若您的應用程式涉及 SystemLanguageModel,請將此模式加入 CLAUDE.md。否則,代理會回退到舊的 4096 硬編碼值,並在配備更大脈絡視窗的裝置上靜默截斷提示詞。tokenCount(for:) 上的 async throws 簽章具有關鍵作用——若代理貼上同步版本,將無法編譯通過。


真實案例研究

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

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

任務:為 Return 新增一個 tvOS 目標。Return 是一款冥想計時器,已經有 iOS 與 watchOS 版本。TV App 需要 Siri Remote 導航、大螢幕 UI,以及與 iOS App 的設定同步。

代理做得好的部分: - 閱讀現有的 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 目標(File > New > Target > tvOS App) - 將新目標加入 Xcode 專案(.pbxproj 變更) - 為 TV 目標設定 App Groups entitlement - 將 TV 目標加入現有 scheme 或建立新 scheme - 手動將代理建立的所有 Swift 檔案加入 TV 目標 - 親自測試 Siri Remote 導航(代理無法評估焦點行為)

結果:15 個全新的 Swift 檔案,功能完整的 TV App,在大約 3 小時的代理輔助工作內完成。據我估計,代理處理了大約 80% 的實作工作;我則負責需要 Xcode UI 互動的部分(entitlements、目標設定、capability 旗標)以及在實機 Apple TV 上手動測試焦點。若我獨自在這個程式碼庫中完成同等工作 — 根據我未使用代理時所交付的類似功能來推估 — 將會耗費數天的時間。

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

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

經過: 1. 代理寫出一個有效的 Metal shader 修改,新增了 uEnergy uniform 與 HDR tonemapping 2. 程式碼編譯時沒有錯誤 3. 在裝置上,視覺化完全變成一片白 — 強度係數高出 10 倍(3.5 而非 0.30) 4. 代理看不到白色畫面,因此沒有任何回饋訊號 5. 我用肉眼識別出問題,並要求代理降低係數 6. 代理降低了係數,但整體的能量狀態機過於複雜,以另一種方式破壞了視覺化器 7. 全部還原 — 兩個 commit(67959edcda4830)在 869d914 中還原

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

事後我加入 CLAUDE.md 的內容:「DO NOT attempt energy state modifications to the oscilloscope shader without extremely careful coefficient testing. Previous attempt broke the visualizer with coefficients 10x too high.」

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

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

代理所做的事: 1. 閱讀現有的 V1 模型定義 2. 建立帶有新欄位與關聯關係的 V2 模型定義 3. 撰寫一個遵循 SchemaMigrationPlan 協定的 GroceryMigrationPlan 4. 實作 V1toV2 遷移階段:加入預設值 quantity: 1category: nil 5. 更新所有 view 以支援新欄位 6. 更新 SampleData.swift 用於 preview 7. 透過 MCP 建置並執行測試 — 全部通過 8. 建立遷移專屬的單元測試

關鍵:代理之所以成功,是因為 SwiftData 遷移遵循一個定義清楚的協定模式,該模式在 Apple 的文件與訓練資料中都有完整的呈現。CLAUDE.md 明確記錄了 V1 模型,因此代理理解自己是從什麼遷移而來。

案例研究 4:Return 中的 iCloud Session 同步(成功但複雜)

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

代理產出的成果:

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

代理: 1. 建立 MeditationSession 資料模型,包含 UUID、日期、duration、來源裝置與 HealthKit 同步狀態 2. 建立 SessionStore singleton,管理 NSUbiquitousKeyValueStore 進行 iCloud 同步 3. 實作合併衝突解決(基於 UUID 的去重) 4. 加入 SessionHistoryView,並針對各平台做了適配(iOS 上用左滑刪除,tvOS 上以焦點為基礎) 5. 在 iPhone 端為來自其他裝置的 session 串接 HealthKit 同步

需要反覆迭代的部分:最初的實作沒有處理 iPhone App 在背景啟動的情況(沒有前景通知可觸發同步)。代理需要明確的指引:「使用 NSUbiquitousKeyValueStore.didChangeExternallyNotification 來在背景 KV 變更時觸發同步。」得到這個提示之後,實作就正確了。

教訓:當架構描述清楚時,代理能很好地處理多平台架構模式。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. 加入所需的權限(HealthKit、Game Center等) 5. 建立初始CLAUDE.md,包含專案識別與規則

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

第3階段:人工整合(30-60分鐘) 1. 將代理建立的檔案加入Xcode targets 2. 驗證簽署與權限 3. 在實機上測試 4. 檢視視覺佈局與UX 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著色器調校 需要在實機GPU上測試
App Store提交 入口網站與Xcode Organizer
效能分析 需要Instruments
無障礙稽核 部分 代理可加入標籤,由人類驗證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工作階段中以@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.

為什麼這樣有效: 編號的驗收條件提供代理一份檢查清單。參考既有的測試檔案能建立模式。指定使用setUp()可避免代理建立糾結的測試狀態。

無效的測試提示詞:

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

代理需要被提醒的關鍵模式: - 在測試@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.

代理能正確設定快照測試,但無法檢視參考影像。您負責檢視最初的快照,之後代理的測試便能在未來的變更中捕捉到視覺迴歸。


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類別 100-300行 1,000-3,000
Metal shader(.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視窗範圍內。代理可將整個專案保留在上下文中。

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

大型專案的策略

  1. 詳盡的CLAUDE.md檔案註解——代理讀取檔案地圖後,直接導航至相關檔案
  2. Subagent委派——將探索與研究路由至subagent(乾淨的上下文,回傳摘要)
  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 failed — scheme not found」

代理正在猜測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 — 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(請參閱Teaching the Agent to Use MCP
  2. 直接提示:「使用build_sim的MCP工具,而非透過Bash執行xcodebuild」

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

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

「模擬器在開機過程中卡住」

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

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搭配XcodeBuildMCP。它擁有最深入的MCP整合、最成熟的hook系統,以及1M上下文視窗(Opus 4.6),足以將整個iOS專案保留在工作記憶中。從這裡開始,隨著工作流程逐漸成熟,再加入Codex進行審查、以及Xcode原生代理進行快速的行內編輯。

我需要兩個MCP伺服器嗎?

對大多數開發者而言,僅XcodeBuildMCP就涵蓋了90%的需求(建置、測試、模擬器、除錯)。如果您需要文件搜尋、Swift REPL驗證或SwiftUI預覽渲染,再加入Apple的Xcode MCP。您隨時可以稍後加入——這兩個伺服器是獨立的。

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

XcodeBuildMCP包含一個create_project工具,可建立新Xcode專案的骨架。然而對於正式上線的應用程式,我建議在Xcode中建立專案(以正確設定簽署、capabilities及target配置),再使用代理進行所有程式碼實作。您在Xcode新專案精靈中花的5分鐘,可省下數小時因代理產生專案配置問題而花費的時間。

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

處理得很好。Package.swift是標準的Swift檔案,代理可以可靠地讀取與編輯。新增相依套件、更新版本範圍以及配置target皆能正常運作。限制在於以.xcodeproj為基礎的相依套件管理(Xcode的套件解析UI)——這是由Xcode管理的,不應由代理編輯。

代理可以提交到App Store嗎?

不行。App Store提交涉及Xcode的Organizer、佈建設定檔、螢幕截圖、後設資料以及App Store Connect入口網站。這些都無法透過MCP或命令列工具以代理可有意義操作的方式存取。代理可處理一切直到封存階段——實作、測試、修復錯誤及撰寫文件。提交的最後一哩路仍需由人工執行。

不過,代理可協助處理App Store的後設資料。請代理根據最新變更撰寫應用程式描述、關鍵字以及更新內容文字。這類文字產生的工作正是代理擅長之處。

在代理輔助的iOS開發中,我該如何處理secrets與API金鑰?

絕對不要將secrets提交至版本控制。對於連接後端API的iOS應用程式:

  1. 使用.xcconfig檔案進行環境特定的配置
  2. .xcconfig檔案加入.gitignore
  3. 透過Info.plist的build settings引用設定值
  4. 在CLAUDE.md中記錄所需的secrets,但不包含實際數值
## 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 { })能產生正確結果。複雜的多階段動畫若需精確掌控時序,則需要視覺化的反覆調校,這是代理無法做到的。

有效:「在計時器於各狀態之間轉換時,加入spring動畫。」

無效:「讓計時器的動畫感覺更令人滿意。」(主觀,需要視覺化調校。)

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

非常好。代理理解Swift的do/catchResult以及async 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區塊。

我可以使用代理進行無障礙實作嗎?

部分可以。代理能正確新增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導航順序是否正確、測試Dynamic Type縮放,或評估顏色對比度。請使用Xcode的Accessibility Inspector進行驗證。

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

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

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

代理如何處理 SwiftUI 預覽?

兩種方式: 1. Apple Xcode MCP 的 RenderPreview 工具會以無頭模式渲染預覽並回傳結果。代理可以驗證預覽是否能編譯與渲染而不出錯,但無法評估視覺正確性。 2. 基於建置的驗證透過 build_sim 確認預覽提供者能順利編譯。若預覽在執行階段崩潰,建置仍會成功——崩潰只會在 Xcode 嘗試渲染預覽時才會浮現。

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

visionOS 與 Apple Vision Pro 的情況呢?

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

專案規模多大時代理會開始吃力?

上下文視窗大小是限制因素。憑藉 Opus 4.6 的 1M token 視窗,Claude Code 可同時將約 50 至 70 個 Swift 檔案保留在主動工作記憶中。對於更大型的專案,代理會運用檔案搜尋與選擇性讀取,以子集方式處理程式碼庫。擁有 100 個以上檔案的專案運作良好——代理只是依需求讀取檔案,而非將所有內容都保留在上下文中。

實務上的限制不在於檔案數量,而在於程式碼庫的連貫性。一個有詳盡 CLAUDE.md 文件的 200 檔案專案,會比沒有文件的 30 檔案專案產生更好的結果。

使用代理進行 iOS 開發是否需要懂 Swift?

您需要能夠審閱代理的輸出並做出架構決策。您不必親手撰寫每一行程式碼,但必須對 Swift 有足夠的理解,以便察覺代理做出錯誤選擇的時機——尤其是在並行處理、記憶體管理以及框架特定模式方面。代理是您既有技能的 10 倍放大器,而非取代您技能的工具。

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

代理能可靠地解決 Swift 原始檔中的合併衝突。標準的衝突標記(<<<<<<<=======>>>>>>>)對所有代理執行環境而言都是熟悉的格式。然而,.pbxproj 檔案中的合併衝突仍是一項需要手動處理的任務——請勿要求代理解決 .pbxproj 衝突。

為 iOS 開發執行代理的成本如何?

採用 Anthropic 的 Max 方案(Opus 4.6,1M 上下文)時,典型的 iOS 開發工作階段歷時 30 至 120 分鐘,處理 200K 至 800K 個 token。MCP 工具呼叫增加的負擔極小(結構化的 JSON 回應相較於原始建置輸出更為節省 token)。其成本與在任何其他程式碼庫上執行 Claude Code 相當——iOS 開發在費用上並不顯著高於或低於網頁開發。

我可以將代理用於 UIKit 專案嗎?

可以,但代理在 SwiftUI 專案上更為高效。UIKit 需要較多樣板程式碼,宣告式結構較少,且通常涉及代理無法編輯的 Interface Builder 檔案。若您手上是 UIKit 專案,不妨考慮讓代理處理模型層與業務邏輯,UI 部分則手動處理,或逐步將檢視遷移至 SwiftUI。

代理如何處理本地化?

代理能有效建立與編輯 .xcstrings(Xcode 字串目錄)檔案。它們可以新增本地化鍵值、提供翻譯,並維持各語言間的一致性。.xcstrings 檔案的結構化 JSON 格式對代理相當友善。對於 .strings 檔案(舊版格式)代理同樣表現良好——其鍵值對格式相當直觀。


iOS 開發中常見的代理錯誤(以及如何預防)

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

錯誤 1:混用 Observable 模式

會發生什麼:代理在某個檔案中使用 @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:在閉包中產生循環引用

會發生什麼:代理建立的閉包會強引用 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 要求

會發生什麼:代理建立 @Observable 類別時未加上 @MainActor 隔離,導致 Swift 6.2 的並行警告,或在主執行緒以外發生 UI 更新時造成執行階段崩潰。

預防方式:

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

會發生什麼:代理使用已棄用的 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:將模擬器名稱寫死

會發生什麼:代理撰寫建置命令時帶入特定模擬器名稱(「iPhone 16 Pro」),而該模擬器在您的系統上可能並不存在。

預防方式:MCP 已能處理此問題——list_sims 會探索可用的模擬器。在 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:將檔案建立在錯誤的目錄

會發生什麼:代理將新的檢視檔案建立在專案根目錄,而非 Views/ 子目錄,或將模型放入錯誤的群組。

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

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

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

會發生什麼:代理在共用程式碼中使用 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:對簡單功能過度設計

會發生什麼:代理為一個本應只需 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 代理推出 8 款 iOS 應用程式之後,以下是總結:

代理改變了什麼: 實作速度。原本需要數天的工作,現在只需數小時。SwiftUI 視圖、SwiftData 模型、單元測試、重構——這些現在主要由代理產出、由人類審查。

代理沒有改變什麼: 架構決策、視覺設計、效能最佳化或 App Store 送審。這些仍由人類主導。

乘數效應確實存在,但有其邊界。 我對這 8 款應用程式組合的主觀估計:在具備完善 MCP 與 hook 設定、文件齊全的專案上,功能交付時間可提升 3 至 5 倍。這並非與對照組比較的結果,而是同一程式碼庫中代理協助功能與等量單獨工作的實際時間比較。沒有文件、沒有 hook 的專案大約只能提升 1.5 至 2 倍——代理花太多時間在猜測,而非實際建構。18

值得投資的事項: 投入時間在 CLAUDE.md、hooks 與 MCP 設定上。每一小時的設定時間,可省下數倍時間在修正代理錯誤上。設定本身就是產品——代理只是執行引擎。

令我意外的是: MCP 伺服器改變動態的程度有多大。在 MCP 之前,代理是懂 Swift 的精密文字編輯器。在 MCP 之後,它們成為能撰寫、建構、測試、除錯與迭代的開發夥伴。結構化的回饋迴圈,正是「會寫程式的代理」與「能交付產品的代理」之間的差別。

我會對過去的自己說: 從最小的應用程式開始(Reps,14 個檔案),把 MCP 與 hook 設定做對,寫一份完整的 CLAUDE.md,然後再將這些模式擴展到較大的專案。不要從 63 個檔案的多平台應用程式開始。不論專案規模多大,基礎建設投資都是相同的——在小專案上做一次,然後複製到其他專案。

未來展望: Xcode 26.3 的原生代理整合只是開始,不是結束。Apple 推出 MCP 支援,意味著工具鏈正朝向「代理優先」的開發方式邁進。現在投資於代理相容專案結構的開發者——乾淨的 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-04-28 將代理工作流程建議的 Xcode 版本提升至 26.4+(26.4.1,2026-04-16,build 17E202 為最新穩定版,僅修正錯誤)。引用 Xcode 26.4 功能(2026-03-24,build 17E192),適用於代理撰寫的測試與在地化:Swift Testing 圖片附件、Issue.record 的嚴重等級、附加 crashlog 的 UI 測試當機警告(專為 XCUIApplication(bundleIdentifier:) / XCUIApplication(url:) 應用程式設計)、String Catalog 編輯器改進。新增 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:) API(向後部署至 iOS 26.4)——新增代理產生 FM 提示預算程式碼的模式。iOS 26.4.2(4 月 22 日)與 iOS 26.5 beta 3(4 月 20 日)的更新未影響代理工具鏈。
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 維護。涵蓋模擬器、裝置、除錯與 UI 自動化工作流程的 59 個工具。採用語意化版本控制並附有變更紀錄。 

  4. Apple 在 Xcode 26.3 智慧型開發者工具計畫中推出 Xcode MCP 伺服器,將 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 hook 中用於維持一致程式碼風格的 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 透過 Settings > Intelligence 原生支援 Claude Agent 與 Codex runtime,並透過 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 開發工作流程的設定逐步說明與實際成果。 

  12. Apple Developer News,「Upcoming Requirements」。2026-04-28 條目:「上傳至 App Store Connect 的應用程式必須使用 Xcode 26 或更新版本,並搭配 iOS 26、iPadOS 26、tvOS 26、visionOS 26 或 watchOS 26 的 SDK 進行建置。」此項要求所列的平台範圍未包含 macOS。 

  13. Apple,「Xcode 26.4 Release Notes」。Xcode 26.4(2026-03-24,build 17E192)。引用自發行說明的功能:Swift Testing 現透過 CGImageNSImageUIImageCIImage 支援影像附件;Issue.record 接受嚴重性層級;某些 UI 測試應用程式當機——特別是透過 XCUIApplication(bundleIdentifier:)XCUIApplication(url:) 互動的應用程式——會以警告形式回報並附上當機紀錄,而非讓測試失敗;String Catalog 編輯器新增條目剪下/複製/貼上、語言移除,以及從現有語言預先填入翻譯,並提供 BUILD_ONLY_KNOWN_LOCALIZATIONS 設定。 

  14. Apple Developer News,「Xcode 26.4.1 (Build 17E202) Now Available」,2026-04-16。僅為錯誤修正的小版本——修復了 iOS/macOS/visionOS 26.4 之前版本中因符號遺失導致的 MetricKit 當機,以及 swift_asyncLet_finish 中的 Swift async 堆疊配置錯誤(「freed pointer was not the last allocation」)。 

  15. getsentry/XcodeBuildMCP v2.1.0 release,2026-02-23。新增 xcodebuildmcp init CLI 命令,可一步完成代理 skill 與 MCP 設定的安裝,取代原本獨立的 install-skill.sh 指令稿。自動偵測 Claude Code、Cursor 與 Codex;支援 --print(將設定寫入 stdout,供不支援的客戶端使用)與 --uninstall(移除)。 

  16. InfoQ,「Apple Adds Context Window Management to Foundation Models」,2026 年 3 月。記錄全新的 SystemLanguageModel.contextSizetokenCount(for:) API,並確認 @backDeployed(before: iOS 26.4) 註解。取代社群先前推測的 4096-token 硬編碼。 

  17. 檔案數量於 2026-04-27 對八個私有應用程式儲存庫各自執行 find . -name '*.swift' -not -path '*/Tests/*' | wc -l 計算得出。已排除測試檔案。總計與〈The Portfolio〉一節中各應用程式的明細表內部一致。 

  18. 主觀的實際耗時估計,並非與對照組相比的測量值。3-5 倍此一數字為作者回憶 2026 年代理輔助功能與相同程式碼庫中採用代理工作流程之前獨立完成的同等功能在「功能上線時間」上的比較。請將其視為完成 MCP + hook 設定後可預期的經驗法則,而非基準測試結果。 

NORMAL ios-agent-development.md EOF