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

AI 에이전트로 iOS 앱 만들기: 실무자를 위한 가이드

# AI 에이전트로 iOS 앱을 더 빠르게 만드세요. Claude Code, Codex CLI, Xcode 26.3 네이티브, MCP, CLAUDE.md 패턴, 훅, 8개 앱에서 얻은 교훈.

words: 10273 read_time: 52m updated: 2026-05-25 06:04
$ less ios-agent-development.md

요약: 이제 세 가지 agent runtime이 iOS용 코드를 작성해요. MCP가 붙은 Claude Code CLI, MCP가 붙은 Codex CLI, 그리고 Xcode 26.3의 native Intelligence agents입니다. 두 개의 MCP 서버(XcodeBuildMCP의 59개 도구, Apple의 xcrun mcpbridge의 20개 도구)는 agent가 빌드, 테스트, 시뮬레이터, 디버깅에 구조적으로 접근할 수 있게 해줘요. 이 가이드는 실제 CLAUDE.md 패턴, hook 설정, 그리고 무엇이 잘 작동하고 무엇이 깨지는지에 대한 솔직한 평가를 다룹니다. 총 293개의 Swift 파일로 이루어진 8개의 프로덕션 iOS 앱에서 얻은 내용이에요.18 Agent는 SwiftUI 뷰, SwiftData 모델, 리팩터링, 빌드 오류 진단에 강해요. 반면 .pbxproj 수정, 코드 서명, 시각적 디버깅에는 약합니다. “agent가 Swift를 작성한다”와 “agent가 iOS 앱을 출시한다” 사이의 간극은 프롬프트가 아니라 설정으로 메웁니다.

저는 AI coding agent로 8개의 iOS 앱을 만들었어요. 프로토타입이 아니라 App Store에 올라간 앱입니다. HealthKit 통합, Metal 셰이더, SpriteKit 물리, iCloud 동기화, Live Activities, Game Center 리더보드, iOS, watchOS, tvOS를 아우르는 멀티 플랫폼 타깃까지 포함되어 있어요. 이 앱들의 Swift 코드는 모두 agent가 작성하고 제가 검토했거나, 제가 작성한 뒤 agent가 리팩터링했어요. 제 추정으로는 줄 단위 작성의 대부분은 agent가 맡았고, 저는 검토, 범위 결정, 그리고 사람의 판단이 필요한 부분(시각적 마감, 서명, 성능 튜닝, App Store 제출)을 맡았습니다.

이 가이드는 제가 처음 시작할 때 있었으면 했던 참고 자료예요. 어떤 agent runtime을 써야 하는지, 구조적인 빌드 접근을 위해 MCP 서버를 어떻게 설정해야 하는지, CLAUDE.md에 무엇을 넣어야 하는지, 어떤 hook이 agent가 Xcode 프로젝트를 망가뜨리지 못하게 막아주는지, 그리고 무엇보다 agent가 어디에서 실패하고 언제 직접 운전대를 잡아야 하는지를 전체 스택 관점에서 다룹니다.

핵심 요점

AI agent를 처음 쓰는 iOS 개발자를 위해:

  • Claude Code CLI + XcodeBuildMCP로 시작하세요. 가장 성숙한 runtime이며 MCP 도구 범위가 가장 깊어요. 명령 2개를 설치하고 프로젝트에 CLAUDE.md를 추가하면, 오류 메시지를 복사해 주지 않아도 agent가 빌드, 테스트, 디버깅을 할 수 있어요.
  • agent가 .pbxproj를 수정하게 두지 마세요. 이것이 가장 중요한 규칙입니다. .pbxproj.xcodeproj/ 쓰기를 차단하는 PreToolUse hook 하나가 몇 시간의 복구 작업을 막아줘요.
  • CLAUDE.md는 agent의 온보딩 문서입니다. 여기에 들인 시간은 프로젝트를 만지는 모든 agent 세션에서 회수됩니다.

이미 agent를 쓰고 있고 iOS를 워크플로에 추가하려는 사용자를 위해:

  • MCP는 iOS 빌드 루프를 바꿉니다. MCP 이전에는 agent가 Swift를 작성할 수는 있었지만 컴파일 여부를 검증할 수 없었어요. XcodeBuildMCP를 쓰면 agent가 코드를 작성하고, 빌드하고, 구조화된 오류를 읽고, 수정하고, 테스트까지 자율적으로 실행합니다.
  • 세 가지 runtime은 서로 다른 필요를 충족합니다. 깊은 agentic 세션에는 Claude Code CLI, headless 배치 작업에는 Codex CLI, IDE를 벗어나지 않는 빠른 inline 수정에는 Xcode 26.3 native agents가 맞아요.
  • Hook 인프라는 그대로 가져올 수 있어요. 기존 PostToolUse formatter, PreToolUse blocker, test runner hook은 경로만 조금 조정하면 iOS 프로젝트에서도 똑같이 작동해요.

AI 보조 iOS 개발을 평가하는 팀 리드를 위해:

  • Agent 효과는 프로젝트 크기가 아니라 프로젝트 문서화 수준에 따라 커집니다. 자세한 CLAUDE.md가 있는 63개 파일 앱은 CLAUDE.md가 없는 14개 파일 앱보다 더 나은 agent 결과물을 냅니다.
  • .pbxproj 경계는 협상의 대상이 아닙니다. Agent는 Xcode 프로젝트 파일을 안정적으로 편집하지 못해요. 워크플로는 Xcode 타깃에 파일을 수동으로 추가하는 과정을 전제로 해야 합니다.
  • 솔직한 ROI: 문서화가 잘된 프로젝트에서는 agent가 구현의 대부분을 처리합니다. 아래 사례 연구의 15개 파일 TV 앱은 agent 보조 작업 3시간 만에 출시되었고, 이 점을 보여줘요. 남은 작업인 시각적 마감, 서명, 성능 튜닝, App Store 제출에는 사람의 판단이 필요합니다.

원하는 경로 선택하기

필요한 것 이동할 곳
처음으로 MCP 설정하기 MCP 설정: 전체 구성 — 두 서버 설치, 검증, agent 설정
iOS 프로젝트용 CLAUDE.md 작성하기 iOS 프로젝트를 위한 CLAUDE.md 패턴 — 8개 앱에서 가져온 실제 예시
세 가지 agent runtime 비교하기 iOS를 위한 세 가지 Agent Runtime — Claude Code vs. Codex vs. Xcode native
agent가 할 수 있는 일과 할 수 없는 일 이해하기 Agent가 잘하는 일Agent가 못하는 일
iOS 개발용 hook 설정하기 iOS 개발을 위한 Hooks — 저장 시 format, .pbxproj 보호, test runner
심층 참고 자료(이 페이지) 계속 읽으세요 — 설정부터 고급 패턴까지 모두 다룹니다

이 가이드를 사용하는 방법

이 문서는 3,000줄이 넘는 참고 자료예요. 자신의 경험 수준에 맞는 곳에서 시작하세요.

경험 여기서 시작 다음으로 살펴볼 내용
iOS + agent 모두 처음 사전 준비MCP 설정첫 Agent 세션 CLAUDE.md 패턴, 잘되는 것/안 되는 것
iOS 개발자, agent는 처음 세 가지 RuntimeMCP 설정CLAUDE.md Hooks, 아키텍처 패턴
Agent 사용자, iOS는 처음 아키텍처 패턴Agent가 못하는 일CLAUDE.md 프레임워크별 컨텍스트, 고급 워크플로
둘 다 경험 있음 고급 워크플로Hooks멀티 플랫폼 패턴 Runtime 비교, 포트폴리오

목차

  1. 포트폴리오: 8개 앱, 293개 파일
  2. 사전 준비
  3. iOS를 위한 세 가지 Agent Runtime
  4. MCP 설정: 전체 구성
  5. iOS 프로젝트를 위한 CLAUDE.md 패턴
  6. 첫 Agent 세션
  7. iOS에서 Agent가 잘하는 일
  8. iOS에서 Agent가 못하는 일
  9. iOS 개발을 위한 Hooks
  10. Agent와 잘 맞는 아키텍처 패턴
  11. 프레임워크별 컨텍스트
  12. 멀티 플랫폼 패턴
  13. 고급 워크플로
  14. 실전 사례 연구
  15. Agent와 함께하는 프로젝트 생명주기
  16. Agent 정의 설정하기
  17. Agent 보조 iOS를 위한 테스트 패턴
  18. iOS 프로젝트를 위한 Context Window 관리
  19. 문제 해결
  20. iOS에서 흔한 Agent 실수
  21. 솔직한 평가
  22. FAQ
  23. 빠른 참고 카드
  24. 참고 자료

관련 자료

주제 자료
Xcode용 MCP 설정(더 짧은 블로그 글) 두 개의 MCP 서버가 Claude Code를 iOS Build System으로 만든 방법
Claude Code CLI 전체 참고 자료 Claude Code CLI: 전체 가이드
Codex CLI 참고 자료 Codex CLI: 전체 가이드
Hook system 심층 분석 Anatomy of a Claw: 오케스트레이션 레이어로서의 84개 Hooks
Agent 아키텍처 패턴 Agent 아키텍처 가이드
Mac desktop app + Remote Control Claude Code Mac Desktop + Remote Control: CLI 사용자 가이드

Apple Ecosystem Series. Apple Intelligence, MCP, Foundation Models, Vision, Core ML, iOS 26 프레임워크 스택과 통합되는 SwiftUI 앱에 관한 21개의 프로덕션 글입니다. Water, Get Bananas, Return, 그리고 941 포트폴리오의 다른 앱에서 얻은 내용이에요.

시리즈 허브: Apple Ecosystem Series

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
Runtime 기능과 tooling으로서의 온디바이스 LLM Foundation Models + Agentic Workflow
Apple 개발을 위한 Hooks Hooks for Apple Development
Cross-process state Single Source of Truth: SwiftData + MCP + iCloud

Frameworks (E2/E3):

주제 자료
Foundation Models 온디바이스 LLM Foundation Models On-Device LLM
Vision framework (CV primitives) Vision Framework: What’s Built In
Core ML inference patterns Core ML On-Device Inference
RealityKit spatial mental model RealityKit and the Spatial Mental Model
SwiftUI internals What SwiftUI Is Made Of
Symbol Effects animation vocabulary Symbol Effects: SwiftUI’s Built-In Animation Vocabulary
iOS 26+의 Liquid Glass Liquid Glass in SwiftUI: Three Patterns

Shipped-code (E1):

주제 자료
Live Activities state machine Live Activities State Machine
watchOS runtime contract watchOS Runtime Contract
SwiftData schema discipline SwiftData Schema Discipline
HealthKit + SwiftUI patterns HealthKit + SwiftUI on iOS 26
Multi-platform SwiftUI Five Apple Platforms, Three Shared Files
XcodeBuildMCP integration Two MCP Servers, One Xcode Project

Synthesis (E5):

주제 자료
iOS 앱의 세 가지 surface The Three Surfaces of an iOS App
Platform target decisions The Apple Platform Matrix
제가 쓰기를 거부하는 것 What I Refuse to Write About

포트폴리오: 8개 앱, 293개 파일

설정으로 들어가기 전에, 이 가이드가 어떤 경험을 바탕으로 작성되었는지 먼저 살펴보겠습니다. 이 앱들은 장난감 프로젝트가 아닙니다. 5개의 Apple 프레임워크, 3개의 플랫폼, 그리고 14개 파일짜리 운동 추적 앱부터 63개 파일짜리 멀티 플랫폼 명상 타이머까지 iOS 복잡도의 전 범위를 다룹니다.

스택 파일 복잡도
Banana List SwiftUI + SwiftData + iCloud Drive 동기화 + Claude Desktop용 MCP 서버 53 전체 CRUD, iCloud 동기화, 앱 데이터를 Claude Desktop에 노출하는 커스텀 MCP 서버
Ace Citizenship SwiftUI 학습 앱 + FastAPI 백엔드 26 클라이언트-서버, REST API 통합, 퀴즈 엔진
TappyColor SpriteKit 색상 매칭 게임 30 게임 루프, 물리, 터치 처리, 파티클 효과
Return Zen 명상 타이머 — iOS 26+, watchOS, tvOS 63 HealthKit, Live Activities, Watch 확장 런타임, TV 포커스 내비게이션, iCloud 세션 동기화
amp97 Metal 셰이더 + 오디오 시각화 41 커스텀 Metal 렌더 파이프라인, 오디오 분석, 실시간 GPU 컴퓨트
Reps SwiftUI + SwiftData 운동 추적 14 최소 기능 앱, 깔끔한 SwiftData 패턴
Water SwiftUI + SwiftData + Metal + HealthKit 수분 섭취 추적 34 Metal 유체 시뮬레이션, HealthKit 물 섭취 기록, 위젯
Starfield Destroyer SpriteKit + Metal 우주 슈팅 게임 32 99개 레벨, 8개 우주선, Game Center 리더보드, Metal 후처리

파일 수가 중요한 이유: Agent의 효과는 프로젝트 크기가 아니라 프로젝트의 가독성과 더 밀접하게 관련됩니다. Return(63개 파일)은 amp97(41개 파일)보다 더 나은 agent 출력을 만들어냅니다. Return에는 파일 주석, 아키텍처 다이어그램, 명시적인 패턴이 담긴 상세한 CLAUDE.md가 있기 때문입니다. 반면 amp97의 Metal 셰이더는 문서 품질과 관계없이 agent가 추론하기 본질적으로 더 어렵습니다.


사전 요구 사항

iOS 개발용 agent 런타임을 설정하기 전에 다음을 준비하세요.

App Store Connect 마감일: 2026년 4월 28일부터 App Store Connect에 업로드하는 앱은 Xcode 26 이상에서 iOS 26, iPadOS 26, tvOS 26, visionOS 26 또는 watchOS 26용 SDKs를 사용해 빌드해야 합니다.12 (macOS 제출은 이 요구 사항에 해당하지 않습니다.) 팀이 아직 Xcode 16.x를 사용하고 있다면, 이 가이드의 agent 지원 툴체인은 전환을 강제하는 계기가 되기도 합니다. 어차피 아래의 MCP 서버들은 Xcode 26.3+ 없이는 작동하지 않습니다.

필수: - macOS 15+ (Sequoia) 또는 macOS Tahoe - Xcode 26.3+ 설치 및 설정 완료(xcrun mcpbridge의 최소 기준). Xcode 26.5+ 권장: agent 워크플로 업그레이드인 코딩 어시스턴트의 메시지 대기열과 확인 질문 지원, 그리고 26.4에서 처음 추가된 Swift Testing 이미지 첨부, 기록된 이슈 심각도, crashlog가 포함된 UI 테스트 충돌 경고, String Catalog 편집기 개선 사항을 사용할 수 있습니다.1314 Xcode 26.5(2026년 5월 11일, 빌드 17F42)가 최신 안정 버전이며, 26.4.1(2026년 4월 16일, 빌드 17E202)은 마지막 26.4 계열 버그 수정 릴리스였습니다.15 - 최소 1개의 iOS Simulator 런타임 설치 - Claude Code용 Anthropic API 계정 또는 Codex용 OpenAI 계정

권장: - SwiftFormat 설치(brew install swiftformat) — 저장 시 포맷팅 hook에서 사용 - SwiftLint 설치(brew install swiftlint) — 선택 사항이지만 스타일 강제에 유용 - 터미널 사용에 익숙할 것 — 세 런타임 모두 명령줄에서 실행되거나 명령줄과 통합됩니다

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를 위한 세 가지 에이전트 런타임

세 가지 서로 다른 런타임이 iOS 코드를 작성하고, 빌드하고, 테스트할 수 있습니다. 이들은 서로 교체 가능하지 않으며, 각각 다른 강점과 다른 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+에는 Claude Code, Cursor, 또는 Codex를 자동 감지하고 에이전트 스킬 + MCP 설정을 한 단계로 설치하는 init 하위 명령이 포함되어 있습니다.

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

플래그: --print (지원되지 않는 클라이언트를 위해 stdout으로 설정 작성), --uninstall (제거). 어떤 MCP 서버를 어떤 범위에서 연결할지 명시적으로 제어하고 싶다면 이 단계를 건너뛰세요. 위의 수동 claude mcp add 호출이 그러한 제어를 제공합니다.16

최적의 사용처: 심층 구현 세션 — 새로운 기능 빌드, 여러 파일에 걸친 리팩토링, 복잡한 이슈 디버깅, 빌드-테스트-수정 루프를 자율적으로 실행하기. Claude Code의 1M 컨텍스트 창(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 생태계 (테스트된 커뮤니티 서버가 더 적음) - 훅 시스템 사용 가능(v0.119.0+)이지만 Claude Code보다 덜 성숙함 — 이벤트 유형이 더 적고 조건부 if 필드가 없음

iOS에서 Claude Code보다 Codex를 사용해야 할 때:

모델 다양성을 원할 때 Codex를 사용하세요 — 첫 번째 에이전트가 작성한 코드를 두 번째 에이전트가 검토하면 서로 다른 종류의 오류를 잡아냅니다. collab 워크플로 (Claude가 빌드하고 Codex가 검토)는 iOS에 효과적입니다. 한 모델 계열에는 올바르게 보이는 SwiftUI 패턴이 다른 모델이 잡아내는 미묘한 문제를 가질 수 있기 때문입니다. Metal 셰이더와 동시성 패턴은 특히 이중 모델 검토의 혜택을 받습니다.

3. Xcode 26.3 네이티브 에이전트

무엇인가: Apple은 Xcode의 Intelligence 패널에 AI 코딩 에이전트를 직접 통합했습니다. Xcode 26.3 기준으로, Xcode 설정 > Intelligence에서 Claude Agent와 Codex를 인텔리전스 제공자로 구성할 수 있습니다.

설정:

  1. Xcode 26.3+ 열기
  2. 설정 > Intelligence로 이동
  3. 새 제공자 추가:
  4. Claude의 경우: “Claude Agent”를 선택하고 Anthropic API 키 입력
  5. Codex의 경우: “Codex”를 선택하고 OpenAI API 키 입력
  6. 에이전트가 Intelligence 사이드바에 나타나고 인라인으로 호출할 수 있습니다

최적의 사용처: 빠른 인라인 편집, 에이전트 수준의 추론을 통한 코드 완성, 그리고 Xcode를 떠나지 않으려는 개발자에게 적합합니다. 네이티브 통합 덕분에 에이전트는 MCP 브리징 없이도 Xcode의 프로젝트 컨텍스트 — 열린 파일, 빌드 타겟, 스킴 구성 — 에 직접 접근할 수 있습니다.

CLI 에이전트와 비교한 제한 사항: - 훅 시스템 없음 — format-on-save를 강제하거나 .pbxproj 쓰기를 차단할 수 없음 - CLAUDE.md 로딩 없음 — 에이전트가 프로젝트 수준 설정 파일을 읽지 않음 - 제한된 자율성 — 에이전트는 전체 프로젝트가 아닌 현재 파일 또는 선택 영역에서 작동함 - 서브에이전트 위임 없음 — 복잡한 다단계 작업을 병렬화할 수 없음 - MCP 서버 구성 없음 — 에이전트는 Xcode의 내장 도구만 사용함

Xcode 네이티브 에이전트를 사용해야 할 때:

터미널로 전환하는 것이 부담스러운 빠르고 범위가 한정된 편집에 적합합니다. “이 모델에 계산된 속성을 추가하세요.” “이 함수에 대한 단위 테스트를 작성하세요.” “이 뷰를 @Observable을 사용하도록 리팩토링하세요.” 한두 개의 파일에 영향을 주고 빌드-테스트 사이클이 필요하지 않은 작업입니다.

빌드, 테스트, 다중 파일 리팩토링 또는 자율적 오류 수정이 필요한 모든 작업에는 MCP를 갖춘 CLI 에이전트를 사용하세요.

런타임 비교 매트릭스

기능 Claude Code CLI Codex CLI Xcode 26.3 네이티브
MCP 지원 완전 (79개 도구) 완전 (79개 도구) 내장 Xcode 도구만
훅 시스템 예 (성숙함) 예 (기본, v0.119.0+) 아니요
CLAUDE.md / 프로젝트 설정 codex.md 동등물 아니요
자율적 빌드-테스트-수정 예 (MCP를 통해) 예 (MCP를 통해) 부분적 (인라인만)
서브에이전트 위임 예 (최대 10개 병렬) 아니요 아니요
컨텍스트 창 1M 토큰 (Opus 4.6) 모델에 따라 다름 제공자에 따라 다름
다중 파일 작업 전체 코드베이스 접근 전체 코드베이스 접근 현재 파일 / 선택 영역
.pbxproj 보호 훅을 통해 수동 해당 없음 (Xcode를 네이티브로 사용)
Format-on-save PostToolUse 훅을 통해 외부 도구 Xcode 설정
오프라인 기능 아니요 아니요 아니요
비용 모델 Anthropic API 사용량 OpenAI API 사용량 제공자 API 사용량

권장 사항: Claude Code CLI를 기본 런타임으로 사용하세요. 빠른 인라인 편집에는 Xcode 26.3 네이티브 에이전트를 사용하세요. 검토 작업과 배치 작업에는 Codex CLI를 사용하세요. 이 세 가지는 서로 경쟁하기보다는 보완합니다.


MCP 설정: 전체 구성

MCP(Model Context Protocol)는 에이전트를 “Swift를 작성하고 빌드되기를 바라기만 하는” 수준에서 “Swift를 작성하고, 빌드하고, 구조화된 오류를 읽고, 수정하는” 수준으로 바꿔 줍니다. 이 섹션에서는 블로그 글보다 더 깊게 들어가 두 서버, 모든 설치 방법, 검증, 도구가 실제로 사용되도록 보장하는 에이전트 설정까지 다룹니다.

XcodeBuildMCP: 헤드리스 iOS 개발을 위한 59개 도구

XcodeBuildMCPxcodebuild, xcrun simctl, LLDB를 59개의 구조화된 MCP 도구로 감싸 줍니다. Xcode를 실행하지 않아도 작동하며, 전체 빌드-테스트-디버그 사이클이 Apple의 command-line tools를 통해 헤드리스로 동작합니다.

설치 옵션:

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

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

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

-s user 플래그는 서버를 모든 프로젝트에서 전역으로 사용할 수 있게 합니다. 프로젝트 범위로만 설치하려면 생략하세요. iOS 프로젝트에서만 MCP를 사용하고 웹 프로젝트에서는 사용하지 않으려는 경우에 유용합니다.

-e XCODEBUILDMCP_SENTRY_DISABLED=true 환경 변수는 crash report telemetry를 비활성화합니다. XcodeBuildMCP에는 기본적으로 Sentry가 포함되어 있으며, 파일 경로를 포함한 오류 데이터를 전송합니다. 프로젝트에 진단 정보를 기여하려는 경우가 아니라면 옵트아웃하세요.1

전체 도구 목록(8개 범주, 59개 도구):

범주 도구 역할
프로젝트 탐색 discover_projs, list_schemes, list_targets .xcodeproj/.xcworkspace 파일을 찾고, 사용할 수 있는 scheme과 target을 나열합니다
빌드 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 breakpoint와 변수 검사를 포함한 전체 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를 관리할 수 있습니다. 에이전트는 사용할 수 있는 runtime을 탐색하고 적절한 기기를 선택합니다.

  4. discover_projs + list_schemes — 프로젝트 인트로스펙션입니다. 에이전트가 scheme 이름이나 workspace 구조를 추측할 필요가 없습니다.

  5. debug_attach_sim + debug_stack + debug_variables — 원격 LLDB 디버깅입니다. 에이전트는 사용자가 debugger를 열지 않아도 breakpoint를 설정하고, 변수를 검사하고, 코드를 단계별로 실행할 수 있습니다.

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 문서 검색을 제공합니다
Previews RenderPreview 헤드리스 SwiftUI preview 렌더링을 제공합니다

Apple MCP에만 있는 도구(XcodeBuildMCP에서는 사용할 수 없음):

  1. DocumentationSearch — WWDC 세션을 포함한 Apple developer documentation을 검색합니다. Apple API 질문에는 웹 검색보다 빠르고 신뢰할 수 있습니다. “HKQuantityType(.dietaryWater)가 유효한가요?”라고 물으면 원본 출처에서 확정적인 답을 얻을 수 있습니다.

  2. ExecuteSnippet — 프로젝트 컨텍스트 안에서 Swift REPL을 실행합니다. 에이전트는 전체 앱을 빌드하지 않고도 API 동작을 검증하고, 타입 변환을 테스트하고, 표현식을 확인할 수 있습니다.

  3. RenderPreview — SwiftUI preview를 헤드리스로 렌더링합니다. 에이전트는 view가 오류 없이 렌더링되는지 확인할 수 있지만, 시각적 정확성은 평가할 수 없습니다. 렌더링 결과가 시각적으로 검사되는 것이 아니라 데이터로 반환되기 때문입니다.

  4. XcodeListNavigatorIssues — 빌드 오류뿐 아니라 Xcode analyzer의 실시간 진단을 반환합니다. 사용하지 않는 변수, 잠재적인 retain cycle, 빌드 시스템이 드러내지 않는 deprecation warning 같은 문제를 잡아냅니다.

두 서버가 모두 필요한 이유

두 서버는 빌드와 테스트에서 겹치지만 근본적으로 다릅니다.

┌─────────────────────────────────────────────────────────────────┐
                     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 preview 렌더링, 실시간 진단입니다. 이런 기능이 필요한 세션에서는 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 문서를 찾기 위해 웹 검색을 사용할 수 있습니다(더 느리고 신뢰성이 낮음).

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

이것이 중요한 이유: 에이전트는 코드를 작성하기 전에 deployment target을 알아야 합니다. iOS 17을 대상으로 하는 에이전트는 NavigationView@ObservedObject를 사용합니다. iOS 26을 대상으로 하는 에이전트는 NavigationStack@Observable을 사용합니다. bundle ID는 entitlements와 HealthKit 설정에 중요합니다. Swift 버전은 동시성 모델(async/await와 completion handler, 엄격한 동시성과 느슨한 동시성)을 결정합니다.

2. 목적 주석이 있는 파일 구조

## File Structure

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

각 파일명 뒤의 인라인 주석은 장식이 아닙니다. 작성할 수 있는 문서 중 가장 효과가 큰 문서입니다. 에이전트가 새 기능을 어디에 추가할지 결정할 때, 이 주석은 프로젝트 구조를 이해하려고 모든 파일을 읽는 대신 첫 시도에 올바른 파일로 안내합니다.

안티 패턴: 주석 없이 파일만 나열하는 방식입니다. TimerManager.swift만으로는 해당 파일이 상태를 다루는지, UI를 다루는지, 둘 다 다루는지 에이전트가 알 수 없습니다. TimerManager.swift # Timer state, logic, and repeat handling는 그 파일에 무엇이 속하고 무엇이 속하지 않는지 정확히 알려줍니다.

3. 빌드 및 테스트 명령

## Build & Test

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

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

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

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

에이전트가 MCP를 우선해야 하더라도 원본 명령을 포함하세요. 원본 명령은 fallback 문서 역할을 하며 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 동기화와 앱 데이터를 Claude Desktop에 노출하는 커스텀 MCP 서버를 갖춘 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개 파일 프로젝트에 40줄짜리 CLAUDE.md입니다. 작성에는 10분이 걸리고, 에이전트가 혼란스러워하며 낭비할 몇 시간을 줄여줍니다.

실제 CLAUDE.md: Starfield Destroyer (SpriteKit + Metal — 32개 파일)

게임 프로젝트에는 더 많은 프레임워크별 컨텍스트가 필요합니다. 에이전트는 scene graph, physics category, game state machine을 이해해야 합니다.

# 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개 이상 파일) + 아키텍처 다이어그램 + 관계 맵 + multi-target 정보 Return (63개 파일): cross-platform 아키텍처, session sync 다이어그램, 플랫폼별 차이
전문화 (Metal/GPU) + pipeline 다이어그램 + shared type 정의 + buffer layout amp97 (41개 파일): render pipeline 단계, uniform struct, buffer management

과하게 문서화하는 비용은 거의 0에 가깝습니다(에이전트는 필요 없는 부분을 건너뜁니다). 문서화가 부족할 때의 비용은 큽니다(에이전트가 코드베이스와 충돌하는 패턴을 만들어냅니다).

CLAUDE.md 체크리스트

iOS 프로젝트용 CLAUDE.md를 만들거나 검토할 때 이 체크리스트를 사용하세요.

  • [ ] bundle ID와 deployment target이 명시되어 있음
  • [ ] Swift 버전과 아키텍처 패턴이 이름으로 명시되어 있음
  • [ ] 인라인 목적 주석이 있는 파일 구조
  • [ ] 올바른 scheme과 destination이 포함된 빌드 명령
  • [ ] 올바른 scheme과 destination이 포함된 테스트 명령
  • [ ] MCP 선호 사항 명시(“xcodebuild보다 build_sim 선호”)
  • [ ] @Observable 규칙(ObservableObject는 절대 사용하지 않음)
  • [ ] NavigationStack 규칙(NavigationView는 절대 사용하지 않음)
  • [ ] .pbxproj 금지
  • [ ] 프레임워크별 컨텍스트(HealthKit 권한, SwiftData 관계, SpriteKit hierarchy, Metal pipeline)
  • [ ] 플랫폼 가용성 guard가 문서화되어 있음(#if canImport, #if os)
  • [ ] 핵심 singleton과 공유 패턴이 문서화되어 있음
  • [ ] 알려진 제한 사항이나 주의점이 명시되어 있음

첫 Agent Session

MCP 설정을 마치고 프로젝트에 CLAUDE.md가 있다면, 효과적인 첫 session을 이렇게 진행할 수 있습니다. 여기서는 Claude Code CLI를 사용하지만, workflow는 어떤 runtime에도 적용됩니다.

1단계: Agent가 프로젝트를 볼 수 있는지 확인하세요

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.

agent가 CLAUDE.md 내용을 언급하지 않는다면, 파일이 project root(.xcodeproj 또는 Package.swift와 같은 디렉터리)에 있는지 확인하세요.

2단계: 상태 확인 Build를 실행하세요

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단계: Test를 실행하세요

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를 수정하지 않겠다는 agent의 메모는 CLAUDE.md의 규칙이 적용된 결과입니다. 이 규칙이 없으면 agent는 project file 수정을 시도하고, 높은 확률로 파일을 손상시킵니다.


iOS에서 Agents가 잘하는 일

다음은 agents가 최소한의 사람 검토만으로도 일관되게 정확하고 production-ready한 결과물을 만들어내는 작업들입니다.

SwiftUI Views와 Modifiers

agents는 SwiftUI의 선언형 문법 패턴을 깊이 인식합니다. View 구성, modifier chain, state binding, layout은 agent의 training data와 잘 맞습니다. SwiftUI의 API 영역이 문서화가 잘 되어 있고 패턴도 매우 일관적이기 때문입니다.

agents가 뛰어난 영역: - 설명을 바탕으로 새 view 만들기(“X, Y, Z용 toggle이 있는 settings sheet를 만들어 주세요”) - modifier chain 적용하기(.glassEffect(), .sensoryFeedback(), .navigationTitle()) - layout pattern 변환하기(VStack에서 LazyVGrid로, List에서 ScrollView로) - SwiftData model에 @Bindable form binding 구현하기 - sample data로 preview provider 만들기

훌륭한 결과를 만드는 prompt 예시:

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.

구체성이 중요합니다. “settings view를 만들어 주세요”라고 하면 일반적인 결과물이 나옵니다. “SettingsSheet.swift의 기존 pattern과 맞는 SettingsView를 만들어 주세요”라고 하면 codebase와 일관된 결과물이 나옵니다.

SwiftData Models와 Queries

agents는 SwiftData의 @Model macro, relationship, @Query pattern을 안정적으로 처리합니다. framework의 선언적인 성격(Django ORM 또는 SQLAlchemy와 비슷함)은 agent가 여러 codebase에서 본 pattern과 잘 맞습니다.

agents가 뛰어난 영역: - relationship이 있는 @Model class 정의하기 - sort descriptor와 predicate를 사용해 @Query 작성하기 - modelContext를 통한 CRUD 작업 구현하기 - schema version 간 migration plan 만들기 - preview data와 test fixture 만들기

agents에게 지침이 필요한 영역: - 복잡한 #Predicate expression(SwiftData의 predicate DSL에는 agent가 항상 알지는 못하는 제한이 있습니다. 알려진 제한은 CLAUDE.md에 문서화하세요) - CloudKit sync 설정(SwiftData를 통해 자동으로 처리되지만, agent가 manual sync를 구현하려 할 수 있습니다)

Unit Tests

agent가 작성한 unit test는 iOS project에서 일관되게 품질이 높습니다. agent는 XCTest pattern, async test method, setup/teardown lifecycle을 이해합니다.

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)

agent는 setUp()tearDown(), 적절한 assertion, timer 기반 test를 위한 async 처리를 갖춘 잘 구조화된 XCTest case를 만들어냅니다.

Refactoring과 Pattern 적용

agents는 기계적인 refactoring에 뛰어납니다. view를 component로 추출하고, ObservableObject@Observable로 변환하고, NavigationView에서 NavigationStack으로 migration하고, 여러 파일에 걸쳐 일관된 pattern을 적용하는 작업입니다.

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.

agent는 각 파일을 체계적으로 처리하고, 변환을 정확히 적용하며, 기존 기능을 유지합니다. 이는 높은 leverage를 가진 작업입니다. 사람이 직접 편집하면 1시간 걸릴 refactoring도 몇 분 안에 거의 완벽한 정확도로 끝납니다.

MCP를 통한 Build Error 진단

구조화된 MCP output이 있으면 agents는 대부분의 개발자보다 build error를 더 빠르게 진단합니다. agent는 error JSON를 읽고, 정확한 file과 line을 찾고, error message를 이해한 뒤 fix를 적용합니다. 많은 경우 한 번의 turn으로 끝납니다.

agents가 자율적으로 고치는 error: - 누락된 import - type mismatch - protocol conformance 누락 - deprecated API 사용(대체 항목 포함) - 누락된 required initializer parameter - access control 위반

agents에게 도움이 필요한 error: - 모호한 type resolution(여러 module이 같은 type을 정의하는 경우) - 복잡한 generic constraint 실패 - macro expansion error(agent는 expanded macro output을 볼 수 없습니다)

Simulator 관리

agents는 MCP를 통해 simulator lifecycle을 잘 처리합니다.

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

agent는 list_sims를 호출해 사용 가능한 runtime을 찾고, boot_sim으로 simulator를 시작하고, build_sim으로 build와 install을 수행하며, screenshot으로 capture합니다. 모두 구조화된 MCP call을 통해 처리합니다.


iOS에서 Agents가 잘하지 못하는 것

Agents가 어디에서 실패하는지 솔직하게 정리합니다. 이 경계를 알아두면 좌절과 토큰 낭비를 줄일 수 있습니다.

.pbxproj 파일 수정 — 절대 금지

iOS agent 개발에서 가장 중요한 규칙입니다. .pbxproj 파일은 Xcode의 프로젝트 설정입니다. UUID 참조, 빌드 단계 목록, 타깃 멤버십이 들어 있는 구조화된 텍스트 파일입니다. 겉으로는 사람이 읽을 수 있어 보이지만, 실제로는 AI agents가 파싱하기 거의 불가능합니다.

Agents가 .pbxproj에서 실패하는 이유: - 이 파일은 위치가 중요한 커스텀 형식을 사용합니다(JSON도 아니고, YAML도 아니며, XML도 아닙니다) - 모든 항목이 UUID로 교차 참조됩니다. 파일 하나를 추가하려면 보통 3-5개의 서로 다른 섹션을 일관되게 업데이트해야 합니다 - 문자 하나만 잘못 들어가도 전체 프로젝트 파일이 손상됩니다 - Xcode의 .pbxproj 병합 충돌 해결은 원래도 취약합니다. agent가 편집하면 더 나빠집니다

Agent가 .pbxproj를 편집하면 벌어지는 일: 1. 편집은 성공한 것처럼 보입니다(agent가 “file updated”라고 보고합니다) 2. Xcode가 프로젝트 열기를 거부합니다(“The project file is corrupted”) 3. git 기록에서 복구하느라 15-60분을 씁니다 4. PreToolUse hook을 추가해야 한다는 사실을 배우게 됩니다(Hooks 참조)

작업 흐름: Agent는 Swift 파일을 만듭니다. 사용자는 그 파일을 Xcode 프로젝트에 직접 추가합니다(Xcode로 드래그하거나 File > Add Files 사용). 파일당 5초면 충분하며, 몇 시간짜리 복구 작업을 막아줍니다.

Swift Package Manager 프로젝트의 경우: 이 제한은 덜 심각합니다. Package.swift는 agents가 안정적으로 편집할 수 있는 표준 Swift 파일입니다. 프로젝트가 SPM만 사용한다면(.xcodeproj 없음), agent가 전체 프로젝트 구조를 관리할 수 있습니다.

복잡한 Interface Builder / Storyboard 편집

프로젝트가 Interface Builder(.xib 파일)나 Storyboards(.storyboard 파일)를 사용한다면, agents는 이를 의미 있게 편집할 수 없습니다. 이들은 자동 생성 UUID, 제약 조건 참조, outlet 연결을 포함한 XML 파일이며, 텍스트 편집이 아니라 시각적 편집을 위해 설계되었습니다.

완화 방법: 새 view에는 SwiftUI만 사용하세요. 프로젝트에 기존 Interface Builder 파일이 있다면 그대로 두고, 새 UI는 SwiftUI로 만드세요.

성능 최적화

Agents는 올바른 코드는 작성하지만, 반드시 성능이 좋은 코드를 작성하지는 않습니다. Agents는 앱을 프로파일링하거나 병목을 찾거나 프레임 속도를 측정할 수 없습니다. 성능 최적화에는 다음이 필요합니다.

  1. Instruments 프로파일링(시각적 도구이며 agent가 접근할 수 없습니다)
  2. 특정 기기의 GPU/CPU 특성에 대한 이해
  3. 측정 기반의 반복적인 변경

이 문제가 드러나는 곳: - Metal shader 최적화(agent는 유효한 Metal을 작성하지만 GPU 프레임 시간을 측정할 수 없습니다) - SwiftUI view body 복잡도(agent는 다시 그리기 오버헤드를 유발하는 깊게 중첩된 views를 만듭니다) - Core Data / SwiftData fetch 최적화(agent는 올바른 query를 작성하지만 큰 dataset에서는 느릴 수 있습니다)

완화 방법: 구현에는 agents를 사용하고, Instruments로 직접 프로파일링한 다음, 직접 식별한 구체적인 최적화를 agent에게 적용하게 하세요.

코드 서명과 프로비저닝

Agents는 오류 메시지를 읽는 것 이상으로 코드 서명 문제를 디버깅할 수 없습니다. 프로비저닝 프로파일 관리, 인증서 생성, entitlement 설정, App Store 제출은 근본적으로 Apple Developer portal, Keychain Access, Xcode의 signing UI를 사용하는 사람이 수행해야 하는 작업 흐름입니다.

Agent가 보는 것: “Signing for ‘Return’ requires a development team.”

Agent가 볼 수 없는 것: 인증서가 만료되었는지, 프로비저닝 프로파일에 기기가 포함되어 있는지, bundle ID가 App ID와 일치하는지, entitlements 파일이 올바른지 여부입니다.

완화 방법: 모든 signing은 Xcode의 Signing & Capabilities 탭에서 처리하세요. Signing 실패를 agents에게 디버깅해 달라고 요청하지 마세요.

복잡한 Metal Shader 디버깅

Agents는 문법적으로 올바른 Metal Shading Language(MSL)를 작성하지만, 시각적 출력이나 GPU 쪽 문제를 검증할 수 없습니다. Metal shaders는 GPU에서 실행됩니다. Agent에게는 shader가 올바른 시각적 결과를 내는지 확인할 피드백 메커니즘이 없습니다.

Agents가 Metal로 할 수 있는 일: - 설명을 바탕으로 vertex와 fragment shaders 작성 - Swift에서 Metal render pipeline 설정 - 데이터 병렬 작업용 compute shaders 생성 - .metal 파일의 컴파일 오류 수정

Agents가 Metal로 할 수 없는 일: - Shader 출력의 시각적 정확성 검증 - GPU 성능 디버깅(프레임 시간, occupancy, memory bandwidth) - 시각적 artifacts 진단(banding, precision issues, 잘못된 color space) - 서로 다른 GPU 아키텍처에서 테스트(A-series와 M-series의 동작 차이)

완화 방법: Metal shaders는 실제 기기에서 테스트하세요. Simulator의 Metal 구현은 기기 GPU 동작을 대표하지 않습니다. 시각적 디버깅에는 Xcode의 GPU Frame Capture를 사용하세요.

시각적 레이아웃 검증

Agents는 앱의 UI를 볼 수 없습니다. SwiftUI layout 코드를 작성하고 컴파일 여부는 확인할 수 있지만, 결과 화면이 올바르게 보이는지는 판단할 수 없습니다. 10픽셀 어긋나게 렌더링되거나, 잘못된 font weight를 사용하거나, 요소가 겹치는 view도 빌드 오류를 내지 않으며 모든 로직 테스트를 통과합니다.

완화 방법: UI 변경은 직접 시각적으로 검토하세요. Xcode의 SwiftUI Previews(또는 headless 렌더링용 Apple MCP를 통한 RenderPreview)로 layout을 확인하세요. 자동화된 시각적 회귀 감지를 위해 swift-snapshot-testing 같은 라이브러리로 snapshot testing을 고려하세요.


iOS 개발용 Hooks

Hooks는 에이전트 워크플로의 특정 지점에서 항상 정해진 방식으로 실행되는 shell 명령어입니다. Hooks는 강제 적용 장치입니다. 즉, “.pbxproj를 편집하지 마세요”(에이전트가 무시할 수도 있는 제안)와 “.pbxproj를 편집할 수 없습니다”(강제 차단)의 차이를 만듭니다.

hook 시스템에 대한 배경은 Claude Code hooks 가이드를 참고하세요. 이 섹션에서는 iOS 전용 hook 패턴을 다룹니다.

PreToolUse: .pbxproj 쓰기 차단

모든 iOS 프로젝트에서 가장 중요한 hook입니다. 이 hook은 에이전트가 .pbxproj 파일, .xcodeproj/ 디렉터리, 기타 Xcode가 관리하는 파일에 쓰지 못하도록 차단합니다.

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

프로젝트 루트의 .claude/settings.json에 넣거나, 전역 보호를 위해 ~/.claude/settings.json에 넣으세요.

작동 방식: 에이전트가 패턴과 일치하는 파일에 Edit 또는 Write 도구를 사용하려고 하면 hook이 실행되고, 파일 경로를 감지한 뒤 stderr에 경고를 출력하고 코드 2로 종료합니다. 이렇게 하면 도구 사용이 차단됩니다. 에이전트는 오류 메시지를 받고 접근 방식을 조정합니다.

감지하는 항목: - 직접적인 .pbxproj 편집 - .xcodeproj/ 또는 .xcworkspace/ 디렉터리 내부의 모든 파일 - Interface Builder 파일(.xib, .storyboard)

PostToolUse: SwiftFormat으로 저장 시 자동 포맷

에이전트가 Swift 파일을 작성하거나 편집할 때마다 자동으로 포맷합니다.

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

요구 사항: SwiftFormat이 설치되어 있어야 합니다(brew install swiftformat).

이것이 중요한 이유: 에이전트는 문법적으로 올바른 Swift를 만들지만, 포맷 규칙을 일관되게 따르지는 않습니다. SwiftFormat은 들여쓰기, 중괄호 위치, import 정렬을 표준화합니다. 저장 시 자동 포맷 hook을 사용하면 에이전트가 건드린 모든 Swift 파일이 사용자에게 보이기 전에 자동으로 포맷됩니다.

선택 사항: 프로젝트 루트에 .swiftformat 설정 파일 추가로 포맷 규칙을 사용자화할 수 있습니다.

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

PostToolUse: SwiftLint 자동 실행

SwiftLint를 사용한다면 Swift 파일을 편집할 때마다 실행하세요.

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

|| true는 lint 경고가 에이전트를 차단하지 않도록 합니다. lint 위반을 차단하려면 이 부분을 제거하세요.

PostToolUse: 변경 후 자동 빌드

더 강한 피드백 루프가 필요하다면 Swift 파일이 변경될 때마다 빌드를 트리거하세요.

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

경고: 비용이 큽니다. 파일을 편집할 때마다 빌드가 실행됩니다. 신중하게 사용하세요. 즉각적인 빌드 피드백이 필요한 디버깅 세션에서 가장 유용합니다. 일반 개발에서는 에이전트가 준비되었을 때 MCP를 통해 수동으로 빌드를 트리거하도록 두세요.

PreToolUse: Entitlement 수정 차단

entitlements 파일이 에이전트에 의해 실수로 수정되지 않도록 보호하세요.

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

통합 iOS Hook 설정

제가 모든 iOS 프로젝트에서 사용하는 전체 .claude/settings.json은 다음과 같습니다.

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

이 설정은 두 가지를 보장합니다. 1. 에이전트가 Xcode 프로젝트 파일을 손상시킬 수 없습니다(PreToolUse 차단) 2. 에이전트가 건드린 모든 Swift 파일이 자동으로 포맷됩니다(PostToolUse 포맷)


에이전트와 잘 맞는 아키텍처 패턴

모든 Swift 아키텍처가 에이전트에게 똑같이 적합한 것은 아니에요. 다음 패턴은 명시적이고 일관되며 학습 데이터에도 잘 나타나 있어 가장 좋은 결과를 내요.

@Observable (ObservableObject는 사용하지 않음)

iOS 26+ 타깃에서는 @Observable만 사용해야 해요. 이것은 최신 패턴이면서 에이전트 친화적인 패턴이에요.

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

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

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

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

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

@Observable이 에이전트 친화적인 이유: 패턴이 더 단순하고(@Published 어노테이션이 필요 없음), 소유권 모델이 더 명확하며(@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. 반응형 데이터에는 뷰에서 @Query를 사용하세요: @Query var items: [GroceryItem] 4. 뷰가 아닌 코드에서는 modelContext.fetch()를 사용하세요 5. 관계 삭제에는 명시적인 규칙이 필요해요: .cascade, .nullify, .deny

Swift 6.2 동시성

새 프로젝트에서는 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
}

동시성에 대한 에이전트 가이드: - 모든 뷰 모델에 @MainActor를 표시하세요. 데이터 경합 경고를 막아줘요 - 모든 비동기 작업에는 async/await를 사용하세요. completion handler는 사용하지 마세요 - actor 간 전송에는 값 타입을 Sendable로 만드세요 - 뷰에서 비동기 초기화에는 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 효과를 직접 재현하지 말고 시스템 modifier를 사용하세요.”


프레임워크별 맥락

각 Apple 프레임워크에는 에이전트와 관련된 고려 사항이 있어요. 이 섹션에서는 8개 앱에서 사용한 프레임워크를 다뤄요.

HealthKit

사용 앱: Return, Water

HealthKit은 권한 처리와 플랫폼 가드를 신중하게 다뤄야 해요.

// Always check availability and authorization
import HealthKit

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

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

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

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

HealthKit에 대한 에이전트 규칙: - 항상 HKHealthStore.isHealthDataAvailable()로 가드하세요 - 권한이 있다고 가정하지 마세요. 쓸 때마다 확인하세요 - 멀티 플랫폼 코드에는 #if canImport(HealthKit)를 사용하세요. tvOS에서는 HealthKit을 사용할 수 없어요 - HealthKit이 제공하는 범위를 넘어 건강 데이터를 로컬에 저장하지 마세요 - Info.plist에 NSHealthShareUsageDescriptionNSHealthUpdateUsageDescription을 모두 포함하세요

SpriteKit

사용 앱: TappyColor, Starfield Destroyer

SpriteKit의 scene graph 모델에는 명확한 에이전트 지침이 필요해요.

## 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 sequence와 group 만들기 - physics body와 contact detection 설정하기 - 게임 상태 머신 구현하기 - HUD overlay 만들기

SpriteKit에서 에이전트가 약한 것: - 성능에 민감한 게임 루프. 에이전트가 프레임마다 불필요한 작업을 추가해요 - 복잡한 물리 시뮬레이션. 정밀도가 필요하면 커스텀 physics가 SKPhysicsBody보다 나아요 - particle effect 튜닝. 시각적 작업이라 반복이 필요해요

Metal

사용 앱: amp97, Water, Starfield Destroyer

Metal은 에이전트가 가장 어려워하는 프레임워크예요. GPU programming model은 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번의 빌드-오류-수정 주기를 거쳐야 할 기능도 하나의 자율 루프 안에서 완료됩니다.

잘 작동하는 경우: 명확한 승인 기준이 있는 잘 정의된 기능.

깨지는 경우: 열린 결말의 기능(“보기 좋게 만들어줘”), 성능에 민감한 코드, 또는 시각적 검증이 필요한 모든 작업.

iOS를 위한 Subagent 위임

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 관계 순환 보통 강함 (GPT-4o)
@MainActor 격리 누락 강함 보통
Metal 버퍼 정렬 보통 보통
Retain cycle 감지 강함 (Opus) 강함 (o3)
API 지원 중단 인지 강함 (더 최신 학습 데이터) 보통
동시성 경쟁 조건 강함 강함 (다른 패턴 포착)

듀얼 리뷰의 목적은 더 많은 버그를 찾는 것이 아니라 다른 종류의 버그를 찾는 것입니다. 각 모델 계열은 패턴 인식에서 서로 다른 실패 모드를 가집니다.

여러 앱에 걸친 배치 작업

프레임워크나 패턴 변경이 여러 앱에 영향을 줄 때는 다음처럼 처리합니다.

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

주의해서 사용하세요. 비대화형 모드에는 --dangerously-skip-permissions 플래그가 필요하지만, 이 플래그는 모든 안전 검사를 우회합니다. .pbxproj 파일을 보호하도록 PreToolUse 훅이 준비되어 있는지 확인하세요.

Apple 온디바이스 LLM를 사용하는 앱

앱이 Apple의 Foundation Models 프레임워크를 호출한다면(예: 오프라인 요약, 분류, 구조화된 출력 생성), 에이전트는 프롬프트 예산을 알아야 합니다. iOS 26.4에서는 기존의 4096토큰 추정을 대체하는 SystemLanguageModel용 API 2개가 추가되었습니다. contextSize는 모델이 단일 대화에서 받아들이는 최대 토큰 수이고, 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 시그니처는 반드시 필요합니다. 동기 버전을 붙여 넣는 에이전트는 컴파일에 실패합니다.


실제 사례 연구

추상적인 조언은 쉬워요. 여기서는 실패 사례까지 포함해, agent가 도와주는 iOS 개발이 실제로 어떻게 작동하는지 보여주는 8개 앱의 구체적인 시나리오를 소개해요.

사례 연구 1: Return에 TV 앱 추가하기 (성공)

작업: 이미 iOS와 watchOS 버전이 있던 명상 타이머 Return에 tvOS 타깃을 추가하는 일이었어요. TV 앱에는 Siri Remote 내비게이션, 대형 화면 UI, iOS 앱과의 설정 동기화가 필요했어요.

agent가 잘한 것: - 기존 iOS TimerManager를 읽고, tvOS에서 사용할 수 없는 Live Activities와 HealthKit을 제외한 TVTimerManager를 만들었어요 - Siri Remote 포커스 내비게이션용 커스텀 버튼 스타일(TVCapsuleButtonStyle, TVCircleButtonStyle)을 만들었어요 - Siri Remote로 사용할 수 없는 wheel picker를 +/- 버튼으로 대체하는 TVStepper 컴포넌트를 만들었어요 - App Groups(group.com.941apps.Return)를 통해 설정 동기화를 구현했어요 - 공유 코드 전반에 #if os(tvOS) guard를 추가했어요 - MCP에서 platform=tvOS Simulator,name=Apple TV로 빌드하고 테스트했어요

제가 직접 해야 했던 것: - Xcode에서 tvOS 타깃 만들기(File > New > Target > tvOS App) - 새 타깃을 Xcode 프로젝트에 추가하기(.pbxproj 변경) - TV 타깃의 App Groups entitlement 설정하기 - TV 타깃을 기존 scheme에 추가하거나 새 scheme 만들기 - agent가 만든 모든 Swift 파일을 TV 타깃에 직접 추가하기 - Siri Remote 내비게이션을 직접 테스트하기(agent는 포커스 동작을 평가할 수 없어요)

결과: agent가 도와준 약 3시간의 작업으로 15개의 새 Swift 파일과 완전히 작동하는 TV 앱이 만들어졌어요. 제 추정으로는 agent가 구현 작업의 약 80%를 처리했고, 저는 Xcode UI 상호작용이 필요한 부분(entitlements, target setup, capability flags)과 실제 Apple TV에서의 수동 포커스 테스트를 맡았어요. 이 코드베이스에서 비슷한 기능을 agent 없이 출시해 본 경험에 비추면, 같은 작업을 혼자 했다면 며칠이 걸렸을 거예요.

사례 연구 2: amp97의 Metal Shader 디버깅 (부분 실패)

작업: oscilloscope shader에 energy 기반 intensity 시스템을 추가하는 일이었어요. 시각화가 오디오 energy에 맞춰 pulse해야 했어요.

일어난 일: 1. agent는 uEnergy uniform과 HDR tonemapping을 추가하는 유효한 Metal shader 수정을 작성했어요 2. 코드는 오류 없이 컴파일됐어요 3. 기기에서는 시각화가 완전히 흰색으로 보였어요. intensity 계수가 너무 높았어요(0.30이 아니라 3.5) 4. agent는 흰 화면을 볼 수 없어서 피드백 신호가 없었어요 5. 제가 눈으로 문제를 확인하고 agent에게 계수를 낮추라고 요청했어요 6. agent는 계수를 낮췄지만, 전체 energy state machine이 너무 복잡해서 visualizer를 다른 방식으로 망가뜨렸어요 7. 전부 되돌렸어요. 두 커밋(67959ed, cda4830)이 869d914에서 revert됐어요

교훈: Metal shader는 agent 지원 개발에서 가장 어려운 영역이에요. 피드백 루프가 끊겨 있기 때문이에요. agent는 문법(컴파일됨)과 의미(올바른 타입)는 검증할 수 있지만, 출력(제대로 보이는지)은 검증할 수 없어요. 시각 동작을 바꾸는 shader 수정은 반드시 기기에서 사람이 확인해야 해요.

이후 CLAUDE.md에 추가한 내용: “DO NOT attempt energy state modifications to the oscilloscope shader without extremely careful coefficient testing. Previous attempt broke the visualizer with coefficients 10x too high.”

사례 연구 3: Banana List의 SwiftData 마이그레이션 (성공)

작업: 데이터 모델을 V1에서 V2로 마이그레이션하면서 GroceryItemquantity 필드를 추가하고, 관계가 있는 새 Category 모델을 추가하는 일이었어요.

agent가 한 일: 1. 기존 V1 모델 정의를 읽었어요 2. 새 필드와 관계가 포함된 V2 모델 정의를 만들었어요 3. SchemaMigrationPlan protocol conformance가 있는 GroceryMigrationPlan을 작성했어요 4. V1toV2 마이그레이션 단계를 구현했어요. 기본 quantity: 1category: nil을 추가했어요 5. 새 필드를 지원하도록 모든 view를 업데이트했어요 6. preview용 SampleData.swift를 업데이트했어요 7. MCP로 빌드하고 테스트를 실행했어요. 모두 통과했어요 8. 마이그레이션 전용 unit test를 만들었어요

핵심: SwiftData 마이그레이션은 Apple 문서와 학습 데이터에 충분히 반영된, 잘 정의된 protocol 패턴을 따르기 때문에 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, 날짜, duration, source device, HealthKit sync status를 포함한 MeditationSession 데이터 모델을 만들었어요 2. iCloud 동기화를 위해 NSUbiquitousKeyValueStore를 관리하는 SessionStore singleton을 만들었어요 3. merge conflict resolution을 구현했어요(UUID 기반 중복 제거) 4. 플랫폼별 적응이 포함된 SessionHistoryView를 추가했어요(iOS에서는 swipe-to-delete, tvOS에서는 focus 기반) 5. 다른 기기에서 온 세션을 iPhone 쪽 HealthKit 동기화에 연결했어요

반복이 필요했던 부분: 초기 구현은 iPhone 앱이 background에서 실행되는 경우를 처리하지 못했어요(sync를 위한 foreground notification이 없음). agent에게 구체적인 지침이 필요했어요. “NSUbiquitousKeyValueStore.didChangeExternallyNotification을 사용해 background KV 변경 시 sync를 트리거하세요.” 이 힌트 이후 구현은 올바르게 작동했어요.

교훈: architecture가 명확히 설명되어 있으면 agent는 멀티 플랫폼 architecture 패턴을 잘 처리해요. iCloud sync 패턴은 사소하지 않지만, agent가 이해한 문서화된 Apple 패턴을 따릅니다. edge case(background sync)는 문서화가 충분하지 않아 사람이 가진 domain 지식이 필요했어요.

사례 연구 5: Starfield Destroyer의 Game Center 통합 (성공)

작업: space shooter에 Game Center leaderboards와 achievements를 추가하는 일이었어요.

agent가 잘한 것: - 앱 entry point에 GKLocalPlayer.local.authenticateHandler를 구현했어요 - score submission과 achievement reporting 메서드가 있는 GameCenterManager를 만들었어요 - 모든 Game Center 작업 전에 authentication state checking을 추가했어요 - offline case를 자연스럽게 처리했어요(Game Center 없이도 게임은 플레이되고, 재연결되면 제출됨) - 8-ship progression system에 맞는 achievement 정의를 만들었어요

수동 작업이 필요했던 것: - App Store Connect에서 leaderboards와 achievements 만들기(웹 포털이라 agent가 접근할 수 없음) - Xcode에서 Game Center entitlement 설정하기 - sandbox Game Center 계정으로 테스트하기(기기에서 수동 sign-in 필요)


Agent를 활용한 프로젝트 라이프사이클

새 iOS 프로젝트 시작하기

Agent의 도움을 받아 새 프로젝트를 시작할 때 가장 좋은 워크플로는 다음과 같습니다.

1단계: 사람이 설정하기 (15-30분) 1. Xcode 프로젝트를 만듭니다 (File > New > Project) 2. 서명과 capabilities를 설정합니다 3. 배포 대상과 지원 대상을 설정합니다 4. 필요한 entitlements를 추가합니다 (HealthKit, Game Center 등) 5. 프로젝트 정체성과 규칙을 담은 초기 CLAUDE.md를 만듭니다

2단계: Agent 구현 (몇 시간에서 며칠) 1. Agent가 데이터 모델을 만듭니다 (SwiftData, Core Data 또는 일반 structs) 2. Agent가 문서화된 패턴에 따라 views를 만듭니다 3. Agent가 manager/service classes에 비즈니스 로직을 구현합니다 4. Agent가 unit tests를 작성합니다 5. MCP를 통한 build-test-fix 루프를 실행합니다 (자율)

3단계: 사람이 통합하기 (30-60분) 1. Agent가 만든 파일을 Xcode targets에 추가합니다 2. 서명과 entitlements를 확인합니다 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]

Agent의 효과는 CLAUDE.md가 프로젝트의 현재 상태를 얼마나 잘 반영하느냐에 따라 커집니다. 중요한 새 기능을 추가하거나, 아키텍처 패턴을 바꾸거나, 새 frameworks를 도입할 때는 CLAUDE.md를 업데이트하세요.

Agent를 사용할 때와 사용하지 않을 때

작업 Agent? 이유
새 SwiftUI view Agent는 declarative UI에 강합니다
SwiftData model 변경 범위가 명확하고 테스트할 수 있습니다
Unit tests 기계적이고 패턴 기반입니다
Refactoring 체계적이며 여러 파일에 걸칩니다
Build error 진단 예 (MCP를 통해) 구조화된 피드백 루프입니다
새 Xcode target 아니요 Xcode UI와 .pbxproj 변경이 필요합니다
서명과 provisioning 아니요 포털 기반이며 Agent가 접근할 수 없습니다
시각적 다듬기 아니요 사람의 미적 판단이 필요합니다
Metal shader 튜닝 아니요 기기 GPU 테스트가 필요합니다
App Store 제출 아니요 포털과 Xcode Organizer가 필요합니다
성능 프로파일링 아니요 Instruments가 필요합니다
접근성 감사 부분적으로 Agent는 labels를 추가할 수 있고, 사람은 VoiceOver를 확인합니다

Agent 정의 설정하기

Claude Code의 agent definition system(.claude/agents/)을 사용한다면 iOS 전용 Agent를 만드세요.

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

# iOS Developer Agent

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

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

## Build & Test — Always Use MCP

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

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

MCP returns structured JSON. Bash returns unstructured text.

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

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

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

Claude Code 세션에서 @ios-developer로 이 Agent를 참조하세요.


Agent 지원 iOS 테스트 패턴

명확한 지침을 주면 Agent는 훌륭한 unit tests를 작성합니다. 가장 좋은 결과를 내는 패턴은 다음과 같습니다.

테스트 파일 구성

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

이 방식이 잘 작동하는 이유: 번호가 매겨진 acceptance criteria는 Agent에게 체크리스트를 제공합니다. 기존 테스트 파일을 참조하면 따라야 할 패턴이 정해집니다. setUp() 사용 방식을 지정하면 Agent가 얽힌 테스트 상태를 만들지 않게 됩니다.

효과적이지 않은 테스트 프롬프트:

Write tests for TimerManager.

이런 요청은 edge cases를 놓치고 프로젝트 패턴을 따르지 않을 수 있는 일반적이고 얕은 테스트를 만들어 냅니다.

Async 테스트 패턴

Timer 기반 코드와 async 코드를 테스트할 때는 다음을 사용합니다.

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

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

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

        // When
        sut.start()

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

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

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

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

Agent에게 다시 알려줘야 하는 핵심 패턴: - @MainActor classes를 테스트하는 test methods에는 @MainActor를 붙입니다 - Task.sleep 또는 async operations를 사용하는 tests에는 async throws를 사용합니다 - 시간 기반 assertions에는 tolerance를 둡니다 (정확히 1.0초가 아니라 1.1초) - 테스트 격리를 위해 깔끔한 setUp() / tearDown()을 사용합니다

Snapshot Testing

시각적 regression 감지를 위해 swift-snapshot-testing 추가를 고려하세요.

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

Use SnapshotTesting library. Create reference images on first run.

Agent는 snapshot tests를 올바르게 설정하지만 reference images를 검토할 수는 없습니다. 초기 snapshots는 사람이 검토하고, 이후 변경에서는 Agent의 tests가 시각적 regressions를 잡아냅니다.

iOS 프로젝트의 컨텍스트 윈도우 관리

1M 컨텍스트 윈도우(Opus 4.6)는 크지만 무한하지는 않습니다. iOS 프로젝트에는 별도의 컨텍스트 관리 고려 사항이 있습니다.

iOS 파일의 토큰 비용

파일 유형 일반적인 크기 대략적인 토큰 수
SwiftUI view(단순) 50-100줄 500-1,000
SwiftUI view(복잡) 200-400줄 2,000-4,000
SwiftData model 30-80줄 300-800
Manager/service class 100-300줄 1,000-3,000
Metal shader(.metal) 50-200줄 500-2,000
Unit test 파일 50-200줄 500-2,000
CLAUDE.md 100-300줄 1,000-3,000
MCP 응답(build) 다양함 200-2,000
MCP 응답(test) 다양함 500-5,000

50개 파일 프로젝트의 경우: 모든 파일을 읽어도 약 50,000-100,000토큰을 사용합니다. 1M 윈도우 안에 충분히 들어갑니다. agent는 전체 프로젝트를 컨텍스트에 유지할 수 있습니다.

100개 이상 파일 프로젝트의 경우: 선택적으로 읽는 방식이 필요해집니다. agent는 먼저 CLAUDE.md를 읽고(파일 구조 주석을 확인하기 위해), 필요한 특정 파일을 이어서 읽습니다. 그래서 CLAUDE.md의 파일 주석이 중요합니다. 모든 파일을 읽지 않고도 agent를 올바른 파일로 안내해 주기 때문입니다.

대규모 프로젝트 전략

  1. 자세한 CLAUDE.md 파일 주석 — agent는 파일 맵을 읽고 관련 파일로 바로 이동합니다
  2. Subagent 위임 — 탐색과 리서치를 subagent에 맡깁니다(깨끗한 컨텍스트, 요약 반환)
  3. 집중된 프롬프트 — “Modify SettingsView.swift to add a new toggle”이 “update the settings”보다 낫습니다
  4. 세션 경계 — 관련 없는 기능은 긴 세션을 계속 늘리기보다 새 세션에서 시작하세요
  5. /compact 사용 — Claude Code의 compaction 명령은 대화를 요약하고 컨텍스트를 비웁니다

MCP 토큰 효율성

MCP를 써야 하는 가장 강력한 이유 중 하나는 구조화된 JSON 응답이 원시 xcodebuild 출력보다 훨씬 적은 토큰을 사용한다는 점입니다.

시나리오 원시 Bash 토큰 MCP 토큰 절감률
성공한 build 3,000-10,000 200-500 85-95%
실패한 build(오류 1개) 3,000-10,000 300-800 90-92%
Test 결과(20개 test) 2,000-5,000 500-1,000 75-80%
Simulator 목록 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.

또는 CLAUDE.md에 scheme 이름을 명시적으로 추가하세요.

## 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 응답의 실제 status 필드를 확인하세요.

“Simulator hangs during boot”

모든 simulator를 종료하고 다시 부팅하세요.

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

규칙은 “하지 말아 주세요”라고 말합니다. Hooks는 “할 수 없습니다”라고 말합니다.

자주 묻는 질문

어떤 agent runtime으로 시작해야 하나요?

XcodeBuildMCP를 사용하는 Claude Code CLI로 시작하세요. 가장 깊은 MCP 통합, 가장 성숙한 hook 시스템, 그리고 전체 iOS 프로젝트를 작업 메모리에 담을 수 있는 1M 컨텍스트 윈도우(Opus 4.6)를 갖추고 있습니다. 여기서 시작한 뒤, 워크플로가 성숙해지면 리뷰용으로 Codex를 추가하고 빠른 인라인 편집용으로 Xcode 네이티브 agent를 추가하세요.

MCP 서버가 둘 다 필요한가요?

대부분의 개발자에게는 XcodeBuildMCP만으로도 필요한 작업의 90%(빌드, 테스트, 시뮬레이터, 디버깅)를 처리할 수 있습니다. 문서 검색, Swift REPL 검증, SwiftUI 프리뷰 렌더링이 필요하다면 Apple의 Xcode MCP를 추가하세요. 나중에 언제든 추가할 수 있습니다. 두 서버는 서로 독립적입니다.

agent가 새 Xcode 프로젝트를 처음부터 만들 수 있나요?

XcodeBuildMCP에는 새 Xcode 프로젝트를 스캐폴딩하는 create_project 도구가 포함되어 있습니다. 하지만 프로덕션 앱의 경우, 서명, capabilities, target 설정을 정확히 맞추기 위해 Xcode에서 프로젝트를 만든 다음 모든 코드 구현에 agent를 사용하는 방식을 추천합니다. Xcode의 새 프로젝트 마법사에서 쓰는 5분이 agent가 생성한 프로젝트 설정 문제를 해결하느라 쓰는 몇 시간을 아껴줍니다.

agent는 Swift Package Manager 의존성을 어떻게 처리하나요?

잘 처리합니다. Package.swift는 agent가 안정적으로 읽고 편집할 수 있는 표준 Swift 파일입니다. 의존성 추가, 버전 범위 업데이트, target 설정이 모두 잘 작동합니다. 한계는 .xcodeproj 기반 의존성 관리(Xcode의 패키지 해석 UI)입니다. 이는 Xcode가 관리하는 영역이므로 agent가 편집해서는 안 됩니다.

agent가 App Store에 제출할 수 있나요?

아니요. App Store 제출에는 Xcode의 Organizer, provisioning profile, 스크린샷, 메타데이터, App Store Connect 포털이 필요합니다. 이 중 어느 것도 agent가 의미 있게 조작할 수 있는 방식으로 MCP나 command-line 도구에 노출되어 있지 않습니다. agent는 archive 직전까지의 모든 작업, 즉 구현, 테스트, 버그 수정, 문서화를 처리합니다. 제출의 마지막 단계는 여전히 사람이 직접 해야 합니다.

다만 agent는 App Store 메타데이터 작성에는 도움을 줄 수 있습니다. 최신 변경 사항을 바탕으로 앱 설명, 키워드, 새로운 기능 텍스트를 작성해 달라고 요청하세요. 이는 agent가 특히 잘하는 텍스트 생성 작업입니다.

agent를 활용한 iOS 개발에서 secrets와 API keys는 어떻게 처리하나요?

secrets는 절대 commit하지 마세요. backend API에 연결되는 iOS 앱의 경우:

  1. 환경별 설정에는 .xcconfig 파일을 사용하세요
  2. .xcconfig 파일을 .gitignore에 추가하세요
  3. Info.plist build settings를 통해 설정 값을 참조하세요
  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는 어떤가요? agent가 작성할 수 있나요?

agent는 animation 코드를 문법적으로 잘 작성하지만, 결과를 시각적으로 검증할 수는 없습니다. 단순한 animation(.animation(.spring()), .transition(.slide), withAnimation { })은 올바른 결과를 만듭니다. 정확한 타이밍이 필요한 복잡한 다단계 animation은 agent가 수행할 수 없는 시각적 반복 조정이 필요합니다.

효과적: “타이머가 상태 사이를 전환할 때 spring animation을 추가하세요.”

효과적이지 않음: “타이머 animation이 만족스럽게 느껴지게 만드세요.” (주관적이며 시각적 튜닝이 필요합니다.)

agent는 error handling 패턴을 어떻게 처리하나요?

매우 잘 처리합니다. agent는 Swift의 do/catch, Result, async throws 패턴을 이해합니다.

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

agent는 적절한 사용자 표시 메시지가 포함된 구조적인 error handling을 생성합니다. 다만 때때로 오류를 과도하게 처리하므로(전파되어야 할 예외까지 catch), catch 블록은 리뷰하세요.

accessibility 구현에 agent를 사용할 수 있나요?

부분적으로 가능합니다. agent는 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

agent가 할 수 없는 일: VoiceOver 탐색 순서가 올바른지 검증하기, Dynamic Type scaling 테스트하기, 색상 대비 비율 평가하기. 검증에는 Xcode의 Accessibility Inspector를 사용하세요.

SwiftData를 사용하지 않는 경우 Core Data migration은 agent가 어떻게 처리하나요?

agent는 Core Data migration mappings와 model versions를 작성하지만, 수동 Xcode 단계(새 model versions 생성, 현재 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

agent는 SwiftUI previews를 어떻게 처리하나요?

두 가지 방식이 있습니다. 1. Apple Xcode MCP의 RenderPreview 도구는 previews를 headless로 렌더링하고 결과를 반환합니다. agent는 preview가 오류 없이 컴파일되고 렌더링되는지 검증할 수 있지만, 시각적 정확성은 평가할 수 없습니다. 2. build_sim을 통한 build 기반 검증은 preview providers가 컴파일되는지 확인합니다. preview가 런타임에 crash하더라도 build는 성공합니다. crash는 Xcode가 preview를 렌더링하려고 할 때만 나타납니다.

preview를 시각적으로 검증하려면 여전히 Xcode를 열어야 합니다.

visionOS와 Apple Vision Pro는 어떤가요?

같은 패턴이 적용됩니다. XcodeBuildMCP는 visionOS simulators를 지원하며, architectural patterns(@Observable, NavigationStack, SwiftData)도 동일합니다. RealityKit 전용 코드(3D 콘텐츠, immersive spaces, hand tracking)는 Metal과 같은 한계를 따릅니다. agent는 올바른 코드를 작성할 수 있지만 spatial output은 검증할 수 없습니다.

프로젝트가 얼마나 커지면 agent가 어려움을 겪나요?

컨텍스트 윈도우 크기가 제한 요소입니다. Opus 4.6의 1M token 윈도우를 사용하면 Claude Code는 약 50-70개의 Swift 파일을 동시에 active working memory에 담을 수 있습니다. 더 큰 프로젝트에서는 agent가 파일 검색과 선택적 읽기를 사용해 codebase의 일부를 다룹니다. 100개 이상의 파일이 있는 프로젝트도 잘 작동합니다. agent가 모든 것을 context에 들고 있는 대신 필요할 때 파일을 읽을 뿐입니다.

실질적인 한계는 파일 수가 아니라 codebase coherence입니다. 자세한 CLAUDE.md가 있는 잘 문서화된 200개 파일 프로젝트가 문서화되지 않은 30개 파일 프로젝트보다 더 좋은 결과를 냅니다.

iOS 개발에 agent를 사용하려면 Swift를 알아야 하나요?

agent 출력물을 리뷰하고 architectural decisions를 내릴 수 있어야 합니다. 모든 줄을 직접 작성할 필요는 없지만, agent가 잘못된 선택을 했을 때 알아차릴 만큼 Swift를 이해해야 합니다. 특히 concurrency, memory management, framework-specific patterns에서 그렇습니다. agent는 기존 실력을 10배 증폭하는 도구이지, 그 실력을 대체하는 도구가 아닙니다.

agent는 Swift 파일의 merge conflicts를 어떻게 처리하나요?

agent는 Swift source files의 merge conflicts를 안정적으로 해결합니다. 표준 conflict markers(<<<<<<<, =======, >>>>>>>)는 모든 agent runtime이 잘 이해합니다. 하지만 .pbxproj 파일의 merge conflicts는 여전히 수동으로 해결해야 하는 작업입니다. agent에게 .pbxproj conflicts를 해결하라고 요청하지 마세요.

iOS 개발에 agent를 실행하는 비용은 어느 정도인가요?

Anthropic의 Max plan(Opus 4.6, 1M context)을 사용하면 일반적인 iOS 개발 세션은 30-120분 동안 진행되며 200K-800K tokens를 처리합니다. MCP tool calls는 오버헤드가 작습니다(structured JSON responses는 raw build output보다 token 효율이 높습니다). 비용은 다른 codebase에서 Claude Code를 실행하는 것과 비슷합니다. iOS 개발이 web 개발보다 의미 있게 더 비싸거나 더 저렴하지는 않습니다.

UIKit 프로젝트에도 agent를 사용할 수 있나요?

네, 하지만 agent는 SwiftUI에서 더 효과적입니다. UIKit은 boilerplate가 더 많고, declarative structure가 덜하며, agent가 편집할 수 없는 Interface Builder 파일을 포함하는 경우가 많습니다. UIKit 프로젝트가 있다면 UI는 수동으로 처리하면서 model layer와 business logic에 agent를 사용하거나, view를 점진적으로 SwiftUI로 마이그레이션하는 방식을 고려하세요.

agent는 localization을 어떻게 처리하나요?

agent는 .xcstrings(Xcode string catalog) 파일을 효과적으로 만들고 편집합니다. 새 localization keys를 추가하고, 번역을 제공하며, 여러 언어 간의 일관성을 유지할 수 있습니다. .xcstrings 파일의 structured JSON format은 agent 친화적입니다. .strings 파일(legacy format)의 경우에도 agent는 잘 처리합니다. 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.publish, NotificationCenter, 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 클래스를 만들어 Swift 6.2 동시성 경고가 발생하거나, UI 업데이트가 메인 스레드 밖에서 일어나 런타임 크래시가 발생합니다.

예방:

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

발생 상황: Agent가 type-safe한 NavigationLink(value:) + .navigationDestination(for:) 패턴 대신 deprecated된 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”)으로 build 명령을 작성합니다.

예방: MCP가 이를 처리합니다. list_sims가 사용 가능한 simulator를 찾아줍니다. CLAUDE.md에는 다음을 둡니다.

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

실수 6: 잘못된 디렉터리에 파일 만들기

발생 상황: Agent가 새 view 파일을 Views/ 하위 디렉터리가 아니라 프로젝트 루트에 만들거나, model을 잘못된 group에 넣습니다.

예방: CLAUDE.md의 파일 구조 주석이 배치를 안내합니다. 추가로 다음을 둡니다.

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

실수 7: Platform Availability 처리하지 않기

발생 상황: Agent가 tvOS에서는 사용할 수 없는 HealthKit을 tvOS용으로도 컴파일되는 공유 코드에서 사용하거나, watchOS 코드에서 ActivityKit을 사용합니다.

예방:

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

실수 8: 단순한 기능을 과도하게 설계하기

발생 상황: 20줄짜리 유틸리티 함수면 충분한 작업에 agent가 protocol, protocol extension, concrete implementation, 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가 바꾸지 못한 것: Architecture 결정, visual design, performance optimization, App Store submission입니다. 이런 부분은 여전히 사람이 주도합니다.

배수 효과는 실제지만 한계가 있습니다. 8개 앱 포트폴리오 전반에 대한 제 주관적 추정치는, 문서화가 잘 되어 있고 적절한 MCP 및 hook 설정이 있는 프로젝트에서 feature 개발 시간이 3-5배 개선된다는 것입니다. 이는 control group과 비교해 측정한 수치가 아닙니다. 같은 codebase에서 agent-assisted feature와 동등한 solo work를 wall-clock 기준으로 비교한 결과입니다. 문서화가 없고 hook도 없는 프로젝트에서는 개선폭이 1.5-2배 정도에 그칠 수 있습니다. Agent가 build보다 추측에 너무 많은 시간을 쓰기 때문입니다.19

효과가 큰 투자: CLAUDE.md, hook, MCP 설정에 쓰는 시간입니다. 설정에 1시간을 쓰면 agent 실수를 바로잡는 데 드는 여러 시간을 아낄 수 있습니다. 설정이 곧 제품이고, agent는 실행 엔진입니다.

놀라웠던 점: MCP 서버가 작업 흐름을 얼마나 크게 바꿨는지입니다. MCP 전의 agent는 Swift를 이해하는 고급 텍스트 편집기에 가까웠습니다. MCP 후에는 write, build, test, debug, iterate를 수행하는 개발 파트너가 됩니다. 구조화된 feedback loop가 코드를 작성하는 agent와 코드를 출시하는 agent의 차이를 만듭니다.

과거의 저에게 말하고 싶은 것: 가장 작은 앱(Reps, 14개 파일)부터 시작해 MCP와 hook 설정을 제대로 잡고, 충실한 CLAUDE.md를 작성한 다음, 그 패턴을 더 큰 프로젝트로 확장하세요. 63개 파일짜리 multi-platform 앱부터 시작하지 마세요. Infrastructure 투자는 프로젝트 크기와 관계없이 같습니다. 작은 프로젝트에서 한 번 제대로 만든 뒤 나머지에 복사하세요.

미래: Xcode 26.3의 native agent integration은 끝이 아니라 시작입니다. Apple이 MCP 지원을 제공한다는 것은 toolchain이 agent-first development로 이동하고 있다는 뜻입니다. 지금 agent-compatible project structure에 투자하는 개발자, 즉 깔끔한 CLAUDE.md 파일, 테스트 가능한 architecture, 자동화된 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" }]
}

Architecture 규칙

@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 Tool 우선순위

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.2, time.modified2026-05-12T07:40:41.737Z를 반환했습니다.13
2026-05-16 권장 Xcode를 26.5+로 올렸습니다(2026-05-11 릴리스). 새로운 Coding Intelligence 기능 2가지는 agent 워크플로에 중요합니다. 이제 coding assistant에서 메시지를 대기열에 넣을 수 있어 다음 요청을 준비하기 전에 응답을 기다리지 않아도 되고, agents가 진행 전에 명확화 질문을 할 수 있습니다. 두 기능 모두 Xcode의 native agents를 Claude Code 또는 Codex 세션과 병렬로 실행할 때의 마찰을 줄입니다.13 XcodeBuildMCP 최신성 확인: v2.5.2(2026-05-12)가 최신이며, 번들 AXe 1.7.0과 로그 캡처 필터 검증 문제 수정이 추가되었습니다. v2.1.0+의 xcodebuildmcp init 흐름은 계속 권장 설치 경로입니다.
2026-04-28 agent 워크플로용 권장 Xcode를 26.4+로 올렸습니다(26.4.1, 2026-04-16, 빌드 17E202가 최신 안정 버전이며 버그 수정만 포함). agent가 작성한 테스트와 현지화에 유용한 Xcode 26.4 기능(2026-03-24, 빌드 17E192)을 인용했습니다: Swift Testing 이미지 첨부, Issue.record의 심각도, 첨부된 crashlog가 있는 UI 테스트 충돌 경고(특히 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까지 back-deploy됨). agent가 생성하는 FM 프롬프트 예산 코드 패턴을 추가했습니다. iOS 26.4.2(4월 22일)와 iOS 26.5 beta 3(4월 20일)은 agent toolchain에 영향을 주는 변경 없이 출시되었습니다.
2026-04-13 최초 공개. 앱 8개, 런타임 3개, MCP 설정, CLAUDE.md 패턴, hooks, 사례 연구.

참고 자료


  1. XcodeBuildMCP에는 기본적으로 Sentry telemetry가 포함되어 있습니다. 프로젝트의 privacy documentation은 전송되는 내용을 자세히 설명합니다: 오류 메시지, stack trace, 경우에 따라 파일 경로입니다. XCODEBUILDMCP_SENTRY_DISABLED=true 환경 변수를 사용하면 완전히 opt out할 수 있습니다. 

  2. Anthropic, “Model Context Protocol Specification,” modelcontextprotocol.io/specification. MCP 사양은 XcodeBuildMCP와 Apple의 Xcode MCP가 모두 구현하는 JSON-RPC transport, tool discovery, resource protocol을 정의합니다. 

  3. XcodeBuildMCP, github.com/getsentry/XcodeBuildMCP. Sentry가 유지 관리하는 오픈 소스입니다. simulator, device, debugging, UI automation 워크플로 전반에 걸쳐 59개 tools를 제공합니다. changelog가 있는 semantic versioning을 사용합니다. 

  4. Apple은 Xcode 26.3 intelligent developer tools 이니셔티브의 일부로 Xcode MCP 서버를 도입했으며, MCP를 AI coding assistant와 Xcode toolchain 사이의 interface layer로 포지셔닝했습니다. 공식 문서는 Xcode Release Notes를 참고하세요. 

  5. Rudrank Riyam, “Exploring Xcode Using MCP Tools,” rudrank.com/exploring-xcode-using-mcp-tools-cursor-external-clients, 2026. Apple의 MCP tool 수, XPC 의존성, 문서 검색 기능에 대한 독립적인 확인 자료입니다. 

  6. Jimenez, C.E., Yang, J., Wettig, A., et al., “SWE-bench: Can Language Models Resolve Real-World GitHub Issues?” ICLR 2024. arxiv.org/abs/2310.06770. 구조화된 tool 접근 권한을 가진 agents는 구조화되지 않은 shell commands로 제한된 agents보다 훨씬 뛰어난 성능을 보였습니다. 이 결과는 agent 효율성을 위한 구조화된 MCP interfaces의 타당성을 뒷받침합니다. 

  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 예시를 통해 59개 MCP tools를 확인합니다. tool categories: simulator, device, debugging, UI automation. Homebrew 또는 npx로 설치합니다. 

  10. Swiftjective-C, “Agentic Coding in Xcode 26.3 with Claude Code and Codex,” swiftjectivec.com, 2026년 2월. Xcode 26.3이 Settings > Intelligence를 통해 native Claude Agent와 Codex runtime support를 제공한다는 점을 확인합니다. xcrun mcpbridge를 통해 20개 MCP tools가 노출됩니다. 

  11. Blake Crosley, “Two MCP Servers Made Claude Code an iOS Build System,” blakecrosley.com/blog/xcode-mcp-claude-code, 2026년 2월. 같은 저자의 iOS 개발 워크플로에서 나온 설정 walkthrough와 실제 결과입니다. 

  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는 이 요구 사항에 나열된 platform set에 포함되어 있지 않습니다. 

  13. Apple, “Xcode 26.5 Release Notes”“Xcode 26.5 (17F42) - Releases”. Xcode 26.5는 Apple에 의해 2026-05-11에 빌드 17F42로 등재되었습니다. release notes에서 인용한 Coding Intelligence 기능 2가지: 현재 응답이 끝날 때까지 기다리지 않고 coding assistant에서 메시지를 대기열에 넣을 수 있으며(174563016), agents가 진행 전에 context를 수집하기 위해 명확화 질문을 할 수 있습니다(175182375). 또한 12개월 약정 월간 구독을 위한 StoreKit Testing 지원(PricingTerms model, billingPlanType PurchaseOption, TransactionSubscriptionRenewalInfoCommitmentInfo)과 async/await 작업 중 thread를 이동하는 Swift Tasks를 step through할 때의 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). release notes에서 인용한 기능: Swift Testing은 이제 CGImage, NSImage, UIImage, CIImage를 통한 이미지 첨부를 지원합니다. Issue.record는 심각도 수준을 받습니다. 일부 UI 테스트 앱 충돌, 특히 XCUIApplication(bundleIdentifier:) 또는 XCUIApplication(url:)를 통해 상호작용한 앱은 테스트 실패 대신 첨부된 crashlog가 있는 경고로 보고됩니다. String Catalog 편집기는 entry의 cut/copy/paste, 언어 제거, 기존 언어에서 번역 pre-fill을 추가하며, BUILD_ONLY_KNOWN_LOCALIZATIONS 설정도 포함됩니다. 

  15. Apple Developer News, “Xcode 26.4.1 (Build 17E202) Now Available”, 2026-04-16. 버그 수정 dot release만 해당합니다. iOS / macOS / visionOS pre-26.4에서 누락된 symbols로 발생하는 MetricKit 충돌과 Swift async stack-allocation 버그(swift_asyncLet_finish의 “freed pointer was not the last allocation”)를 수정합니다. 

  16. getsentry/XcodeBuildMCP v2.1.0 release, 2026-02-23. agent skills + MCP config를 한 번에 설치하는 xcodebuildmcp init CLI command를 추가하여 standalone install-skill.sh script를 대체했습니다. Claude Code, Cursor, Codex를 자동 감지합니다. --print(지원되지 않는 clients용 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를 확인합니다. 이전 community 추정치였던 4096-token hardcode를 대체합니다. 

  18. 파일 수는 2026-04-27에 8개의 private app repositories 각각에서 실행한 find . -name '*.swift' -not -path '*/Tests/*' | wc -l에서 산출했습니다. test files는 제외했습니다. 총합은 §The Portfolio의 앱별 breakdown table과 내부적으로 일치합니다. 

  19. 주관적인 wall-clock 추정치이며, control group과 비교한 측정값이 아닙니다. 3-5x 수치는 2026년 agent-assisted features와 agent 워크플로 이전에 같은 codebases에서 출시한 동등한 solo features의 time-to-feature 비교에 대한 저자의 기억입니다. benchmark가 아니라 MCP + hook 설정 이후 기대할 수 있는 수준에 대한 heuristic으로 보세요. 

NORMAL ios-agent-development.md EOF