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

AIエージェントでiOSアプリを構築する:実践者のためのガイド

# AIエージェントでiOSアプリをより速く構築できます。Claude Code、Codex CLI、Xcode 26.3ネイティブ、MCP、CLAUDE.mdパターン、フック、8つのアプリから得た教訓。

words: 3135 read_time: 58m updated: 2026-05-25 06:02
$ less ios-agent-development.md

要約: iOS向けコードを扱えるエージェントランタイムは、今では3つあります。MCP対応のClaude Code CLI、MCP対応のCodex CLI、そしてXcode 26.3のネイティブIntelligenceエージェントです。2つのMCPサーバー(59個のツールを備えたXcodeBuildMCPと、20個のツールを備えたAppleのxcrun mcpbridge)により、エージェントはビルド、テスト、シミュレーター、デバッグへ構造化された形でアクセスできます。このガイドでは、実際のCLAUDE.mdパターン、hook設定、そして何が機能し何が壊れるのかについての正直な評価を扱います。内容は、合計293個のSwiftファイルからなる8本の本番iOSアプリから得たものです。18 エージェントはSwiftUIビュー、SwiftDataモデル、リファクタリング、ビルドエラー診断を得意とします。一方で、.pbxprojの変更、コード署名、視覚的なデバッグは苦手です。「エージェントがSwiftを書く」と「エージェントがiOSアプリを出荷する」の差を埋めるのは、プロンプトではなく設定です。

私はAIコーディングエージェントを使って8本のiOSアプリを作ってきました。プロトタイプではありません。App Storeに公開され、HealthKit連携、Metalシェーダー、SpriteKit物理演算、iCloud同期、Live Activities、Game Centerリーダーボード、そしてiOS、watchOS、tvOSにまたがるマルチプラットフォームターゲットを備えたアプリです。これらのアプリのSwiftコードはすべて、エージェントが書いて私がレビューしたものか、私が書いてエージェントがリファクタリングしたものです。私の見積もりでは、行単位の著作の大部分はエージェントが担いました。私はレビュー、スコープ、そして人間の判断が必要な部分(視覚的な仕上げ、署名、パフォーマンス調整、App Store提出)を担当しました。

このガイドは、私が始めたときに欲しかったリファレンスです。どのエージェントランタイムを使うべきか、構造化されたビルドアクセスのためにMCPサーバーをどう設定するか、CLAUDE.mdに何を書くか、エージェントがXcodeプロジェクトを壊さないようにするhookはどれか、そして何より重要な、どこでエージェントが失敗し、人間が舵を取る必要があるのかまで、フルスタックで扱います。

重要なポイント

AIエージェントを初めて使うiOS開発者向け:

  • Claude Code CLI + XcodeBuildMCPから始めましょう。 最も成熟したランタイムであり、MCPツールのカバレッジも最も深いです。2つのコマンドをインストールし、プロジェクトにCLAUDE.mdを追加すれば、エラーメッセージを手でコピーしなくても、エージェントがビルド、テスト、デバッグできます。
  • エージェントに.pbxprojを変更させてはいけません。 これが最も重要なルールです。.pbxproj.xcodeproj/への書き込みをブロックするPreToolUse hookがあれば、復旧に費やす何時間も節約できます。
  • CLAUDE.mdはエージェントのオンボーディング文書です。 ここに費やした時間は、そのプロジェクトに触れるすべてのエージェントセッションで回収できます。

既にエージェントを使っていて、ワークフローにiOSを追加する方向け:

  • MCPはiOSのビルドループを変えます。 MCP以前、エージェントはSwiftを書けても、それがコンパイルできるか検証できませんでした。XcodeBuildMCPがあれば、エージェントはコードを書き、ビルドし、構造化されたエラーを読み、修正し、テストを実行できます。しかも自律的に行えます。
  • 3つのランタイムは、それぞれ異なる用途に向いています。 深いエージェント型セッションにはClaude Code CLI、ヘッドレスなバッチ作業にはCodex CLI、IDEを離れない素早いインライン修正にはXcode 26.3のネイティブエージェントが向いています。
  • hookインフラはそのまま活かせます。 既存のPostToolUseフォーマッター、PreToolUseブロッカー、テストランナーhookは、パスを少し調整するだけでiOSプロジェクトでも同じように機能します。

AI支援のiOS開発を評価しているチームリード向け:

  • エージェントの効果は、プロジェクトサイズではなくプロジェクト文書の質に比例します。 詳細なCLAUDE.mdがある63ファイルのアプリは、何もない14ファイルのアプリよりも良いエージェント出力を生みます。
  • .pbxprojの境界は交渉不可です。 エージェントはXcodeプロジェクトファイルを安定して編集できません。ワークフローでは、Xcodeターゲットへのファイル追加を手作業で行う前提が必要です。
  • 正直なROI: ドキュメントが整ったプロジェクトでは、実装の大部分をエージェントが担えます。これは、3時間のエージェント支援作業で出荷した15ファイルのTVアプリにも表れています(下のケーススタディ参照)。残る作業、つまり視覚的な仕上げ、署名、パフォーマンス調整、App Store提出には、人間の判断が必要です。

読むべき場所を選ぶ

必要なこと 読む場所
初めてMCPをセットアップする MCPセットアップ: 完全設定 — 両方のサーバーをインストールし、検証し、エージェントを設定します
iOSプロジェクト用のCLAUDE.mdを書く iOSプロジェクト向けCLAUDE.mdパターン — 8本のアプリから得た実例
3つのエージェントランタイムを比較する iOS向け3つのエージェントランタイム — Claude Code vs. Codex vs. Xcode native
エージェントにできること、できないことを理解する エージェントが得意なことエージェントが苦手なこと
iOS開発用のhookを設定する iOS開発向けhook — 保存時フォーマット、.pbxproj保護、テストランナー
詳細リファレンス(このページ) このまま読み進めてください。セットアップから高度なパターンまですべて扱います

このガイドの使い方

これは3,000行以上のリファレンスです。自分の経験レベルに合う場所から始めてください。

経験 ここから始める 次に読む
iOS + エージェントが初めて 前提条件MCPセットアップ最初のエージェントセッション CLAUDE.mdパターンうまくいくこと/いかないこと
iOS開発者で、エージェントは初めて 3つのランタイムMCPセットアップCLAUDE.md hookアーキテクチャパターン
エージェントユーザーで、iOSは初めて アーキテクチャパターンエージェントが苦手なことCLAUDE.md フレームワーク別コンテキスト高度なワークフロー
両方に慣れている 高度なワークフローhookマルチプラットフォームパターン ランタイム比較ポートフォリオ

目次

  1. ポートフォリオ: 8本のアプリ、293個のファイル
  2. 前提条件
  3. iOS向け3つのエージェントランタイム
  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. FAQ
  23. クイックリファレンスカード
  24. 参考資料

関連リソース

トピック リソース
Xcode向けMCPセットアップ(短めのブログ記事) 2つのMCPサーバーがClaude CodeをiOSビルドシステムにした
Claude Code CLI完全リファレンス Claude Code CLI: 完全ガイド
Codex CLIリファレンス Codex CLI: 完全ガイド
hookシステムの詳説 Anatomy of a Claw: オーケストレーション層としての84個のhook
エージェントアーキテクチャパターン エージェントアーキテクチャガイド
Macデスクトップアプリ + Remote Control Claude Code Mac Desktop + Remote Control: CLIユーザーガイド

Appleエコシステムシリーズ。 Apple Intelligence、MCP、Foundation Models、Vision、Core ML、iOS 26フレームワークスタックと連携するSwiftUIアプリについての、本番向け記事21本です。Water、Get Bananas、Return、そして941ポートフォリオの他のアプリから得た内容です。

シリーズハブ: Appleエコシステムシリーズ

Agentic Apple(E4):

トピック リソース
Apple Intelligenceのintent surface App Intents Are Apple’s New API to Your App
iOSアプリと並走するMCPサーバー Two Agent Ecosystems, One Shopping List
どちらをいつ使うか App Intents vs MCP Tools: The Routing Question
ランタイム機能としてのオンデバイスLLMとツールとしての違い Foundation Models + Agentic Workflow
Apple開発向けhook Hooks for Apple Development
プロセスをまたぐ状態 Single Source of Truth: SwiftData + MCP + iCloud

フレームワーク(E2/E3):

トピック リソース
Foundation ModelsのオンデバイスLLM Foundation Models On-Device LLM
Visionフレームワーク(CVプリミティブ) Vision Framework: What’s Built In
Core ML推論パターン Core ML On-Device Inference
RealityKitの空間的メンタルモデル RealityKit and the Spatial Mental Model
SwiftUIの内部構造 What SwiftUI Is Made Of
Symbol Effectsのアニメーション語彙 Symbol Effects: SwiftUI’s Built-In Animation Vocabulary
iOS 26+のLiquid Glass Liquid Glass in SwiftUI: Three Patterns

出荷済みコード(E1):

トピック リソース
Live Activitiesの状態機械 Live Activities State Machine
watchOSランタイム契約 watchOS Runtime Contract
SwiftDataスキーマ規律 SwiftData Schema Discipline
HealthKit + SwiftUIパターン HealthKit + SwiftUI on iOS 26
マルチプラットフォームSwiftUI Five Apple Platforms, Three Shared Files
XcodeBuildMCP連携 Two MCP Servers, One Xcode Project

統合(E5):

トピック リソース
iOSアプリの3つのsurface The Three Surfaces of an iOS App
プラットフォームターゲットの判断 The Apple Platform Matrix
私が書かないと決めていること What I Refuse to Write About

ポートフォリオ: 8つのアプリ、293ファイル

設定に入る前に、このガイドの根拠になっているものを示します。これらは単なるサンプルプロジェクトではありません。5つのAppleフレームワーク、3つのプラットフォームにまたがり、14ファイルのワークアウトトラッカーから63ファイルのマルチプラットフォーム瞑想タイマーまで、iOSの複雑さを幅広く含んでいます。

アプリ スタック ファイル数 複雑さ
Banana List SwiftUI + SwiftData + iCloud Drive sync + MCP server for Claude Desktop 53 フルCRUD、iCloud同期、アプリのデータをClaude Desktopに公開するカスタムMCPサーバー
Ace Citizenship SwiftUI学習アプリ + FastAPIバックエンド 26 クライアントサーバー、REST API連携、クイズエンジン
TappyColor SpriteKit色合わせゲーム 30 ゲームループ、物理演算、タッチ処理、パーティクルエフェクト
Return 禅瞑想タイマー — iOS 26+、watchOS、tvOS 63 HealthKit、Live Activities、Watch拡張ランタイム、TVフォーカスナビゲーション、iCloudセッション同期
amp97 Metalシェーダー + オーディオビジュアライゼーション 41 カスタムMetalレンダーパイプライン、オーディオ解析、リアルタイムGPUコンピュート
Reps SwiftUI + SwiftDataワークアウト記録 14 最小限の実用アプリ、整理されたSwiftDataパターン
Water SwiftUI + SwiftData + Metal + HealthKit水分補給記録 34 Metal流体シミュレーション、HealthKit水分摂取ログ、ウィジェット
Starfield Destroyer SpriteKit + Metal宇宙シューティング 32 99レベル、8種類の機体、Game Centerリーダーボード、Metalポストプロセッシング

ファイル数が重要な理由: エージェントの有効性は、プロジェクトのサイズではなく、プロジェクトの読みやすさと相関します。Return(63ファイル)はamp97(41ファイル)よりも優れたエージェント出力を生みます。Returnには、ファイル注釈、アーキテクチャ図、明示的なパターンを含む詳細なCLAUDE.mdがあるためです。amp97のMetalシェーダーは、ドキュメントの品質に関係なく、エージェントにとって本質的に推論が難しい領域です。


前提条件

iOS開発向けにエージェントランタイムを設定する前に、次を確認してください。

App Store Connectの期限: 2026年4月28日以降、App Store Connectへのアプリのアップロードは、iOS 26、iPadOS 26、tvOS 26、visionOS 26、watchOS 26向けのSDKを使用し、Xcode 26以降でビルドされている必要があります。12(macOSへの提出はこの要件の対象外です。)チームがまだXcode 16.xを使っている場合、このガイドのエージェント支援ツールチェーンは移行を促すきっかけにもなります。いずれにしても、以下のMCPサーバーはXcode 26.3+なしでは動作しません。

必須: - macOS 15+(Sequoia)またはmacOS Tahoe - Xcode 26.3+のインストールと設定(xcrun mcpbridgeの最低要件)。エージェントワークフローのアップグレード、つまりコーディングアシスタントでのメッセージキューイングと確認質問のサポートに加え、Swift Testingの画像添付、記録済みissueの重要度、crashlog付きUIテストクラッシュ警告、String Catalogエディタ改善のため、Xcode 26.5+を推奨します。これらは26.4で初めて追加されました。1314 Xcode 26.5(2026年5月11日、build 17F42)が最新の安定版です。26.4.1(2026年4月16日、build 17E202)は26.4系の最後のバグ修正版でした。15 - 少なくとも1つのiOS Simulatorランタイムがインストールされていること - Anthropic APIアカウント(Claude Code用)またはOpenAIアカウント(Codex用)

推奨: - SwiftFormatのインストール(brew install swiftformat) — 保存時フォーマット用hookで使用します - SwiftLintのインストール(brew install swiftlint) — 任意ですが、スタイル強制に役立ちます - ターミナルに慣れていること — 3つのランタイムはいずれもコマンドラインから動作するか、コマンドラインと連携します

Xcodeのインストールを確認します:

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

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

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

xcrun mcpbridgeが「command not found」を返す場合は、Xcode 26.3以降が必要です。App Storeまたはdeveloper.apple.comからXcodeをインストールまたはアップデートしてください。注意: xcode-select --installでインストールされるのはCommand Line Toolsのみで、mcpbridgeは含まれません。完全なXcode.appが必要です。


iOSのための3つのエージェントランタイム

iOSのコードを書き、ビルドし、テストできる3つの異なるランタイムがあります。これらは互換性のあるものではなく、それぞれ異なる強み、異なるMCP統合パターン、そして異なる理想的なユースケースを持っています。

1. Claude Code CLI

概要: Anthropicによるターミナルベースのエージェント型コーディングアシスタントです。コードベースを読み込み、コマンドを実行し、ファイルを変更し、MCPを介して外部ツールに接続します。

MCP統合: XcodeBuildMCPとAppleのXcode MCPの両方を完全にサポートしています。エージェントは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を自動検出してエージェントスキルとMCP設定を1ステップでインストールできます。

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

フラグ:--print(非対応クライアント向けに設定をstdoutに書き出す)、--uninstall(削除)。どのMCPサーバーをどのスコープで接続するかを明示的に制御したい場合は、これをスキップしてください。上記の手動のclaude mcp addコマンドを使えば、その制御が可能です。16

最適な用途: 深い実装セッション — 新機能の構築、複数ファイルにまたがるリファクタリング、複雑な問題のデバッグ、ビルド・テスト・修正ループの自律的な実行。Claude Codeの100万トークンのコンテキストウィンドウ(Opus 4.6使用時)により、エージェントはほとんどの小〜中規模の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導入前のワークフローとの決定的な違いは、エージェントが手動でビルドしたりエラー出力を貼り付けたりするようユーザーに求めない点です。ビルド・エラー・修正のループは自律的に進行します。

2. Codex CLI

概要: OpenAIによるターミナルベースのコーディングエージェントです。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との主な違い: - ClaudeモデルではなくOpenAIモデルを使用 - コンテキストウィンドウサイズとトークン経済性が異なる - サンドボックス優先のパーミッションモデル(デフォルトでより制限的) - MCPエコシステムが小規模(テスト済みのコミュニティサーバーが少ない) - Hooksシステムが利用可能(v0.119.0+)だがClaude Codeほど成熟していない — イベントタイプが少なく、条件付きifフィールドがない

iOS開発でClaude CodeよりCodexを使う場面:

モデルの多様性が欲しいときにCodexを使います。一方のエージェントが書いたコードをもう一方のエージェントがレビューすることで、異なる種類のエラーを発見できます。collabワークフロー(Claudeがビルドし、Codexがレビュー)はiOS開発において効果的です。あるモデルファミリーでは正しく見えるSwiftUIのパターンに、別のモデルファミリーが微妙な問題を見つけ出すことがあるからです。Metalシェーダーや並行処理パターンは特にデュアルモデルレビューの恩恵を受けます。

3. Xcode 26.3ネイティブエージェント

概要: AppleはAIコーディングエージェントを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. エージェントがIntelligenceサイドバーに表示され、インラインで呼び出せるようになります

最適な用途: 素早いインライン編集、エージェントレベルの推論を伴うコード補完、そしてXcodeから離れたくない開発者向けです。ネイティブ統合により、エージェントはXcodeのプロジェクトコンテキスト — 開いているファイル、ビルドターゲット、スキーム設定 — にMCPブリッジなしで直接アクセスできます。

CLIエージェントと比較した制約: - フックシステムなし — フォーマット・オン・セーブの強制や.pbxprojへの書き込みブロックができない - CLAUDE.mdの読み込みなし — エージェントはプロジェクトレベルの設定ファイルを読まない - 自律性の制限 — エージェントは現在のファイルや選択範囲に対して動作し、プロジェクト全体には及ばない - サブエージェントの委譲なし — 複雑なマルチステップタスクを並列化できない - MCPサーバー設定なし — エージェントはXcode組み込みツールのみを使用

Xcodeネイティブエージェントを使う場面:

ターミナルへ切り替えるのが面倒な、素早く範囲が限定された編集向けです。「このモデルに計算プロパティを追加して」「この関数のユニットテストを書いて」「このビューを@Observableを使うようにリファクタリングして」といった、1〜2ファイルに触れるだけでビルド・テストサイクルを必要としないタスクに適しています。

ビルド、テスト、複数ファイルのリファクタリング、自律的なエラー修正が必要な作業には、MCPを備えたCLIエージェントを使用してください。

ランタイム比較マトリクス

機能 Claude Code CLI Codex CLI Xcode 26.3ネイティブ
MCPサポート フル(79ツール) フル(79ツール) Xcode組み込みツールのみ
フックシステム あり(成熟) あり(基本、v0.119.0+) なし
CLAUDE.md / プロジェクト設定 あり codex.md相当あり なし
自律的なビルド・テスト・修正 あり(MCP経由) あり(MCP経由) 部分的(インラインのみ)
サブエージェントの委譲 あり(最大10並列) なし なし
コンテキストウィンドウ 100万トークン(Opus 4.6) モデルによる プロバイダによる
複数ファイル操作 コードベース全体にアクセス可能 コードベース全体にアクセス可能 現在のファイル / 選択範囲
.pbxproj保護 フック経由 手動 N/A(Xcodeをネイティブに使用)
フォーマット・オン・セーブ PostToolUseフック経由 外部ツール Xcode設定
オフライン対応 なし なし なし
課金モデル Anthropic API利用料 OpenAI API利用料 プロバイダAPI利用料

推奨: プライマリランタイムとしてClaude Code CLIを使用してください。素早いインライン編集にはXcode 26.3ネイティブエージェントを使い、レビューパスとバッチ操作にはCodex CLIを使います。この3つは競合するのではなく、互いを補完します。


MCP セットアップ: 完全な設定

MCP(Model Context Protocol)は、エージェントを「Swiftを書き、ビルドはユーザー任せ」から「Swiftを書き、ビルドし、構造化されたエラーを読み取り、修正する」存在へ変えるものです。このセクションでは、ブログ記事よりも踏み込んで、2つのサーバー、すべてのインストール方法、検証、そしてツールが実際に使われるようにするエージェント設定を扱います。

XcodeBuildMCP: ヘッドレス iOS 開発のための59個のツール

XcodeBuildMCP は、xcodebuildxcrun 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 フラグを付けると、すべてのプロジェクトでサーバーをグローバルに利用できます。プロジェクト単位でインストールしたい場合は省略します(Webプロジェクトではなく、iOSプロジェクトだけで MCP を使いたい場合に便利です)。

-e XCODEBUILDMCP_SENTRY_DISABLED=true 環境変数は、クラッシュレポートのテレメトリを無効にします。XcodeBuildMCP にはデフォルトでSentryが含まれており、ファイルパスを含むエラーデータが送信されます。プロジェクトへの診断情報提供を希望しない限り、オプトアウトしましょう。1

全ツール一覧(8カテゴリにわたる59個のツール):

カテゴリ ツール 役割
プロジェクト検出 discover_projs, list_schemes, list_targets .xcodeproj/.xcworkspace ファイルを見つけ、利用可能なスキームとターゲットを一覧表示します
ビルド build_sim, build_device, build_mac ファイルと行ごとに整理された、構造化 JSON のエラー/警告出力付きでビルドします
テスト test_sim, test_device メソッドごとの成功/失敗結果付きでテストを実行します
Simulator ライフサイクル list_sims, boot_sim, shutdown_sim, open_sim, session_set_defaults Simulatorを作成、起動、管理、設定します
デバイス管理 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 — 何百回も呼び出すことになります。ファイル、行、重要度ごとに分類されたエラーを JSON で返します。エージェントはエラーを読み取り、ファイルへ移動し、ユーザーが何もしなくても修正します。

  2. test_sim — テストメソッドごとの結果を返します。単に「テストが失敗した」ではなく、どのテストがなぜ失敗したのかをエージェントが正確に把握できます。

  3. list_sims + boot_simxcrun simctl のフラグを覚えなくてもSimulatorを管理できます。エージェントが利用可能なランタイムを検出し、適切なデバイスを選びます。

  4. discover_projs + list_schemes — プロジェクトの内省です。エージェントがスキーム名やワークスペース構造を推測する必要がありません。

  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個のツール):

カテゴリ ツール 役割
ファイル操作 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 — WWDCセッションを含むAppleの開発者ドキュメントを検索します。Apple API に関する疑問では、Web検索より高速で信頼性があります。「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を開かなくても動作し、システムメモリの消費が少なく、Simulatorとデバイス管理がより充実しています。主力のビルドツールになります。

Apple Xcode MCP を使う場面: ドキュメント検索、Swift REPL検証、SwiftUIプレビュー描画、リアルタイム診断です。これらの機能が必要なセッションでは、Xcodeを開いたままにしておきます。

実際の使い分け: MCP 呼び出しの約90%ではXcodeBuildMCP を使い、ドキュメントとREPL検証ではApple Xcode MCP を使います。ビルドとテストでは、エージェントはデフォルトで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 を実行したり(非構造化出力でコンテキストトークンを浪費します)、Appleドキュメントの確認にWeb検索を使ったりする可能性があります(遅く、信頼性も下がります)。

CLAUDE.mdまたはエージェント定義に以下を追加します。

## Build & Test — Always Use MCP

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

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

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

この指示により、エージェントはまず MCP ツールを使うようになります。これがないと、エージェントがBashで長い xcodebuild コマンドを組み立て、出力の解析に何千ものコンテキストトークンを消費し、ときには実際のエラーを取り違える様子を見ることになります。


iOSプロジェクトのCLAUDE.mdパターン

CLAUDE.mdは、エージェント支援型開発においてプロジェクト内で最も重要なファイルです。エージェントのオンボーディング文書であり、アーキテクチャドキュメントを読んだ新入社員と、推測で進める新入社員ほどの差があります。

私が保守しているすべてのiOSプロジェクトにはCLAUDE.mdがあります。8つのアプリで得た、有効だったパターンを紹介します。

必須セクション

すべてのiOS向けCLAUDE.mdには、次の6つのセクションが必要です。それ以外は任意です。

1. プロジェクトの基本情報

# Return - Zen Focus Timer

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

これが重要な理由: エージェントはコードを書く前に、デプロイメントターゲットを知る必要があります。iOS 17を対象にするエージェントはNavigationView@ObservedObjectを使います。iOS 26を対象にするエージェントはNavigationStack@Observableを使います。Bundle IDはentitlementsやHealthKit設定に関係します。Swiftのバージョンは並行処理モデル(async/awaitかcompletion handlerか、strict concurrencyかlenientか)を決めます。

2. 目的注釈付きファイル構成

## File Structure

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

各ファイル名の後ろにあるインラインコメントは飾りではありません。書けるドキュメントの中で、最も効果が高いものです。エージェントが新機能をどこに追加するか判断するとき、この注釈があれば、プロジェクト構成を理解するために全ファイルを読むのではなく、最初の試行で正しいファイルにたどり着けます。

アンチパターン: 注釈なしでファイルだけを列挙すること。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. フレームワーク固有のコンテキスト

このセクションはアプリによって変わります。分かりにくい設定があるフレームワークでは含めてください。

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)

6つのセクションがどのように連携するかを示す、注釈付きの例です。これはBanana Listで使っているCLAUDE.mdパターンです。Banana Listは、iCloud syncと、アプリのデータをClaude Desktopへ公開するカスタムMCP serverを備えた、53ファイル構成の買い物リストアプリです。

# Banana List - Grocery List App

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

## Core Features

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

## File Structure

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

## SwiftData Models

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

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

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

## Build & Test

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

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

## Key Patterns

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

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

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

## Rules

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

実際のCLAUDE.md: Reps(最小構成のSwiftDataアプリ — 14ファイル)

小規模プロジェクトでは、CLAUDE.mdは簡潔で構いません。ここでは、14ファイル構成のワークアウト記録アプリRepsのパターンを示します。短いCLAUDE.mdでも、6つの必須セクションをすべて押さえている点に注目してください。

# Reps - Workout Tracking

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

## File Structure

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

## Build & Test

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

## SwiftData Relationships

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

## Rules

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

14ファイルのプロジェクトに対して、CLAUDE.mdは40行です。書くのに10分しかかからず、エージェントの混乱を何時間分も減らせます。

実際のCLAUDE.md: Starfield Destroyer(SpriteKit + Metal — 32ファイル)

ゲームプロジェクトでは、より多くのフレームワーク固有コンテキストが必要です。エージェントはscene graph、physics category、ゲーム状態マシンを理解する必要があります。

# Starfield Destroyer - Space Shooter

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

## Game Overview

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

## File Structure

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

## SpriteKit Scene Hierarchy

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

## Physics Categories

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

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

## Game State Machine

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

## Metal Post-Processing

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

## Build & Test

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

## Rules

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

実際のCLAUDE.md: amp97(Metal + Audio Visualization — 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 scene hierarchy、physics category、game loop
大規模(40ファイル以上) + アーキテクチャ図 + 関係マップ + 複数ターゲット情報 Return(63ファイル): クロスプラットフォームアーキテクチャ、session sync図、プラットフォームごとの差分
特化型(Metal/GPU) + パイプライン図 + 共有型定義 + バッファレイアウト amp97(41ファイル): render pipeline stages、uniform struct、buffer management

ドキュメントを書きすぎるコストはほぼゼロです(エージェントは不要な部分を読み飛ばします)。一方、ドキュメント不足のコストは高くなります(エージェントがコードベースと衝突するパターンを作り出します)。

CLAUDE.mdチェックリスト

iOSプロジェクト向けCLAUDE.mdを作成または監査するときは、このチェックリストを使ってください。

  • [ ] Bundle IDとデプロイメントターゲットを明記している
  • [ ] Swiftバージョンとアーキテクチャパターンを明記している
  • [ ] ファイル構成にインラインの目的注釈がある
  • [ ] 正しいschemeとdestinationを使ったビルドコマンドがある
  • [ ] 正しいschemeとdestinationを使ったテストコマンドがある
  • [ ] MCPの優先方針を明記している(”prefer build_sim over xcodebuild”)
  • [ ] @Observableルールがある(ObservableObjectは使わない)
  • [ ] NavigationStackルールがある(NavigationViewは使わない)
  • [ ] .pbxprojの禁止事項がある
  • [ ] フレームワーク固有のコンテキストがある(HealthKit権限、SwiftData relationships、SpriteKit hierarchy、Metal pipeline)
  • [ ] プラットフォーム可用性ガードを記載している(#if canImport、#if os)
  • [ ] 主要なsingletonと共有パターンを記載している
  • [ ] 既知の制限や注意点を記載している

初めてのエージェントセッション

MCP を設定し、プロジェクトに CLAUDE.md を置いたら、効果的な初回セッションの流れは次のようになります。ここでは Claude Code CLI を使いますが、このワークフローはどのランタイムにも適用できます。

ステップ 1: エージェントがプロジェクトを認識できることを確認する

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

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

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

エージェントが CLAUDE.md の内容に触れない場合は、ファイルがプロジェクトルート(.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 のルールによるものです。このルールがなければ、エージェントはプロジェクトファイルを変更しようとして、高い確率で壊してしまいます。


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.

具体性が重要です。「設定ビューを作成して」では汎用的な出力になります。「SettingsSheet.swift の既存パターンに合わせて SettingsView を作成して」と指定すると、コードベースと一貫した出力になります。

SwiftData モデルとクエリ

エージェントは、SwiftData の @Model マクロ、リレーション、@Query パターンを安定して扱えます。このフレームワークの宣言的な性質(Django ORM や SQLAlchemy に近いもの)は、多くのコードベースでエージェントが見てきたパターンとよく対応します。

エージェントが得意な領域: - リレーションを持つ @Model クラスを定義する - ソート記述子と述語を使って @Query を書く - modelContext 経由で CRUD 操作を実装する - スキーマバージョン間のマイグレーション計画を作る - プレビューデータとテストフィクスチャを作る

エージェントにガイダンスが必要な領域: - 複雑な #Predicate 式(SwiftData の述語 DSL には制限があり、エージェントが常に把握しているとは限りません。既知の制限は CLAUDE.md に記載してください) - CloudKit 同期設定(SwiftData 経由で自動化されますが、エージェントが手動同期を実装しようとする場合があります)

ユニットテスト

エージェントが書くユニットテストは、iOS プロジェクトで一貫して高品質です。エージェントは XCTest のパターン、async テストメソッド、setUp/tearDown のライフサイクルを理解しています。

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

エージェントは、setUp()tearDown()、適切なアサーション、タイマーベースのテストに対する async 処理を備えた、よく構造化された XCTest ケースを生成します。

リファクタリングとパターン適用

エージェントは機械的なリファクタリングを得意としています。ビューをコンポーネントに抽出する、ObservableObject@Observable に変換する、NavigationView から NavigationStack に移行する、複数ファイルに一貫したパターンを適用する、といった作業です。

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

エージェントは各ファイルを順に処理し、変換を正しく適用し、既存の機能を維持します。これはレバレッジの高い作業です。手作業なら 1 時間かかるリファクタリングが、ほぼ完璧な精度で数分で完了します。

MCP によるビルドエラー診断

構造化された MCP 出力があれば、エージェントはほとんどの開発者より速くビルドエラーを診断できます。エージェントはエラーの JSON を読み、正確なファイルと行を特定し、エラーメッセージを理解して修正します。多くの場合、1 ターンで完了します。

エージェントが自律的に修正できるエラー: - 不足している 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 呼び出しを通じて実行します。


iOSでエージェントが苦手なこと

エージェントがどこで失敗するのかを正直に整理します。この境界を知っておくと、フラストレーションや無駄なトークン消費を防げます。

.pbxprojファイルの変更 — 絶対にしない

これはiOSエージェント開発で最も重要なルールです。.pbxprojファイルはXcodeのプロジェクト設定です。UUID参照、ビルドフェーズの一覧、ターゲットメンバーシップを含む構造化テキストファイルです。名目上は人間が読めますが、AIエージェントにとっては実質的に解析不能です。

エージェントが.pbxprojで失敗する理由: - ファイルは独自形式(JSONでもYAMLでもXMLでもありません)を使っており、位置に意味があります - すべてのエントリがUUIDで相互参照されています。ファイルを追加するには、3〜5個の異なるセクションを一貫して更新する必要があります - 1文字でも場所を誤ると、プロジェクトファイル全体が壊れます - Xcodeの.pbxprojマージコンフリクト解決はもともと脆弱です。エージェントによる編集はそれをさらに悪化させます

エージェントが.pbxprojを編集すると起きること: 1. 編集は成功したように見えます(エージェントは「file updated」と報告します) 2. Xcodeがプロジェクトを開けなくなります(「The project file is corrupted」) 3. git履歴から復旧するのに15〜60分かかります 4. PreToolUseフックを追加する必要性を学びます(フックを参照)

ワークフロー: エージェントがSwiftファイルを作成します。Xcodeプロジェクトへの追加は手動で行います(Xcodeへドラッグするか、File > Add Filesを使います)。1ファイルあたり5秒で済み、何時間もの復旧作業を防げます。

Swift Package Managerプロジェクトの場合: この制限はそれほど深刻ではありません。Package.swiftは標準的なSwiftファイルなので、エージェントでも安定して編集できます。プロジェクトがSPMのみを使用している場合(.xcodeprojなし)、エージェントがプロジェクト構造全体を管理できます。

複雑なInterface Builder / Storyboard編集

プロジェクトでInterface Builder(.xibファイル)やStoryboard(.storyboardファイル)を使っている場合、エージェントはそれらを意味のある形で編集できません。これらは自動生成UUID、制約参照、アウトレット接続を含むXMLファイルであり、テキスト編集ではなくビジュアル編集を前提に設計されています。

対策: 新しいビューにはSwiftUIだけを使います。プロジェクトにレガシーなInterface Builderファイルがある場合は触らず、新しいUIはSwiftUIで構築しましょう。

パフォーマンス最適化

エージェントは正しいコードを書けますが、必ずしも高性能なコードを書けるわけではありません。アプリをプロファイルしたり、ボトルネックを特定したり、フレームレートを測定したりすることはできません。パフォーマンス最適化には次が必要です。

  1. Instrumentsによるプロファイリング(視覚的なツールであり、エージェントからはアクセスできません)
  2. 特定デバイスのGPU/CPU特性の理解
  3. 測定に基づく反復的な変更

この問題が現れる場所: - Metalシェーダー最適化(エージェントは有効なMetalを書けますが、GPUフレーム時間は測定できません) - SwiftUIのview bodyの複雑さ(エージェントが深くネストしたビューを作成し、再描画オーバーヘッドを引き起こすことがあります) - Core Data / SwiftDataのフェッチ最適化(エージェントは正しいクエリを書けますが、大規模データセットでは遅い場合があります)

対策: 実装にはエージェントを使い、Instrumentsで手動プロファイリングします。そのうえで、特定した最適化をエージェントに適用させます。

コード署名とプロビジョニング

エージェントは、エラーメッセージを読む以上のコード署名問題のデバッグはできません。プロビジョニングプロファイル管理、証明書作成、エンタイトルメント設定、App Store提出は、Apple Developer portal、Keychain Access、Xcodeの署名UIを使う、人間が行うワークフローです。

エージェントに見えるもの: “Signing for ‘Return’ requires a development team.”

エージェントに見えないもの: 証明書が期限切れかどうか、プロビジョニングプロファイルにデバイスが含まれているか、bundle IDがApp IDと一致しているか、エンタイトルメントファイルが正しいかどうかです。

対策: 署名はすべてXcodeのSigning & Capabilitiesタブで処理します。署名失敗のデバッグをエージェントに依頼しないでください。

複雑なMetalシェーダーのデバッグ

エージェントは構文的に正しいMetal Shading Language(MSL)を書けますが、視覚出力の検証やGPU側の問題のデバッグはできません。MetalシェーダーはGPU上で実行されます。シェーダーが正しい視覚結果を生成しているかどうかについて、エージェントにはフィードバック手段がありません。

エージェントがMetalでできること: - 説明に基づいてvertexシェーダーとfragmentシェーダーを書く - SwiftでMetalレンダーパイプラインを設定する - データ並列処理用のcomputeシェーダーを作成する - .metalファイルのコンパイルエラーを修正する

エージェントがMetalでできないこと: - シェーダー出力の視覚的な正しさを検証する - GPUパフォーマンスをデバッグする(フレーム時間、occupancy、メモリ帯域幅) - 視覚的なアーティファクトを診断する(バンディング、精度の問題、誤った色空間) - 異なるGPUアーキテクチャでテストする(A-seriesとM-seriesの挙動差)

対策: Metalシェーダーは実機でテストします。SimulatorのMetal実装は、デバイスのGPU挙動を代表するものではありません。視覚デバッグにはXcodeのGPU Frame Captureを使います。

ビジュアルレイアウト検証

エージェントにはアプリのUIが見えません。SwiftUIレイアウトコードを書き、コンパイルできることは検証できますが、結果の画面が正しく見えるかどうかは判断できません。10ピクセル中心からずれているビュー、誤ったフォントウェイト、要素の重なりは、ビルドエラーを出さず、すべてのロジックテストにも合格します。

対策: UI変更は目視でレビューします。XcodeのSwiftUI Previews(またはヘッドレスレンダリング用のApple MCP経由のRenderPreview)を使ってレイアウトを検証します。自動のビジュアル回帰検出には、swift-snapshot-testingのようなライブラリを使ったスナップショットテストも検討してください。


iOS開発向けHooks

Hooksは、エージェントのワークフロー内の特定の時点で決定的に実行されるシェルコマンドです。強制の仕組みであり、「.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: Entitlementsの変更をブロックする

entitlementsファイルを、エージェントによる意図しない変更から保護します。

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

iOS Hook設定の統合例

以下は、私がすべてのiOSプロジェクトで使っている完全な.claude/settings.jsonです。

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

これにより、2つの保証が得られます。 1. エージェントはXcodeプロジェクトファイルを壊せません(PreToolUseブロック) 2. エージェントが触れたすべてのSwiftファイルは自動フォーマットされます(PostToolUseフォーマット)


エージェントと相性のよい Architecture Patterns

すべての Swift architecture がエージェントに同じくらい扱いやすいわけではありません。以下のパターンは、明示的で一貫しており、学習データでも十分に表現されているため、最もよい結果につながります。

@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 アノテーションが不要)、所有モデルも明確です(@StateObject@ObservedObject の使い分けではなく @State)。動く部分が少ないため、エージェントが生み出すバグも減ります。

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 Concurrency

新規プロジェクトでは Swift 6.2 の strict concurrency をターゲットにします。

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

Concurrency に関するエージェント向けガイド: - すべての view model に @MainActor を付けます(データ競合の警告を防ぎます) - すべての非同期処理には async/await を使います(completion handler は使いません) - actor をまたいで渡す値型は Sendable にします - view での非同期初期化には Task { } を使います - nonisolated は、パフォーマンス上の必要性を測定できた場合にのみ使います

Liquid Glass デザインシステム(iOS 26以降)

iOS 26 では Liquid Glass デザインシステムが導入されました。明示的なガイドを与えれば、エージェントはこれをうまく扱えます。

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

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

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

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

CLAUDE.md に含めてください: 「セクション背景とカードコンテナには .glassEffect() を使います。iOS 26 ではナビゲーションバーが自動的に glass material を採用します。カスタム material で glass effect を手作業で再現しないでください。システム modifier を使います。」


Framework 別の Context

Apple の各 framework には、エージェント固有の注意点があります。このセクションでは、8つのアプリで使った framework を扱います。

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 のシーケンスとグループの作成 - physics body と接触検出の設定 - ゲームステートマシンの実装 - HUD オーバーレイの構築

SpriteKit におけるエージェントの苦手分野: - パフォーマンスが重要なゲームループ(エージェントはフレームごとに不要な処理を追加しがちです) - 複雑な physics シミュレーション(精度が必要な場合は、SKPhysicsBody よりカスタム physics が向いています) - particle effect の調整(視覚的な作業であり、反復が必要です)

Metal

使用しているアプリ: amp97, Water, Starfield Destroyer

Metal は、エージェントが最も苦戦する framework です。GPU のプログラミングモデルは CPU 側の Swift とは根本的に異なり、エージェントは視覚的な出力を検証できません。

## Metal Rules

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

Metal プロジェクトで CLAUDE.md に含めるべき内容: - Uniforms struct の定義(Swift と MSL で共有) - render pipeline state の設定パターン - buffer index とその用途 - 存在する 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
    }
}

高度なワークフロー

自律的なBuild-Test-Fixループ

最も強力なパターンは、エージェントに機能仕様を渡し、build-test-fixサイクルを自律的に反復させることです。

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回のbuild-error-fixサイクルが必要になる機能も、1回の自律ループで完了します。

うまく機能する場合: 受け入れ基準が明確な、よく定義された機能。

破綻しやすい場合: オープンエンドな機能(「見た目をいい感じにして」)、パフォーマンスに敏感なコード、または視覚的な検証が必要なもの。

iOS向けSubagent Delegation

Claude Codeのsubagentシステムは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.

subagentは別のコンテキストウィンドウでドキュメントとコードパターンを調査し、要約を返します。その後、メインセッションが推奨内容を実装します。これにより、調査で主要なコンテキストを消費せずに済みます。

アプリ間でのパターン適用

一貫したパターンで複数の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)

重要な変更では、異なるモデルファミリーの2つのエージェントを使います。

  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 relationship cycles 中程度 強い(GPT-4o)
@MainActor isolation gaps 強い 中程度
Metal buffer alignment 中程度 中程度
Retain cycle detection 強い(Opus) 強い(o3)
API deprecation awareness 強い(新しいトレーニングデータ) 中程度
Concurrency race conditions 強い 強い(異なるパターンを検出)

デュアルレビューの目的は、より多くのバグを見つけることではありません。異なるバグを見つけることです。各モデルファミリーには、パターン認識において異なる失敗モードがあります。

複数アプリにまたがるバッチ操作

フレームワークやパターンの変更が複数のアプリに影響する場合:

# 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フラグは非対話モードに必要ですが、すべての安全チェックを迂回します。.pbxprojファイルを保護するため、PreToolUse hooksが設定されていることを確認してください。

AppleのオンデバイスLLMを使用するアプリ

アプリがAppleのFoundation Modelsフレームワークを呼び出す場合(オフライン要約、分類、構造化出力の生成など)、エージェントはプロンプトの予算を把握している必要があります。iOS 26.4では、以前の4096トークンという推測を置き換える2つのAPIがSystemLanguageModelに追加されました。contextSize(モデルが1つの会話で受け入れる最大トークン数)と、tokenCount(for:)async throwsで、指定したプロンプトが実際に消費するトークン数を返します)です。17 どちらも@backDeployed(before: iOS 26.4)なので、#availableの分岐を組まなくても、FMをサポートするすべてのOSバージョンで利用できます。

エージェントがプロンプト構築コードを生成するときに従うべきパターンは次のとおりです。

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つのアプリから、agent支援によるiOS開発が実際にどう機能するのかを示す具体的なシナリオを紹介します。失敗例も含めています。

ケーススタディ 1: ReturnへのTVアプリ追加(成功)

タスク: すでにiOS版とwatchOS版がある瞑想タイマーReturnに、tvOSターゲットを追加することでした。TVアプリには、Siri Remoteナビゲーション、大画面向けUI、iOSアプリとの設定同期が必要でした。

agentがうまくできたこと: - 既存のiOS TimerManagerを読み、tvOSでは利用できないLive ActivitiesとHealthKitを省いたTVTimerManagerを作成しました - Siri Remoteのフォーカスナビゲーション向けに、カスタムボタンスタイル(TVCapsuleButtonStyleTVCircleButtonStyle)を作成しました - Siri Remoteでは使いにくいホイールピッカーを、+/-ボタンに置き換えるTVStepperコンポーネントを構築しました - 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エンタイトルメントを設定する - 既存のスキームにTVターゲットを追加する、または新しいスキームを作成する - agentが作成したすべてのSwiftファイルを、TVターゲットに手動で追加する - Siri Remoteナビゲーションを手動でテストする(agentはフォーカス挙動を評価できません)

結果: 約3時間のagent支援作業で、15個の新しいSwiftファイルと、完全に動作するTVアプリができました。私の見積もりでは、実装作業のおよそ80%をagentが担当し、Xcode UI操作が必要な部分(エンタイトルメント、ターゲット設定、機能フラグ)と、実機のApple TVでのフォーカステストを私が担当しました。このコードベースで同等の作業を1人で行う場合、過去にagentなしで出荷した類似機能を基準にすると、数日かかる作業だったはずです。

ケーススタディ 2: amp97のMetalシェーダーデバッグ(一部失敗)

タスク: オシロスコープシェーダーに、エネルギーベースの強度システムを追加することでした。ビジュアライゼーションが音声エネルギーに合わせて脈動する必要がありました。

起きたこと: 1. agentは、uEnergy uniformとHDRトーンマッピングを追加する、有効なMetalシェーダー変更を書きました 2. コードはエラーなくコンパイルされました 3. 実機では、ビジュアライゼーションが完全に白く表示されました。強度係数が10倍高すぎたのです(0.30ではなく3.5) 4. agentには白い画面が見えないため、フィードバック信号がありませんでした 5. 私が視覚的に問題を特定し、係数を下げるようagentに依頼しました 6. agentは係数を下げましたが、全体のエネルギーステートマシンが複雑すぎて、別の形でビジュアライザーを壊しました 7. 完全にrevertしました。2つのコミット(67959edcda4830)を869d914でrevertしました

教訓: Metalシェーダーは、agent支援開発で最も難しい領域です。フィードバックループが切れているからです。agentは構文(コンパイルできること)と意味論(型が正しいこと)は検証できますが、出力(見た目が正しいこと)は検証できません。視覚的挙動を変えるシェーダー変更には、必ず実機での人間による検証が必要です。

この後CLAUDE.mdに追加したこと: 「極めて慎重な係数テストなしに、オシロスコープシェーダーのエネルギーステート変更を試みないこと。前回の試みでは係数が10倍高すぎて、ビジュアライザーが壊れた。」

ケーススタディ 3: Banana ListのSwiftDataマイグレーション(成功)

タスク: データモデルをV1からV2へマイグレーションし、GroceryItemquantityフィールドを追加し、リレーションを持つ新しいCategoryモデルを追加することでした。

agentが行ったこと: 1. 既存のV1モデル定義を読みました 2. 新しいフィールドとリレーションを含むV2モデル定義を作成しました 3. SchemaMigrationPlanプロトコルに準拠したGroceryMigrationPlanを書きました 4. V1toV2マイグレーションステージを実装しました。デフォルトのquantity: 1category: nilを追加しました 5. 新しいフィールドに対応するよう、すべてのビューを更新しました 6. プレビュー向けにSampleData.swiftを更新しました 7. MCP経由でビルドとテストを実行し、すべて合格しました 8. マイグレーション専用のユニットテストを作成しました

要点: SwiftDataマイグレーションは、Appleのドキュメントと学習データに十分含まれている、明確なプロトコルパターンに従うため、agentは成功しました。CLAUDE.mdにV1モデルが明示的に記録されていたため、agentは何からマイグレーションするのかを理解できました。

ケーススタディ 4: ReturnのiCloudセッション同期(複雑だが成功)

タスク: デバイス間の瞑想セッション記録を実装することでした。Apple TVやMacで完了したセッションを、HealthKit記録のためにiPhoneへ同期する必要がありました。

agentが生成したもの:

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

agentは次を行いました。 1. UUID、日付、継続時間、ソースデバイス、HealthKit同期ステータスを持つMeditationSessionデータモデルを作成しました 2. iCloud同期向けにNSUbiquitousKeyValueStoreを管理するSessionStoreシングルトンを構築しました 3. マージ競合解決(UUIDベースの重複排除)を実装しました 4. プラットフォーム別の調整を含むSessionHistoryViewを追加しました(iOSではスワイプ削除、tvOSではフォーカスベース) 5. 他デバイスからのセッションに対して、iPhone側のHealthKit同期を接続しました

反復が必要だったこと: 初期実装では、iPhoneアプリがバックグラウンドで起動するケースを扱えていませんでした(同期のためのフォアグラウンド通知がありません)。agentには具体的な指示が必要でした。「バックグラウンドのKV変更で同期をトリガーするために、NSUbiquitousKeyValueStore.didChangeExternallyNotificationを使う」。このヒントの後、実装は正しくなりました。

教訓: アーキテクチャが明確に説明されていれば、agentはマルチプラットフォームのアーキテクチャパターンをうまく扱えます。iCloud同期パターンは単純ではありませんが、Appleのドキュメント化されたパターンに従っており、agentはそれを理解しました。エッジケース(バックグラウンド同期)には、人間のドメイン知識が必要でした。十分に文書化されていないためです。

ケーススタディ 5: Starfield DestroyerのGame Center統合(成功)

タスク: 宇宙シューティングにGame Centerのリーダーボードと実績を追加することでした。

agentがうまくできたこと: - アプリのエントリーポイントにGKLocalPlayer.local.authenticateHandlerを実装しました - スコア送信と実績報告のメソッドを持つGameCenterManagerを作成しました - すべてのGame Center操作の前に、認証状態チェックを追加しました - オフライン時のケースを適切に扱いました(Game Centerなしでもゲームはプレイでき、再接続時に送信されます) - 8機の機体進行システムに合わせた実績定義を作成しました

手動作業が必要だったこと: - App Store Connectでリーダーボードと実績を作成する(Webポータルであり、agentはアクセスできません) - XcodeでGame Centerエンタイトルメントを設定する - サンドボックスのGame Centerアカウントでテストする(実機での手動サインインが必要です)


エージェントを使ったプロジェクトライフサイクル

新しい iOS プロジェクトを始める

エージェント支援で新しいプロジェクトを始める場合の最適なワークフローは次のとおりです。

フェーズ 1: 人間によるセットアップ(15〜30分) 1. Xcode プロジェクトを作成します(File > New > Project) 2. 署名とCapabilitiesを設定します 3. デプロイメントターゲットと対応する実行先を設定します 4. 必要なエンタイトルメントを追加します(HealthKit、Game Center など) 5. プロジェクトの識別情報とルールを含む最初の CLAUDE.md を作成します

フェーズ 2: エージェントによる実装(数時間〜数日) 1. エージェントがデータモデルを作成します(SwiftData、Core Data、またはプレーンな構造体) 2. エージェントが、文書化されたパターンに従ってビューを構築します 3. エージェントが manager/service クラスにビジネスロジックを実装します 4. エージェントがユニットテストを書きます 5. MCP による build-test-fix ループを実行します(自律)

フェーズ 3: 人間による統合(30〜60分) 1. エージェントが作成したファイルを Xcode ターゲットに追加します 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 ターゲット いいえ 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.

これでは汎用的で浅いテストになり、エッジケースを見逃しやすく、プロジェクトのパターンに従わない可能性があります。

Async テストパターン

タイマー ベースや async コードをテストする場合は、次のようにします。

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

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

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

        // When
        sut.start()

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

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

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

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

エージェントに再確認させるべき重要なパターン: - @MainActor クラスをテストするテストメソッドには @MainActor を付ける - Task.sleep や async 処理を使うテストには async throws を使う - 時間ベースのアサーションには許容誤差を持たせる(正確に 1.0 秒ではなく、1.1 秒など) - テスト分離のために、クリーンな setUp() / tearDown() を用意する

Snapshot Testing

ビジュアルリグレッション検出には、swift-snapshot-testing の追加を検討してください。

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

Use SnapshotTesting library. Create reference images on first run.

エージェントは snapshot テストを正しくセットアップできますが、参照画像をレビューすることはできません。最初のスナップショットは人間がレビューし、その後はエージェントのテストが将来の変更でビジュアルリグレッションを検出します。

iOS プロジェクトのコンテキストウィンドウ管理

1Mのコンテキストウィンドウ(Opus 4.6)は大きいですが、無限ではありません。iOS プロジェクトには、コンテキスト管理で固有の考慮点があります。

iOS ファイルのトークンコスト

ファイル種類 一般的なサイズ 概算トークン数
SwiftUI ビュー(シンプル) 50-100行 500-1,000
SwiftUI ビュー(複雑) 200-400行 2,000-4,000
SwiftData モデル 30-80行 300-800
Manager/service クラス 100-300行 1,000-3,000
Metal shader (.metal) 50-200行 500-2,000
Unit test ファイル 50-200行 500-2,000
CLAUDE.md 100-300行 1,000-3,000
MCP response(build) さまざま 200-2,000
MCP response(test) さまざま 500-5,000

50ファイルのプロジェクトの場合: すべてのファイルを読むと、およそ50,000-100,000トークンを消費します。1Mのウィンドウには十分収まります。Agent はプロジェクト全体をコンテキストに保持できます。

100ファイル以上のプロジェクトの場合: 選択的に読む必要が出てきます。Agent はまず CLAUDE.md(ファイル構造の注釈)を読み、その後必要に応じて特定のファイルを読みます。だからこそ、CLAUDE.md のファイル注釈が重要です。すべてを読まなくても、Agent を適切なファイルへ導けます。

大規模プロジェクト向けの戦略

  1. 詳細な CLAUDE.md ファイル注釈 — Agent がファイルマップを読み、関連ファイルへ直接移動できます
  2. Subagent への委任 — 探索や調査を subagent に振り分けます(クリーンなコンテキストで実行し、要約を返します)
  3. 焦点を絞ったプロンプト — 「SettingsView.swift に新しい toggle を追加する」は、「設定を更新する」より適切です
  4. セッション境界 — 長いセッションを延ばすより、無関係な機能では新しいセッションを開始します
  5. /compact を使う — Claude Code の compaction コマンドは会話を要約し、コンテキストを空けます

MCP のトークン効率

MCP を使う強力な理由の1つは、構造化された JSON responses が、生の xcodebuild 出力よりはるかに少ないトークンで済むことです。

シナリオ 生の Bash トークン数 MCP トークン数 削減率
成功した build 3,000-10,000 200-500 85-95%
失敗した build(1 error) 3,000-10,000 300-800 90-92%
Test results(20 tests) 2,000-5,000 500-1,000 75-80%
Simulator list 500-2,000 200-400 60-80%

10-20回の build cycle がある一般的な開発セッションでは、MCP は生の xcodebuild と比べて30,000-150,000トークンを節約できます。その分のトークンを、実際のコード推論に使えます。


トラブルシューティング

“build_sim failed — scheme not found”

Agent が 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 tools not appearing in Claude Code”

セッション途中で登録した MCP tools は、再起動するまで表示されない場合があります。Claude Code を終了し、新しいセッションを開始してください。

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

その後、確認します。

You: List all available MCP tools from XcodeBuildMCP.

“Agent keeps using xcodebuild via Bash instead of MCP”

Agent が Tool Search 経由で MCP tools を発見できていません。修正方法は2つあります。

  1. CLAUDE.md に明示的なガイダンスを追加するAgent に MCP の使い方を教えるを参照)
  2. 直接プロンプトする: “Use the build_sim MCP tool, not xcodebuild via Bash”

“Build succeeds but agent reports failure”

XcodeBuildMCP は xcodebuild 出力を解析します。build がエラーのように見える警告を出す場合(非推奨警告でよくあります)、Agent が結果を誤解することがあります。MCP response の実際の status field を確認してください。

“Simulator hangs during boot”

すべての simulators を終了して再起動します。

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

または、Agent に依頼します。

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

“Agent tried to modify .pbxproj despite CLAUDE.md rules”

CLAUDE.md のルールは提案です。Hooks は強制です。.pbxproj への書き込みをブロックする PreToolUse hook がない場合、Agent はいずれ変更を試みます。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'"
      }
    ]
  }
}

Rules は「やめてください」と伝えます。Hooks は「できません」と止めます。

FAQ

どのagent runtimeから始めるべきですか?

Claude Code CLI with XcodeBuildMCPから始めましょう。最も深いMCP統合、最も成熟したhookシステム、そしてiOSプロジェクト全体をworking memoryに保持できる1M context window(Opus 4.6)があります。まずはここから始め、workflowが成熟してきたら、review用にCodex、短いinline編集用にXcode native agentsを追加してください。

両方のMCPサーバーが必要ですか?

ほとんどの開発者には、XcodeBuildMCPだけでニーズの90%(build、test、simulator、debugging)をカバーできます。documentation検索、Swift REPL verification、SwiftUI preview renderingが必要な場合は、AppleのXcode MCPを追加してください。2つのサーバーは独立しているため、あとからいつでも追加できます。

agentsは新しいXcodeプロジェクトをゼロから作成できますか?

XcodeBuildMCPには、新しいXcodeプロジェクトをscaffoldするcreate_projectツールがあります。ただしproductionアプリでは、まずXcodeでプロジェクトを作成することをおすすめします。signing、capabilities、target configurationを正しく設定するためです。そのうえで、すべてのcode implementationにagentsを使います。Xcodeのnew project wizardに5分かけることで、agentが生成したproject configuration問題に何時間も費やす事態を避けられます。

agentsはSwift Package Manager dependenciesをどう扱いますか?

かなりうまく扱えます。Package.swiftは標準的なSwiftファイルなので、agentsは安定して読み書きできます。dependenciesの追加、version rangeの更新、targetsの設定はいずれも機能します。制約があるのは.xcodeprojベースのdependency管理(Xcodeのpackage resolution UI)です。これはXcodeが管理する領域なので、agentで編集すべきではありません。

agentsはApp Storeにsubmitできますか?

いいえ。App Store submissionには、XcodeのOrganizer、provisioning profiles、screenshots、metadata、App Store Connect portalが関わります。これらはMCPやcommand-line tools経由で、agentsが意味のある形で操作できるものではありません。agentsが担当できるのはarchiveの手前まで、つまりimplementation、testing、bug fixing、documentationです。submissionの最後の一歩は、引き続き人間が操作します。

ただし、agentsはApp Store metadataの作成には役立ちます。最新の変更内容をもとに、アプリのdescription、keywords、what’s-new textを書くよう依頼してください。これはagentsが得意なtext generation作業です。

agent支援のiOS開発でsecretsやAPI keysをどう扱えばよいですか?

secretsは絶対にcommitしないでください。backend APIsに接続するiOSアプリでは、次のようにします。

  1. 環境別の設定には.xcconfigファイルを使います
  2. .xcconfigファイルを.gitignoreに追加します
  3. Info.plistのbuild settings経由でconfig valuesを参照します
  4. 必要なsecretsは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`.

agentはkeysが存在することと使われる場所を把握しますが、実際の値を見ることはありません。

SwiftUI animationsはどうですか。agentsは書けますか?

agentsはanimation codeを構文的にはうまく書けますが、結果を視覚的に検証できません。単純なanimations(.animation(.spring()).transition(.slide)withAnimation { })なら正しい結果になります。正確なtimingが必要な複雑なmulti-step animationsは、agentsにはできないvisual iterationが必要です。

有効: 「timerがstate間でtransitionするときにspring animationを追加してください。」

無効: 「timer animationが気持ちよく感じられるようにしてください。」(主観的で、visual tuningが必要です。)

agentsはerror handling patternsをどう扱いますか?

非常にうまく扱えます。agentsはSwiftのdo/catchResultasync throws patternsを理解しています。

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

agentsは適切なuser-facing messagesを含むstructured error handlingを生成します。ただし、ときどきerrorsを過剰に扱うことがあります(propagateすべきexceptionsをcatchするなど)。catch blocksはreviewしてください。

accessibility implementationにagentsを使えますか?

一部は使えます。agentsは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

agentsにできないことは、VoiceOverのnavigation orderが正しいかの検証、Dynamic Type scalingのtest、color contrast ratiosの評価です。検証にはXcodeのAccessibility Inspectorを使ってください。

SwiftDataを使っていない場合、Core Data migrationはどう扱いますか?

agentsはCore Data migration mappingsやmodel versionsを書けますが、手動のXcode手順(新しいmodel versionsの作成、current versionの選択)は自動化できません。SwiftDataではなくまだCore Dataを使っている場合は、CLAUDE.mdにmodel version historyを記録してください。

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

agentsはSwiftUI previewsをどう扱いますか?

方法は2つあります。 1. Apple Xcode MCPのRenderPreviewツールはpreviewsをheadlessにrenderし、結果を返します。agentはpreviewがcompileされ、errorsなしでrenderされることを確認できますが、visual correctnessは評価できません。 2. build_simによるbuild-based verificationでは、preview providersがcompileされることを確認できます。previewがruntimeでcrashしてもbuildは成功します。crashが現れるのは、Xcodeがpreviewをrenderしようとしたときだけです。

previewsのvisual verificationには、やはりXcodeを開く必要があります。

visionOSとApple Vision Proはどうですか?

同じpatternsが適用できます。XcodeBuildMCPはvisionOS simulatorsをサポートしており、architectural patterns(@Observable、NavigationStack、SwiftData)も同じです。RealityKit固有のcode(3D content、immersive spaces、hand tracking)はMetalと同じ制約があります。agentsは正しいcodeを書けますが、spatial outputは検証できません。

agentsが苦しくなるproject sizeはどのくらいですか?

制約になるのはcontext window sizeです。Opus 4.6の1M token windowがあれば、Claude Codeは約50〜70個のSwiftファイルを同時にactive working memoryへ保持できます。さらに大きなプロジェクトでは、agentはfile searchとselective readingを使い、codebaseの一部を対象に作業します。100以上のファイルがあるプロジェクトでも問題なく動きます。すべてをcontextに保持するのではなく、必要に応じてファイルを読むだけです。

実用上の限界はfile countではなく、codebase coherenceです。詳細なCLAUDE.mdがある、よくdocumentedされた200ファイルのプロジェクトのほうが、documentationのない30ファイルのプロジェクトより良い結果になります。

iOS開発でagentsを使うにはSwiftを知っている必要がありますか?

agent outputをreviewし、architectural decisionsを下せる必要があります。すべての行を自分で書く必要はありませんが、agentが誤った選択をしたときに気づける程度にはSwiftを理解している必要があります。特にconcurrency、memory management、framework-specific patternsの周辺です。agentは既存のskillを10倍に増幅するものであり、代替するものではありません。

agentsはSwiftファイルのmerge conflictsをどう扱いますか?

agentsはSwift source filesのmerge conflictsを安定して解決できます。標準的なconflict markers(<<<<<<<=======>>>>>>>)は、すべてのagent runtimesがよく理解しています。ただし、.pbxprojファイルのmerge conflictsは引き続き手動で解決する作業です。.pbxproj conflictsの解決をagentsに依頼しないでください。

iOS開発でagentsを実行するcostはどのくらいですか?

AnthropicのMax plan(Opus 4.6、1M context)では、一般的なiOS development sessionは30〜120分で、200K〜800K tokensを処理します。MCP tool callsによるoverheadは最小限です(structured JSON responsesは、raw build outputと比べてtoken効率が高いためです)。costは、他のcodebaseでClaude Codeを実行する場合と同程度です。iOS開発がweb developmentより大幅に高くなったり安くなったりするわけではありません。

UIKit projectsでもagentsを使えますか?

はい。ただしagentsはSwiftUIのほうが効果的です。UIKitはboilerplateが多く、declarative structureが少なく、agentsが編集できないInterface Builder filesを伴うこともよくあります。UIKit projectがある場合は、UIは手動で扱いながらmodel layerやbusiness logicにagentsを使うか、viewsを段階的にSwiftUIへ移行することを検討してください。

agentsはlocalizationをどう扱いますか?

agentsは.xcstrings(Xcode string catalog)ファイルを効果的に作成・編集できます。新しいlocalization keysの追加、translationsの提供、languages間のconsistency維持が可能です。.xcstringsファイルのstructured JSON formatはagentに扱いやすい形式です。.stringsファイル(legacy format)でも、agentsはうまく処理できます。key-value formatが単純だからです。


iOSでよくあるAgentのミス(と防ぎ方)

ここでは、8つのiOSプロジェクトで数千回のAgentとのやり取りを通じて観察した、繰り返し起きるエラーをまとめています。それぞれに予防策があります。

ミス1: Observableパターンを混在させる

何が起きるか: Agentがあるファイルでは@Observableを使い、別のファイルではObservableObjectを使います。あるいは、すでにObservableである@Modelクラスに@Observableを追加してしまいます。

予防策: CLAUDE.mdに明示的なルールを書きます。

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

ミス2: クロージャでRetain Cycleを作る

何が起きるか: Agentがselfを強参照でキャプチャするクロージャを作ります。特にTimer.publishNotificationCenter、completion handlerで起きやすいです。

予防策: 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が@MainActor分離なしで@Observableクラスを作り、UI更新がメインスレッド外で発生したときにSwift 6.2の並行処理警告やランタイムクラッシュを引き起こします。

予防策:

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

ミス4: Destination Closure付きのNavigationLinkを使う

何が起きるか: Agentが、型安全なNavigationLink(value:) + .navigationDestination(for:)パターンではなく、非推奨のNavigationLink(destination:label:)を使います。

予防策:

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

ミス5: Simulator名をハードコードする

何が起きるか: Agentが、システムに存在しない可能性のある特定のSimulator名(”iPhone 16 Pro”)を使ってビルドコマンドを書きます。

予防策: これはMCPが処理します。list_simsが利用可能なSimulatorを検出します。CLAUDE.mdでは次のようにします。

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

ミス6: 間違ったディレクトリにファイルを作る

何が起きるか: Agentが新しいViewファイルをViews/サブディレクトリではなくプロジェクトルートに作ったり、modelを間違ったグループに置いたりします。

予防策: CLAUDE.mdのファイル構造アノテーションが配置を案内します。加えて、次のようにします。

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

ミス7: Platform Availabilityを扱わない

何が起きるか: Agentが、tvOS向けにもコンパイルされる共有コードでHealthKitを使ったり(tvOSではHealthKitは利用不可)、watchOSコードでActivityKitを使ったりします。

予防策:

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

ミス8: シンプルな機能を過剰設計する

何が起きるか: 本来は20行のユーティリティ関数で済むはずのものに対して、Agentがprotocol、protocol extension、具体実装、factory、dependency injection containerを作ってしまいます。

予防策: シンプルさの原則を含めます。

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

正直な評価

AI Agentで8つのiOSアプリを出荷してきた結果をまとめると、次のようになります。

Agentが変えたもの: 実装速度です。数日かかっていたことが数時間で済むようになりました。SwiftUI View、SwiftData model、unit test、refactoringは、いまでは主にAgentが生成し、人間がレビューするものになっています。

Agentが変えなかったもの: アーキテクチャ判断、ビジュアルデザイン、パフォーマンス最適化、App Store提出です。これらは今も人間主導です。

倍率効果は本物ですが、限界もあります。 8アプリのポートフォリオ全体での主観的な見積もりでは、適切なMCPとhook設定があり、よく文書化されたプロジェクトでは、機能追加までの時間が3〜5倍改善しました。これはcontrol groupと比較して測定したものではありません。同じコードベース内で、Agent支援による機能実装と同等の単独作業を、実時間で比較したものです。文書化されておらずhookもないプロジェクトでは、おそらく1.5〜2倍程度です。Agentが構築するよりも推測に時間を使いすぎるためです。19

投資に見合うもの: CLAUDE.md、hook、MCP設定に使う時間です。セットアップに1時間かけるたびに、Agentのミスを修正する多くの時間を節約できます。設定こそがプロダクトであり、Agentは実行エンジンです。

意外だったこと: MCPサーバーが、やり取りの構造を大きく変えたことです。MCP以前のAgentは、Swiftを理解する高機能なテキストエディタでした。MCP以後は、書き、ビルドし、テストし、デバッグし、反復する開発パートナーになりました。構造化されたフィードバックループこそが、コードを書くAgentと、コードを出荷するAgentの違いです。

過去の自分に伝えるなら: まず最小のアプリ(Reps、14ファイル)から始め、MCPとhookのセットアップを正しく整え、充実したCLAUDE.mdを書き、そのパターンを大きなプロジェクトへ広げましょう。63ファイルのマルチプラットフォームアプリから始めてはいけません。インフラへの投資は、プロジェクトの規模に関係なく同じです。小さなプロジェクトで一度行い、それをほかのすべてにコピーします。

今後: Xcode 26.3のネイティブAgent統合は終点ではなく始まりです。AppleがMCPサポートを出荷したことで、ツールチェーンはAgent-first開発へ向かっています。今のうちにAgentと相性のよいプロジェクト構造、つまり整理されたCLAUDE.mdファイル、テストしやすいアーキテクチャ、自動化されたhookへ投資する開発者は、ツールの改善とともにその投資を複利で伸ばしていけるでしょう。


クイックリファレンスカード

インストール(1回限りのセットアップ)

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

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

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

# Verify
claude mcp list

必須のCLAUDE.mdセクション

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

必須のHooks

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

アーキテクチャルール

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

MCPツールの優先順位

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

変更履歴

日付 変更内容
2026-05-24 Xcode 26.5 の安定版リリース日を 2026-05-11 に修正し、Apple のリリースページに基づいてビルドを 17F42 に固定しました。このパスでのローカル検証: xcodebuild -versionXcode 26.5 / Build version 17F42 を返し、xcodebuildmcp の npm latest は 2.5.2time.modified2026-05-12T07:40:41.737Z でした。13
2026-05-16 推奨 Xcode を 26.5+(2026-05-11 リリース)に更新しました。エージェントワークフローで重要な Coding Intelligence の新機能が2つあります。コーディングアシスタントでメッセージをキューに入れられるようになり、次の依頼を並べる前に応答を待つ必要がなくなりました。また、エージェントが処理を進める前に確認質問をできるようになりました。どちらも、Xcode のネイティブエージェントを Claude Code や Codex セッションと並行して動かす際の摩擦を減らします。13 XcodeBuildMCP の最新性チェック: v2.5.2(2026-05-12)が最新で、バンドルされた AXe 1.7.0 と、ログキャプチャのフィルター検証問題の修正が追加されています。v2.1.0+ からの xcodebuildmcp init フローは、引き続き推奨インストール手順です。
2026-04-28 エージェントワークフロー向けの推奨 Xcode を 26.4+ に更新しました(26.4.1、2026-04-16、ビルド 17E202 が最新安定版で、バグ修正のみ)。エージェントが書くテストとローカリゼーションに有用な Xcode 26.4 の機能(2026-03-24、ビルド 17E192)を引用しました: Swift Testing の画像添付、Issue.record の severity、クラッシュログ付きの UI-test クラッシュ警告(特に XCUIApplication(bundleIdentifier:) / XCUIApplication(url:) アプリ向け)、String Catalog エディタの改善。手動の MCP セットアップに代わる手順として、xcodebuildmcp init 自動インストーラー(v2.1.0+、2026-02-23)を追加しました。
2026-04-27 App Store Connect: 2026-04-28 から Xcode 26+ での提出が必須になります。Foundation Models に SystemLanguageModel.contextSizetokenCount(for:) APIs が追加されました(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 telemetry が含まれています。プロジェクトの privacy documentation には、送信される内容が詳述されています: エラーメッセージ、スタックトレース、場合によってはファイルパスです。XCODEBUILDMCP_SENTRY_DISABLED=true env var で完全にオプトアウトできます。 

  2. Anthropic、「Model Context Protocol Specification」、modelcontextprotocol.io/specification。MCP 仕様は、XcodeBuildMCP と Apple の Xcode MCP の両方が実装する JSON-RPC transport、ツール検出、リソースプロトコルを定義しています。 

  3. XcodeBuildMCP、github.com/getsentry/XcodeBuildMCP。オープンソースで、Sentry がメンテナンスしています。シミュレーター、デバイス、デバッグ、UI automation ワークフローにまたがる59個のツールがあります。changelogs 付きのセマンティックバージョニングです。 

  4. Apple は、Xcode 26.3 intelligent developer tools initiative の一部として Xcode MCP server を導入し、AI coding assistants と Xcode toolchain の間のインターフェース層として MCP を位置づけました。公式ドキュメントは 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 commands に限定されたエージェントを大きく上回りました。この結果は、エージェントの有効性における構造化 MCP インターフェースの価値を裏づけています。 

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

  8. SwiftFormat、github.com/nicklockwood/SwiftFormat。一貫したコードスタイルのために PostToolUse hooks で使用する Swift formatting tool です。 

  9. XcodeBuildMCP official site、xcodebuildmcp.com。CLI output example によって59個の MCP ツールを確認できます。ツールカテゴリ: シミュレーター、デバイス、デバッグ、UI automation。Homebrew または npx でインストールします。 

  10. Swiftjective-C、「Agentic Coding in Xcode 26.3 with Claude Code and Codex」、swiftjectivec.com、2026年2月。Xcode 26.3 が Settings > Intelligence 経由でネイティブ Claude Agent と Codex runtime support を同梱していることを確認しています。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 の項目: 「Apps uploaded to App Store Connect must be built with Xcode 26 or later using an SDK for iOS 26, iPadOS 26, tvOS 26, visionOS 26, or watchOS 26.」この要件で列挙されたプラットフォームには macOS は含まれていません。 

  13. Apple、“Xcode 26.5 Release Notes” および “Xcode 26.5 (17F42) - Releases”。Xcode 26.5 は、Apple により 2026-05-11 にビルド 17F42 として掲載されました。リリースノートから引用した Coding Intelligence の機能は2つです: 現在の応答完了を待たずに、コーディングアシスタントでメッセージをキューに入れられること(174563016)、そしてエージェントが処理前に確認質問をしてコンテキストを集められること(175182375)。また、12か月契約の月額サブスクリプション向け StoreKit Testing support(PricingTerms model、billingPlanType PurchaseOptionTransactionSubscriptionRenewalInfoCommitmentInfo)と、async/await 操作中にスレッドを移動する Swift Tasks をステップ実行する際の Swift debugger 修正も含まれます。2026-05-24 の現セッション検証: xcodebuild -versionXcode 26.5Build version 17F42 を返し、npm view xcodebuildmcp version dist-tags.latest time.modified --json は latest 2.5.2time.modified 2026-05-12T07:40:41.737Z を返しました。あわせて参照: 9to5Mac、“Xcode 26.5 adds two features that make agentic coding more useful”、2026-05-12。 

  14. Apple、“Xcode 26.4 Release Notes”。Xcode 26.4(2026-03-24、ビルド 17E192)。リリースノートから引用した機能: Swift Testing が CGImageNSImageUIImageCIImage による画像添付をサポートするようになりました。Issue.record は severity levels を受け付けます。一部の UI-test app crashes、具体的には XCUIApplication(bundleIdentifier:) または XCUIApplication(url:) を通じて操作されるアプリは、テスト失敗ではなく、添付クラッシュログ付きの警告として報告されます。String Catalog editor には、entries の cut/copy/paste、言語削除、既存言語からの翻訳プリフィルに加え、BUILD_ONLY_KNOWN_LOCALIZATIONS setting が追加されました。 

  15. Apple Developer News、“Xcode 26.4.1 (Build 17E202) Now Available”、2026-04-16。バグ修正のみの dot release です。iOS / macOS / visionOS pre-26.4 での missing symbols による MetricKit crash と、Swift async stack-allocation bug(swift_asyncLet_finish 内の「freed pointer was not the last allocation」)を修正しています。 

  16. getsentry/XcodeBuildMCP v2.1.0 release、2026-02-23。agent skills + MCP config を1ステップでインストールする xcodebuildmcp init CLI command が追加され、単体の install-skill.sh script を置き換えました。Claude Code、Cursor、Codex を自動検出します。--print(非対応クライアント向けに config を stdout へ書き出す)と --uninstall(削除)をサポートします。 

  17. InfoQ、“Apple Adds Context Window Management to Foundation Models”、2026年3月。新しい SystemLanguageModel.contextSizetokenCount(for:) APIs を文書化し、@backDeployed(before: iOS 26.4) annotations を確認しています。従来のコミュニティ推測である4096-token のハードコードを置き換えます。 

  18. ファイル数は、2026-04-27 に8つの private app repositories それぞれに対して find . -name '*.swift' -not -path '*/Tests/*' | wc -l を実行して得たものです。テストファイルは除外しています。合計は、§The Portfolio のアプリ別内訳表と内部的に整合しています。 

  19. 主観的な wall-clock estimate であり、control group に対する測定ではありません。3-5x という数字は、2026年のエージェント支援機能と、エージェントワークフロー導入前に同じ codebases で単独で出荷した同等機能の time-to-feature 比較について、著者の記憶に基づくものです。ベンチマークではなく、MCP + hook setup 後に期待できる感覚値として扱ってください。 

NORMAL ios-agent-development.md EOF