Cómo crear apps de iOS con agentes de IA: la guía del profesional
# Crea apps de iOS más rápido con agentes de IA. Claude Code, Codex CLI, Xcode 26.3 nativo, MCP, patrones de CLAUDE.md, hooks y lecciones de 8 apps.
TL;DR: Tres runtimes de agentes ahora generan código para iOS: Claude Code CLI con MCP, Codex CLI con MCP, y los agentes nativos de Intelligence de Xcode 26.3. Dos servidores MCP (XcodeBuildMCP con 59 herramientas y
xcrun mcpbridgede Apple con 20 herramientas) le dan a los agentes acceso estructurado a builds, pruebas, simuladores y depuración. Esta guía cubre patrones reales de CLAUDE.md, configuraciones de hooks y evaluaciones honestas de qué funciona y qué se rompe — basadas en 8 apps de iOS en producción que totalizan 293 archivos Swift.17 Los agentes destacan en vistas SwiftUI, modelos SwiftData, refactorización y diagnóstico de errores de build. Fallan en modificaciones de .pbxproj, firma de código y depuración visual. La brecha entre “el agente escribe Swift” y “el agente publica una app de iOS” se cierra mediante configuración, no mediante prompts.
He construido 8 apps de iOS con agentes de codificación de IA. No prototipos — apps en el App Store, con integraciones de HealthKit, shaders de Metal, física de SpriteKit, sincronización con iCloud, Live Activities, tablas de líderes de Game Center y objetivos multiplataforma que abarcan iOS, watchOS y tvOS. Cada línea de Swift en estas apps fue escrita por un agente y revisada por mí, o escrita por mí y refactorizada por un agente. Según mi estimación, los agentes manejaron el grueso de la autoría a nivel de líneas; yo me encargué de la revisión, el alcance y las partes que requieren juicio humano (acabado visual, firma, ajuste de rendimiento, envío al App Store).
Esta guía es la referencia que me hubiera gustado tener cuando empecé. Cubre la pila completa: qué runtime de agente usar, cómo configurar servidores MCP para acceso estructurado al build, qué poner en tu CLAUDE.md, qué hooks evitan que el agente destruya tu proyecto de Xcode, y — lo más crítico — dónde fallan los agentes y necesitas tomar el control.
Puntos Clave
Para desarrolladores de iOS nuevos en agentes de IA:
- Empieza con Claude Code CLI + XcodeBuildMCP. Es el runtime más maduro con la cobertura de herramientas MCP más profunda. Instala dos comandos, agrega un CLAUDE.md a tu proyecto, y el agente puede compilar, probar y depurar sin que tengas que copiar mensajes de error.
- Nunca permitas que un agente modifique .pbxproj. Esta es la regla más importante. Un hook PreToolUse que bloquee escrituras a
.pbxprojy.xcodeproj/te ahorrará horas de recuperación. - Tu CLAUDE.md es el documento de incorporación del agente. Las horas que inviertas en él se compensan en cada sesión del agente que toque el proyecto.
Para usuarios experimentados de agentes que agregan iOS a su flujo de trabajo:
- MCP transforma el ciclo de build de iOS. Antes de MCP, los agentes escribían Swift pero no podían verificar que compilara. Con XcodeBuildMCP, el agente escribe código, lo compila, lee errores estructurados, los corrige y ejecuta pruebas — de forma autónoma.
- Tres runtimes sirven para necesidades distintas. Claude Code CLI para sesiones agénticas profundas, Codex CLI para trabajo headless por lotes, los agentes nativos de Xcode 26.3 para correcciones rápidas en línea sin salir del IDE.
- La infraestructura de hooks se traslada sin problema. Tus formateadores PostToolUse, bloqueadores PreToolUse y hooks de ejecución de pruebas existentes funcionan igual para proyectos de iOS con ajustes menores de rutas.
Para líderes de equipo que evalúan el desarrollo de iOS asistido por IA:
- La efectividad del agente escala con la documentación del proyecto, no con el tamaño del proyecto. Una app de 63 archivos con un CLAUDE.md detallado produce mejor salida del agente que una app de 14 archivos sin él.
- El límite de .pbxproj no es negociable. Los agentes no pueden editar archivos de proyecto de Xcode de forma confiable. Tu flujo de trabajo debe contemplar la adición manual de archivos a los objetivos de Xcode.
- ROI honesto: los agentes manejan el grueso de la implementación en proyectos bien documentados — visible en la app de TV de 15 archivos publicada en 3 horas de trabajo asistido por agentes (caso de estudio más abajo). El trabajo restante — acabado visual, firma, ajuste de rendimiento, envío al App Store — requiere juicio humano.
Elige Tu Camino
| Lo que necesitas | Ve aquí |
|---|---|
| Configurar MCP por primera vez | Configuración de MCP: La Configuración Completa — instala ambos servidores, verifica, configura agentes |
| Escribir un CLAUDE.md para tu proyecto de iOS | Patrones de CLAUDE.md para Proyectos de iOS — ejemplos reales de 8 apps |
| Comparar los tres runtimes de agentes | Tres Runtimes de Agentes para iOS — Claude Code vs. Codex vs. Xcode nativo |
| Entender lo que los agentes pueden y no pueden hacer | Lo Que los Agentes Hacen Bien y Lo Que los Agentes Hacen Mal |
| Configurar hooks para desarrollo de iOS | Hooks para Desarrollo de iOS — formato al guardar, protección de .pbxproj, runners de pruebas |
| Referencia profunda (esta página) | Sigue leyendo — todo desde la configuración hasta patrones avanzados |
Cómo Usar Esta Guía
Esta es una referencia de más de 3.000 líneas. Empieza donde encaje tu nivel de experiencia:
| Experiencia | Empieza Aquí | Luego Explora |
|---|---|---|
| Nuevo en iOS + agentes | Requisitos Previos → Configuración de MCP → Tu Primera Sesión con un Agente | Patrones de CLAUDE.md, Lo Que Funciona/No Funciona |
| Desarrollador de iOS, nuevo en agentes | Tres Runtimes → Configuración de MCP → CLAUDE.md | Hooks, Patrones de Arquitectura |
| Usuario de agentes, nuevo en iOS | Patrones de Arquitectura → Lo Que los Agentes Hacen Mal → CLAUDE.md | Contexto Específico de Frameworks, Flujos de Trabajo Avanzados |
| Experimentado en ambos | Flujos de Trabajo Avanzados → Hooks → Patrones Multiplataforma | Comparación de Runtimes, El Portafolio |
Tabla de Contenidos
- El Portafolio: 8 Apps, 293 Archivos
- Requisitos Previos
- Tres Runtimes de Agentes para iOS
- Configuración de MCP: La Configuración Completa
- Patrones de CLAUDE.md para Proyectos de iOS
- Tu Primera Sesión con un Agente
- Lo Que los Agentes Hacen Bien en iOS
- Lo Que los Agentes Hacen Mal en iOS
- Hooks para Desarrollo de iOS
- Patrones de Arquitectura Que Funcionan con Agentes
- Contexto Específico de Frameworks
- Patrones Multiplataforma
- Flujos de Trabajo Avanzados
- Casos de Estudio del Mundo Real
- Ciclo de Vida del Proyecto con Agentes
- Configurando Definiciones de Agentes
- Patrones de Pruebas para iOS Asistido por Agentes
- Gestión de la Ventana de Contexto para Proyectos de iOS
- Solución de Problemas
- Errores Comunes de Agentes en iOS
- La Evaluación Honesta
- Preguntas Frecuentes
- Tarjeta de Referencia Rápida
- Referencias
Recursos Relacionados
| Tema | Recurso |
|---|---|
| Configuración de MCP para Xcode (entrada de blog más corta) | Dos Servidores MCP Hicieron de Claude Code un Sistema de Build de iOS |
| Referencia completa de Claude Code CLI | Claude Code CLI: La Guía Completa |
| Referencia de Codex CLI | Codex CLI: La Guía Completa |
| Inmersión profunda en el sistema de hooks | Anatomía de una Garra: 84 Hooks como Capa de Orquestación |
| Patrones de arquitectura de agentes | Guía de Arquitectura de Agentes |
El portafolio: 8 apps, 293 archivos
Antes de adentrarnos en la configuración, esto es de donde se nutre esta guía. No son proyectos de juguete: abarcan cinco frameworks de Apple, tres plataformas y todo el rango de complejidad de iOS, desde un tracker de entrenamientos de 14 archivos hasta un temporizador de meditación multiplataforma de 63 archivos.
| App | Stack | Archivos | Complejidad |
|---|---|---|---|
| Banana List | SwiftUI + SwiftData + sincronización con iCloud Drive + servidor MCP para Claude Desktop | 53 | CRUD completo, sincronización con iCloud, servidor MCP personalizado que expone los datos de la app a Claude Desktop |
| Ace Citizenship | App de estudio en SwiftUI + backend FastAPI | 26 | Cliente-servidor, integración con API REST, motor de quiz |
| TappyColor | Juego de emparejar colores en SpriteKit | 30 | Bucle de juego, física, manejo de toques, efectos de partículas |
| Return | Temporizador de meditación zen — iOS 26+, watchOS, tvOS | 63 | HealthKit, Live Activities, runtime extendido en Watch, navegación por foco en TV, sincronización de sesiones con iCloud |
| amp97 | Shaders de Metal + visualización de audio | 41 | Pipeline de renderizado Metal personalizado, análisis de audio, cómputo GPU en tiempo real |
| Reps | Seguimiento de entrenamientos con SwiftUI + SwiftData | 14 | App mínima viable, patrones limpios de SwiftData |
| Water | Seguimiento de hidratación con SwiftUI + SwiftData + Metal + HealthKit | 34 | Simulación de fluidos en Metal, registro de consumo de agua en HealthKit, widget |
| Starfield Destroyer | Juego de naves espaciales en SpriteKit + Metal | 32 | 99 niveles, 8 naves, tablas de clasificación de Game Center, postprocesamiento en Metal |
Por qué importan los conteos de archivos: la efectividad del agente se correlaciona con la legibilidad del proyecto, no con su tamaño. Return (63 archivos) produce mejor salida del agente que amp97 (41 archivos) porque Return tiene un CLAUDE.md detallado con anotaciones de archivos, diagramas de arquitectura y patrones explícitos. Los shaders de Metal de amp97 son intrínsecamente más difíciles de razonar para los agentes, independientemente de la calidad de la documentación.
Requisitos previos
Antes de configurar cualquier runtime de agente para desarrollo iOS:
Fecha límite de App Store Connect: a partir del 2026-04-28, las subidas de apps a App Store Connect deben compilarse con Xcode 26 o posterior usando SDKs para iOS 26, iPadOS 26, tvOS 26, visionOS 26 o watchOS 26.12 (Las subidas de macOS no están sujetas a este requisito.) Si tu equipo sigue en Xcode 16.x, la cadena de herramientas asistida por agentes de esta guía sirve también como mecanismo forzoso: ninguno de los servidores MCP de más abajo funciona sin Xcode 26.3+ de todas formas.
Requerido:
- macOS 15+ (Sequoia) o macOS Tahoe
- Xcode 26.3+ instalado y configurado (el piso de xcrun mcpbridge); se recomienda Xcode 26.4+ para los adjuntos de imágenes en Swift Testing, severidad de incidencias registradas, advertencias de fallos en pruebas UI con crashlogs y mejoras en el editor de String Catalog.13 Xcode 26.4.1 (2026-04-16, build 17E202) es la versión estable más reciente, solo con correcciones de bugs.14
- Al menos un runtime de iOS Simulator instalado
- Una cuenta de Anthropic API (para Claude Code) o cuenta de OpenAI (para Codex)
Recomendado:
- SwiftFormat instalado (brew install swiftformat) — usado por hooks de formato al guardar
- SwiftLint instalado (brew install swiftlint) — opcional, pero útil para imponer estilo
- Familiaridad con la terminal — los tres runtimes operan desde la línea de comandos o se integran con ella
Verifica tu instalación de Xcode:
# Check Xcode version
xcodebuild -version
# Expected: Xcode 26.3 or later (26.4+ recommended)
# Check available simulators
xcrun simctl list devices available
# Expected: at least one iPhone simulator
# Verify xcrun mcpbridge is available
xcrun mcpbridge --help
# Expected: usage information (not "command not found")
Si xcrun mcpbridge devuelve “command not found”, necesitas Xcode 26.3 o posterior. Instala o actualiza Xcode desde la App Store o developer.apple.com. Nota: xcode-select --install solo instala las Command Line Tools, que no incluyen mcpbridge: necesitas el Xcode.app completo.
Tres entornos de ejecución de agentes para iOS
Tres entornos de ejecución distintos pueden escribir, compilar y probar código de iOS. No son intercambiables: cada uno tiene fortalezas diferentes, distintos patrones de integración con MCP y casos de uso ideales diferentes.
1. Claude Code CLI
Qué es: El asistente de codificación agéntico basado en terminal de Anthropic. Lee tu base de código, ejecuta comandos, modifica archivos y se conecta a herramientas externas a través de MCP.
Integración con MCP: Soporte completo tanto para XcodeBuildMCP como para el MCP de Xcode de Apple. El agente descubre las herramientas mediante el protocolo MCP y las invoca con parámetros estructurados. 59 + 20 herramientas entre ambos servidores.
Configuración:
# 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
Alternativa — Instalador automático xcodebuildmcp init (v2.1.0+, 2026-02-23):
Si prefieres saltarte el cableado manual de MCP, XcodeBuildMCP v2.1.0+ incluye un subcomando init que detecta automáticamente Claude Code, Cursor o Codex e instala las skills del agente y la configuración de MCP en un solo paso:
xcodebuildmcp init
# Or without a global install:
npx -y xcodebuildmcp@latest init
Flags: --print (escribe la configuración en stdout para clientes no compatibles), --uninstall (eliminar). Sáltatelo si quieres control explícito sobre qué servidores MCP se conectan y a qué nivel; las invocaciones manuales de claude mcp add mostradas arriba te dan ese control.15
Mejor para: Sesiones profundas de implementación: construir nuevas funciones, refactorizar a través de múltiples archivos, depurar problemas complejos y ejecutar bucles de compilación-prueba-corrección de forma autónoma. La ventana de contexto de 1M de Claude Code (con Opus 4.6) significa que el agente puede mantener en memoria de trabajo la mayoría de proyectos iOS pequeños y medianos: en mi experiencia, hasta unos 50 archivos según su tamaño.
Sesión típica:
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]
La diferencia clave respecto al flujo previo a MCP: el agente nunca te pide compilar manualmente ni pegar la salida de errores. El bucle compilación-error-corrección es autónomo.
2. Codex CLI
Qué es: El agente de codificación basado en terminal de OpenAI. Similar en concepto a Claude Code, pero usa modelos de OpenAI (GPT-4o, o3) y tiene un modelo de permisos diferente.
Integración con MCP: Codex admite MCP mediante el comando codex mcp add. El MCP de Xcode de Apple funciona directamente:
# Add Apple Xcode MCP to Codex
codex mcp add xcode -- xcrun mcpbridge
XcodeBuildMCP también funciona con Codex a través del mismo comando npx:
# Add XcodeBuildMCP to Codex
codex mcp add XcodeBuildMCP -- npx -y xcodebuildmcp@latest mcp
Mejor para: Operaciones por lotes sin interfaz, integración con CI/CD y tareas en las que quieras una segunda opinión de una familia de modelos diferente. El modo sandbox de Codex ejecuta el código en entornos aislados, lo que resulta útil para operaciones destructivas como ejecuciones de suites de pruebas que modifican el estado.
Diferencias clave respecto a Claude Code:
- Usa modelos de OpenAI en lugar de modelos de Claude
- Tamaños de ventana de contexto y economía de tokens diferentes
- Modelo de permisos sandbox-first (más restrictivo por defecto)
- Ecosistema MCP más pequeño (menos servidores comunitarios probados)
- Sistema de hooks disponible (v0.119.0+) pero menos maduro que el de Claude Code: menos tipos de eventos y sin campo condicional if
Cuándo usar Codex en lugar de Claude Code para iOS:
Usa Codex cuando quieras diversidad de modelos: tener un segundo agente que revise el código escrito por el primero detecta diferentes tipos de errores. El flujo de colaboración (Claude construye, Codex revisa) es efectivo para iOS porque los patrones de SwiftUI que parecen correctos a una familia de modelos pueden tener problemas sutiles que otra detecta. Los shaders de Metal y los patrones de concurrencia se benefician especialmente de la revisión con dos modelos.
3. Agentes nativos de Xcode 26.3
Qué es: Apple integró agentes de codificación con IA directamente en el panel Intelligence de Xcode. A partir de Xcode 26.3, puedes configurar Claude Agent y Codex como proveedores de inteligencia en Xcode Settings > Intelligence.
Configuración:
- Abre Xcode 26.3+
- Navega a Settings > Intelligence
- Agrega un nuevo proveedor:
- Para Claude: Selecciona “Claude Agent” e ingresa tu clave de API de Anthropic
- Para Codex: Selecciona “Codex” e ingresa tu clave de API de OpenAI
- El agente aparece en la barra lateral Intelligence y puede invocarse en línea
Mejor para: Ediciones rápidas en línea, autocompletado de código con razonamiento a nivel de agente y desarrolladores que prefieren no salir de Xcode. La integración nativa significa que el agente tiene acceso directo al contexto del proyecto en Xcode —archivos abiertos, destinos de compilación, configuración de esquemas— sin necesidad de un puente MCP.
Limitaciones en comparación con los agentes CLI: - Sin sistema de hooks: no puedes forzar formateo al guardar ni bloquear escrituras en .pbxproj - Sin carga de CLAUDE.md: el agente no lee tus archivos de configuración a nivel de proyecto - Autonomía limitada: el agente opera sobre el archivo o la selección actual, no sobre todo el proyecto - Sin delegación a subagentes: las tareas complejas de varios pasos no pueden paralelizarse - Sin configuración de servidores MCP: el agente solo usa las herramientas integradas de Xcode
Cuándo usar los agentes nativos de Xcode:
Para ediciones rápidas y acotadas donde cambiar a la terminal supone una sobrecarga. “Agrega una propiedad calculada a este modelo.” “Escribe una prueba unitaria para esta función.” “Refactoriza esta vista para que use @Observable.” Tareas que tocan uno o dos archivos y no requieren un ciclo de compilación-prueba.
Para cualquier cosa que requiera compilar, probar, refactorizar entre múltiples archivos o corregir errores de forma autónoma, usa un agente CLI con MCP.
Matriz comparativa de entornos de ejecución
| Capacidad | Claude Code CLI | Codex CLI | Xcode 26.3 nativo |
|---|---|---|---|
| Soporte de MCP | Completo (79 herramientas) | Completo (79 herramientas) | Solo herramientas integradas de Xcode |
| Sistema de hooks | Sí (maduro) | Sí (básico, v0.119.0+) | No |
| CLAUDE.md / configuración del proyecto | Sí | Equivalente codex.md | No |
| Compilación-prueba-corrección autónoma | Sí (vía MCP) | Sí (vía MCP) | Parcial (solo en línea) |
| Delegación a subagentes | Sí (hasta 10 en paralelo) | No | No |
| Ventana de contexto | 1M tokens (Opus 4.6) | Varía según el modelo | Varía según el proveedor |
| Operaciones multi-archivo | Acceso a toda la base de código | Acceso a toda la base de código | Archivo actual / selección |
| Protección de .pbxproj | Mediante hooks | Manual | N/A (usa Xcode de forma nativa) |
| Formateo al guardar | Mediante hooks PostToolUse | Herramientas externas | Configuración de Xcode |
| Capacidad sin conexión | No | No | No |
| Modelo de coste | Uso de API de Anthropic | Uso de API de OpenAI | Uso de API del proveedor |
La recomendación: Usa Claude Code CLI como tu entorno de ejecución principal. Usa los agentes nativos de Xcode 26.3 para ediciones rápidas en línea. Usa Codex CLI para pasadas de revisión y operaciones por lotes. Los tres se complementan en lugar de competir.
Configuración de MCP: La configuración completa
MCP (Model Context Protocol) es lo que transforma a un agente de “escribe Swift y espera que tú lo compiles” a “escribe Swift, lo compila, lee errores estructurados y los corrige.” Esta sección profundiza más que la publicación del blog — cubre ambos servidores, todos los métodos de instalación, la verificación y la configuración del agente que garantiza que las herramientas se utilicen realmente.
XcodeBuildMCP: 59 herramientas para el desarrollo headless de iOS
XcodeBuildMCP envuelve xcodebuild, xcrun simctl y LLDB en 59 herramientas estructuradas de MCP. Funciona sin que Xcode esté en ejecución — todo el ciclo de compilar-probar-depurar opera de forma headless mediante las herramientas de línea de comandos de Apple.
Opciones de instalación:
# 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
La bandera -s user hace que el servidor esté disponible globalmente en todos los proyectos. Omítela para una instalación con alcance de proyecto (útil si solo quieres MCP en proyectos de iOS, no en proyectos web).
La variable de entorno -e XCODEBUILDMCP_SENTRY_DISABLED=true desactiva la telemetría de informes de fallos. XcodeBuildMCP incluye Sentry de forma predeterminada, que envía datos de errores incluyendo rutas de archivos. Desactívala salvo que quieras contribuir con diagnósticos al proyecto.1
Inventario completo de herramientas (59 herramientas en 8 categorías):
| Categoría | Herramientas | Qué hacen |
|---|---|---|
| Descubrimiento de proyectos | discover_projs, list_schemes, list_targets |
Encuentran archivos .xcodeproj/.xcworkspace, listan los esquemas y targets disponibles |
| Compilación | build_sim, build_device, build_mac |
Compilan con salida estructurada de errores/advertencias de JSON por archivo y línea |
| Pruebas | test_sim, test_device |
Ejecutan pruebas con resultados de aprobado/fallado por método |
| Ciclo de vida del simulador | list_sims, boot_sim, shutdown_sim, open_sim, session_set_defaults |
Crean, arrancan, gestionan y configuran simuladores |
| Gestión de dispositivos | list_devices, install_device, launch_device |
Despliegue y gestión de dispositivos reales |
| Depuración | debug_attach_sim, debug_attach_device, debug_breakpoint, debug_stack, debug_variables, debug_eval, debug_continue, debug_step, debug_detach |
Integración completa con LLDB con puntos de interrupción e inspección de variables |
| Automatización de UI | snapshot_ui, screenshot, tap, swipe, type_text |
Interacción automatizada y captura visual |
| Andamiaje de proyectos | create_project, add_file, add_package |
Crean proyectos y añaden dependencias |
Las herramientas que más importan en el trabajo diario:
-
build_sim— La invocarás cientos de veces. Devuelve JSON con errores categorizados por archivo, línea y severidad. El agente lee el error, navega al archivo y lo corrige sin que toques nada. -
test_sim— Devuelve resultados por método de prueba. El agente sabe exactamente qué prueba falló y por qué, no solo que “las pruebas fallaron.” -
list_sims+boot_sim— Gestión de simuladores sin tener que memorizar las banderas dexcrun simctl. El agente descubre los runtimes disponibles y elige un dispositivo apropiado. -
discover_projs+list_schemes— Introspección del proyecto. El agente no necesita adivinar el nombre de tu esquema ni la estructura del workspace. -
debug_attach_sim+debug_stack+debug_variables— Depuración remota con LLDB. El agente puede establecer puntos de interrupción, inspeccionar variables y avanzar paso a paso por el código sin que abras el depurador.
Apple Xcode MCP: 20 herramientas que se conectan a Xcode
El servidor MCP de Apple se distribuye con Xcode 26.3 mediante xcrun mcpbridge. Se comunica con un proceso de Xcode en ejecución a través de XPC (el framework de comunicación entre procesos de Apple), exponiendo el estado interno al que ninguna herramienta de CLI puede acceder.
Instalación:
# Standard installation (global)
claude mcp add --transport stdio xcode \
-s user -- xcrun mcpbridge
# For Codex CLI
codex mcp add xcode -- xcrun mcpbridge
Requiere Xcode 26.3+ y un proceso de Xcode en ejecución. Si Xcode no está abierto, cada llamada de MCP a través de este servidor fallará o se quedará colgada. XcodeBuildMCP no tiene esta limitación.
Inventario de herramientas (20 herramientas en 5 categorías):
| Categoría | Herramientas | Qué hacen |
|---|---|---|
| Operaciones de archivos | XcodeRead, XcodeWrite, XcodeUpdate, XcodeGlob, XcodeGrep |
Leen/escriben archivos dentro del contexto del proyecto Xcode |
| Compilación y pruebas | BuildProject, GetBuildLog, RunAllTests, RunSomeTests |
Compilan y prueban con el sistema de compilación interno de Xcode |
| Diagnósticos | XcodeListNavigatorIssues, XcodeRefreshCodeIssuesInFile |
Diagnósticos de código en tiempo real (no solo errores de compilación) |
| Código y documentación | ExecuteSnippet, DocumentationSearch |
Ejecución de Swift REPL y búsqueda en la documentación de Apple |
| Vistas previas | RenderPreview |
Renderizado headless de previews de SwiftUI |
Herramientas que son exclusivas de Apple MCP (no disponibles en XcodeBuildMCP):
-
DocumentationSearch— Busca en la documentación para desarrolladores de Apple, incluidas las sesiones de la WWDC. Más rápido y fiable que la búsqueda web para preguntas sobre API de Apple. Pregunta “¿es válido HKQuantityType(.dietaryWater)?” y obtén una respuesta definitiva desde la fuente. -
ExecuteSnippet— Ejecución de Swift REPL dentro del contexto del proyecto. El agente puede verificar el comportamiento de API, probar conversiones de tipos y validar expresiones sin compilar la aplicación completa. -
RenderPreview— Renderiza vistas previas de SwiftUI de forma headless. El agente puede comprobar si una vista se renderiza sin errores, aunque no puede evaluar la corrección visual (el renderizado se devuelve como datos, no se inspecciona visualmente). -
XcodeListNavigatorIssues— Devuelve diagnósticos en tiempo real desde el analizador de Xcode, no solo errores de compilación. Detecta problemas como variables no utilizadas, posibles ciclos de retención y advertencias de obsolescencia que el sistema de compilación no expone.
Por qué ambos servidores
Se solapan en compilaciones y pruebas, pero difieren fundamentalmente:
┌─────────────────────────────────────────────────────────────────┐
│ 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 │ │ │ │
│ └─────────────────────┘ └─────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Usa XcodeBuildMCP para: El ciclo de compilar-probar-depurar. Funciona sin tener Xcode abierto, consume menos memoria del sistema y ofrece una gestión más completa de simuladores y dispositivos. Esta es tu herramienta principal de compilación.
Usa Apple Xcode MCP para: Búsquedas en la documentación, verificación con Swift REPL, renderizado de vistas previas de SwiftUI y diagnósticos en tiempo real. Mantén Xcode abierto durante las sesiones que necesiten estas capacidades.
En la práctica: uso XcodeBuildMCP para aproximadamente el 90% de las llamadas de MCP y Apple Xcode MCP para la documentación y la verificación con REPL. El agente recurre por defecto a XcodeBuildMCP para compilaciones y pruebas porque es más rápido (sin la sobrecarga del proceso de Xcode) y más fiable (sin dependencia de XPC).
Verificación
Después de instalar ambos servidores, verifica que están conectados:
# List all configured MCP servers
claude mcp list
# Expected output includes:
# XcodeBuildMCP: npx -y xcodebuildmcp@latest mcp - Connected
# xcode: xcrun mcpbridge - Connected
Si un servidor aparece como “Disconnected” o no aparece:
- XcodeBuildMCP no se conecta: asegúrate de que Node.js está instalado (
node --version). El comandonpxrequiere Node.js 18+. - Apple Xcode MCP no se conecta: asegúrate de que Xcode 26.3+ está instalado y de que el comando
xcrun mcpbridgefunciona en tu terminal. Abre Xcode al menos una vez para aceptar el contrato de licencia. - Ninguno aparece: reinicia Claude Code (
claudeen una terminal nueva). Los servidores de MCP registrados a mitad de sesión pueden no aparecer hasta que reinicies.
Cómo enseñar al agente a usar MCP
Instalar los servidores de MCP es necesario, pero no suficiente. Sin una guía explícita, el agente puede recurrir a ejecutar xcodebuild mediante Bash (salida no estructurada, tokens de contexto desperdiciados) o usar la búsqueda web para la documentación de Apple (más lenta y menos fiable).
Añade esto a tu CLAUDE.md o a la definición del agente:
## Build & Test — Always Use MCP
Prefiere las herramientas de MCP sobre los comandos de shell sin procesar para TODAS las operaciones de compilación:
- **Build**: `build_sim` / `build_device` (NO `xcodebuild` vía Bash)
- **Test**: `test_sim` / `test_device` (NO `xcodebuild test` vía Bash)
- **Simuladores**: `list_sims`, `boot_sim`, `open_sim` (NO `xcrun simctl` vía Bash)
- **Debug**: `debug_attach_sim`, `debug_stack`, `debug_variables`
- **Documentación de Apple**: `DocumentationSearch` (NO WebSearch para APIs de Apple)
- **Verificación de Swift**: `ExecuteSnippet` (NO `swift` vía Bash)
- **Previews**: `RenderPreview` para verificación headless de SwiftUI
MCP devuelve JSON estructurado. Bash devuelve texto sin estructurar.
Los datos estructurados significan menos tokens consumidos y un mejor diagnóstico de errores.
Esta orientación garantiza que el agente recurra primero a las herramientas de MCP. Sin ella, observarás que el agente construye comandos xcodebuild extensos vía Bash, consume miles de tokens de contexto al analizar la salida y, en ocasiones, identifica erróneamente el error real.
Patrones de CLAUDE.md para proyectos iOS
Tu CLAUDE.md es el archivo más importante del proyecto para el desarrollo asistido por agentes. Es el documento de incorporación del agente: la diferencia entre un nuevo empleado que leyó la documentación de arquitectura y otro que está adivinando.
Cada proyecto iOS que mantengo tiene un CLAUDE.md. Estos son los patrones que funcionan, extraídos de las 8 aplicaciones.
Las secciones esenciales
Cada CLAUDE.md de iOS necesita estas seis secciones. Todo lo demás es opcional.
1. Identidad del proyecto
# 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
Por qué importa: el agente necesita conocer el deployment target antes de escribir cualquier código. Un agente que apunta a iOS 17 usará NavigationView y @ObservedObject. Un agente que apunta a iOS 26 usará NavigationStack y @Observable. El bundle ID importa para los entitlements y la configuración de HealthKit. La versión de Swift determina el modelo de concurrencia (async/await vs. completion handlers, strict concurrency vs. lenient).
2. Estructura de archivos con anotaciones de propósito
## 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
```
Los comentarios en línea después del nombre de cada archivo no son decoración. Son la documentación de mayor apalancamiento que puedes escribir. Cuando el agente decide dónde añadir una nueva función, estas anotaciones lo guían al archivo correcto en el primer intento, en lugar de leer cada archivo para entender el diseño del proyecto.
Antipatrón: listar archivos sin anotaciones. TimerManager.swift no le dice nada al agente sobre si gestiona estado, UI o ambos. TimerManager.swift # Timer state, logic, and repeat handling le dice exactamente qué pertenece allí y qué no.
3. Comandos de compilación y prueba
## 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.
Incluye los comandos sin procesar aunque el agente deba preferir MCP. Los comandos sin procesar sirven como documentación de respaldo y hacen explícitos los nombres de los esquemas y los destinos.
4. Patrones y reglas clave
## 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
Estos patrones evitan que el agente introduzca inconsistencias. Sin documentación explícita de patrones, el agente a veces usará ObservableObject en un archivo y @Observable en otro, o creará un nuevo mecanismo de configuración en lugar de usar el singleton existente Settings.shared.
5. Cosas que el agente nunca debe hacer
## 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
Las prohibiciones explícitas son más efectivas que las expectativas implícitas. El agente sigue las restricciones negativas con mayor fiabilidad que las sugerencias positivas porque son binarias (hazlo / no lo hagas) en lugar de heurísticas (prefiere esto / a veces usa aquello).
6. Contexto específico del framework
Esta sección varía según la app. Inclúyela para cualquier framework que tenga configuración no obvia:
Para apps con 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)`
Para apps con 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
Para apps con 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
Para apps con 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 real: Banana List (SwiftUI + SwiftData + iCloud + servidor MCP)
Aquí tienes un ejemplo anotado que muestra cómo las seis secciones funcionan en conjunto para una app moderadamente compleja. Este es el patrón de CLAUDE.md que uso para Banana List, una app de listas de la compra de 53 archivos con sincronización por iCloud y un servidor MCP personalizado que expone los datos de la app a Claude Desktop:
# Banana List - Grocery List App
**Bundle ID:** `com.941apps.BananaList`
**Target:** iOS 26+
**Architecture:** SwiftUI + SwiftData + iCloud Drive sync
**Swift version:** 6.2
**Minimum deployment:** iOS 26.0
## Core Features
- Grocery lists with items, categories, and quantities
- iCloud Drive sync via SwiftData CloudKit integration
- Custom MCP server exposing list data to Claude Desktop
- Liquid Glass design system
- Haptic feedback on interactions
- Share sheets for list sharing
## Estructura de archivos
```
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
```
## Modelos SwiftData
### Relaciones
- `GroceryList` tiene muchos `GroceryItem` (eliminación en cascada)
- `GroceryItem` pertenece a un `GroceryList` (obligatorio)
- `GroceryItem` tiene un `Category` opcional
- `Category` tiene muchos `GroceryItem` (anular al eliminar)
### Configuración del contenedor
```swift
@main
struct BananaListApp: App {
var body: some Scene {
WindowGroup {
ListsView()
}
.modelContainer(for: [GroceryList.self, GroceryItem.self, Category.self])
}
}
```
### Patrones de consulta
- Listas: `@Query(sort: \GroceryList.name) var lists: [GroceryList]`
- Elementos activos: `@Query(filter: #Predicate { !$0.isCompleted })`
- Por categoría: filtra en memoria después de obtener los datos (limitaciones de los predicados de SwiftData)
## Compilación y pruebas
```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
```
Prefiere las herramientas de MCP (`build_sim`, `test_sim`) en lugar de comandos sin procesar.
## Patrones clave
### Observable + SwiftData
- Las clases `@Model` de SwiftData son automáticamente Observable
- NO agregues `@Observable` a las clases `@Model` (es redundante y genera advertencias)
- Usa `@Bindable` para enlaces bidireccionales a las propiedades del modelo en formularios
- Usa `@Query` en las vistas y `modelContext.fetch()` en código que no sea de vistas
### Sincronización con iCloud
- Automática mediante la integración de SwiftData con CloudKit
- Resolución de conflictos: gana la última escritura (predeterminado de CloudKit)
- El estado de sincronización se expone a través de `CloudSyncManager.shared.syncState`
- Prueba la sincronización ejecutando en dos simuladores con la misma cuenta de iCloud
### Arquitectura del servidor MCP
- Se ejecuta como servidor WebSocket local en el puerto 8765
- Expone 6 herramientas: listAll, getList, createList, addItem, completeItem, deleteItem
- Claude Desktop se conecta mediante la configuración de MCP en `~/.config/claude-desktop/config.json`
## Reglas
- NUNCA modifiques el contenido de .pbxproj o .xcodeproj
- NUNCA cambies el esquema del modelo sin actualizar SampleData.swift
- NUNCA uses `ObservableObject` — los modelos de SwiftData ya son Observable
- NUNCA uses `@StateObject` — usa `@State` con clases `@Observable`
- NUNCA uses `NavigationView` — siempre `NavigationStack`
- NUNCA agregues el macro `@Observable` a las clases `@Model`
- SIEMPRE usa `@Bindable` para enlaces de formularios a propiedades del modelo
- SIEMPRE prueba los cambios de sincronización con iCloud en dos instancias de simulador
CLAUDE.md real: Reps (App SwiftData mínima — 14 archivos)
Para proyectos pequeños, el CLAUDE.md puede ser conciso. Aquí está el patrón para Reps, un rastreador de entrenamientos de 14 archivos. Observa cómo incluso un CLAUDE.md corto cubre las seis secciones esenciales:
# 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
Son 40 líneas de CLAUDE.md para un proyecto de 14 archivos. Toma 10 minutos escribirlo y ahorra horas de confusión del agente.
CLAUDE.md real: Starfield Destroyer (SpriteKit + Metal — 32 archivos)
Los proyectos de juegos requieren más contexto específico del framework. El agente necesita comprender el grafo de la escena, las categorías de física y la máquina de estados del juego:
# 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
```
## Jerarquía de la escena de SpriteKit
```
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)
```
## Categorías de física
```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
```
## Máquina de estados del juego
```
.menu → .playing → .paused → .playing
→ .gameOver → .menu
→ .bossIntro → .playing
→ .levelComplete → .playing (next level)
```
## Posprocesamiento con Metal
- Shader de bloom: `BloomShader.metal` — desenfoque gaussiano multipase + mezcla aditiva
- Uniformes: `PostProcessUniforms { float intensity; float threshold; float2 resolution; }`
- Se aplica después de que SpriteKit renderiza cada frame mediante `SKView.presentScene(:transition:)`
- NO modifiques los shaders de Metal sin probarlos en un dispositivo
## Compilación y pruebas
```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
## Reglas
- NUNCA modifiques .pbxproj
- NUNCA modifiques las máscaras de bits de PhysicsCategory (rompe toda la detección de colisiones)
- NUNCA cambies el orden z de la jerarquía de la escena sin entender el orden de renderizado
- NUNCA modifiques ShaderTypes.h sin actualizar las referencias tanto de Swift como de Metal
- Agrega nuevos enemigos creando subclases de EnemyShip, no modificándolo
- Pooling de balas: recicla mediante removeFromParent() + re-add, nunca asignes nuevas
- Game Center: siempre verifica isAuthenticated antes de enviar puntuaciones
CLAUDE.md real: amp97 (Metal + visualización de audio — 41 archivos)
Los proyectos en Metal necesitan el contexto más específico del framework porque los agentes no pueden verificar la salida visual:
# amp97 - Visualizador de audio
**Bundle ID:** `com.941apps.amp97`
**Target:** iOS 26+
**Arquitectura:** Pipeline de renderizado Metal + análisis con AVAudioEngine
**Versión de Swift:** 6.2
## Arquitectura
```
Entrada de audio (micrófono/archivo)
→ Tap de AVAudioEngine
→ FFT (vDSP)
→ Buffers de frecuencia/amplitud
→ Compute shader de Metal (análisis)
→ Pipeline de renderizado Metal (visualización)
→ CADisplayLink (60fps)
→ MTKView
```
## Estructura de archivos
```
amp97/
├── amp97App.swift # Entrada de la app
├── Audio/
│ ├── AudioEngine.swift # Configuración de AVAudioEngine, instalación del tap
│ ├── FFTProcessor.swift # FFT con vDSP, extracción de bins de frecuencia
│ ├── AudioBuffer.swift # Ring buffer para datos de audio
│ └── MicrophoneManager.swift # Permiso de micrófono, configuración de sesión
├── Rendering/
│ ├── MetalView.swift # Wrapper de MTKView para SwiftUI
│ ├── Renderer.swift # Loop principal de renderizado, estado del pipeline
│ ├── ShaderLibrary.swift # Gestión de shaders compilados
│ ├── BufferManager.swift # Actualizaciones de uniforms con triple buffer
│ └── TextureManager.swift # Render targets fuera de pantalla
├── Shaders/
│ ├── Shaders.metal # Vertex + fragment shaders
│ ├── AudioCompute.metal # Kernel de cómputo para análisis de audio
│ ├── PostProcess.metal # Bloom, color grading
│ └── ShaderTypes.h # Uniforms compartidos (bridging header)
├── Visualizations/
│ ├── WaveformViz.swift # Forma de onda estilo osciloscopio
│ ├── SpectrumViz.swift # Barras de espectro de frecuencia
│ ├── CircularViz.swift # Visualización radial
│ └── VizSelector.swift # Cambio entre visualizaciones
├── Views/
│ ├── MainView.swift # Visualización a pantalla completa con overlays
│ ├── ControlsOverlay.swift # Play/pausa, selección de viz, ganancia
│ └── SettingsView.swift # Fuente de audio, sensibilidad
└── Extensions/
├── SIMD+Extensions.swift # Helpers de matemática vectorial
└── Color+Metal.swift # Conversión UIColor → float4
```
## Pipeline de Metal
### Uniforms (ShaderTypes.h)
```c
typedef struct {
float time;
float2 resolution;
float audioLevel; // Amplitud RMS de 0,0-1,0
float frequencyBins[64]; // Salida de FFT, normalizada
float4x4 transform;
} Uniforms;
```
### Pipeline de renderizado
1. Pase de cómputo: AudioCompute.metal procesa los datos de FFT → textura
2. Pase de renderizado: Shaders.metal lee la textura + uniforms → visualización
3. Pase de post-procesado: PostProcess.metal aplica bloom → salida final
### Gestión de buffers
- Triple buffering con DispatchSemaphore(value: 3)
- Uniforms actualizados por frame en la CPU, consumidos por GPU 1-2 frames después
- Ring buffer de datos de audio: 4096 muestras, lock-free con un solo productor/consumidor
## Reglas
- NUNCA modifiques ShaderTypes.h sin actualizar AMBOS lados, Swift y Metal
- NUNCA excedas los 64 bins de frecuencia (tamaño de buffer fijo en el shader)
- NUNCA pruebes la salida visual de Metal en el simulador — solo en dispositivo
- NUNCA modifiques el formato del tap del audio engine (48kHz, mono, float32)
- Disciplina de triple buffer: siempre haz signal del semáforo en el completion handler
- Sesión de audio: categoría .playAndRecord con la opción .defaultToSpeaker
Escalando CLAUDE.md según el tamaño del proyecto
El nivel de detalle adecuado depende de la cantidad de archivos y de la complejidad del framework:
| Tamaño del proyecto | Profundidad de CLAUDE.md | Ejemplo |
|---|---|---|
| Pequeño (< 20 archivos) | Identidad + lista de archivos + reglas | Reps (14 archivos): patrones básicos de SwiftData, comandos de build, prohibiciones |
| Mediano (20-40 archivos) | + Contexto del framework + patrones clave | TappyColor (30 archivos): jerarquía de escenas de SpriteKit, categorías de física, game loop |
| Grande (40+ archivos) | + Diagramas de arquitectura + mapas de relaciones + información multi-target | Return (63 archivos): arquitectura multiplataforma, diagrama de sincronización de sesión, diferencias por plataforma |
| Especializado (Metal/GPU) | + Diagramas de pipeline + definiciones de tipos compartidos + layouts de buffer | amp97 (41 archivos): etapas del pipeline de renderizado, struct de uniforms, gestión de buffers |
El costo de sobre-documentar es prácticamente cero (el agente omite lo que no necesita). El costo de sub-documentar es alto (el agente inventa patrones que entran en conflicto con tu base de código).
Checklist de CLAUDE.md
Usa este checklist al crear o auditar un CLAUDE.md para un proyecto iOS:
- [ ] Bundle ID y deployment target especificados
- [ ] Versión de Swift y patrón de arquitectura nombrados
- [ ] Estructura de archivos con anotaciones de propósito en línea
- [ ] Comando de build con scheme y destino correctos
- [ ] Comando de test con scheme y destino correctos
- [ ] Preferencia de MCP documentada (“preferir build_sim sobre xcodebuild”)
- [ ] Regla de @Observable (nunca ObservableObject)
- [ ] Regla de NavigationStack (nunca NavigationView)
- [ ] Prohibición de .pbxproj
- [ ] Contexto específico del framework (permisos de HealthKit, relaciones de SwiftData, jerarquía de SpriteKit, pipeline de Metal)
- [ ] Guards de disponibilidad de plataforma documentados (#if canImport, #if os)
- [ ] Singletons clave y patrones compartidos documentados
- [ ] Limitaciones conocidas o gotchas señalados
Tu primera sesión con un agente
Con MCP configurado y un CLAUDE.md en tu proyecto, aquí tienes un recorrido de una primera sesión efectiva. Esto usa Claude Code CLI, pero el flujo de trabajo aplica a cualquier runtime.
Paso 1: Verifica que el agente puede ver tu proyecto
Tú: Resume este proyecto. ¿Con qué scheme debería hacer build?
Claude: [lee CLAUDE.md]
[llama a discover_projs vía MCP]
[llama a list_schemes vía MCP]
Este es Return, un temporizador zen de meditación para iOS 26+, watchOS y tvOS.
Schemes disponibles: Return, ReturnWatch, ReturnTV, ReturnTests.
Scheme principal para iOS: Return.
Si el agente no hace referencia al contenido de tu CLAUDE.md, verifica que el archivo esté en la raíz del proyecto (mismo directorio que .xcodeproj o Package.swift).
Paso 2: Ejecuta un build de health check
Tú: Haz build del scheme Return para el simulador de iOS y reporta los resultados.
Claude: [llama a list_sims — encuentra iPhone 16 Pro en iOS 26.2]
[llama a boot_sim — arranca el simulador]
[llama a build_sim — hace build del proyecto]
Build exitoso. 63 archivos fuente compilados.
2 advertencias:
- HomeView.swift:132 — UIScreen.main deprecated en iOS 26.0
- LogWaterIntent.swift:61 — Resultado de try? sin usar
0 errores.
Paso 3: Ejecuta los tests
Tú: Ejecuta todos los tests y reporta pasados/fallidos.
Claude: [llama a test_sim]
12 tests ejecutados:
✓ TimerManagerTests (5/5 pasados)
✓ SettingsTests (4/4 pasados)
✓ ConstantsTests (3/3 pasados)
Todos los tests pasaron.
Paso 4: Implementa una función
Tú: Agrega un nuevo tema "Rain" (Lluvia) al sistema de temas. Sigue el patrón
existente en Theme.swift y ThemeManager.swift. Incluye un sonido
ambiente de lluvia. Haz build y ejecuta tests después de implementarlo.
Claude: [lee Theme.swift — entiende el patrón de struct Theme]
[lee ThemeManager.swift — entiende el registro de temas]
[lee las definiciones de temas existentes]
[agrega el tema Rain a Theme.swift siguiendo el patrón existente]
[registra el tema Rain en ThemeManager.swift]
[llama a build_sim — build exitoso]
[llama a test_sim — todos los tests pasan]
Tema Rain agregado:
- Theme.swift: nuevo `static let rain` con video, cover, ambient
- ThemeManager.swift: agregado al array `allThemes`
- Build: éxito (0 errores, 2 advertencias existentes)
- Tests: 12/12 pasados
Nota: Necesitarás agregar rain_ambient.wav al proyecto
y añadir manualmente los nuevos cambios de Theme.swift al target de Xcode
(no modifiqué .pbxproj).
La nota del agente sobre no modificar .pbxproj es resultado de las reglas en CLAUDE.md. Sin esa regla, el agente intentaría modificar el archivo del proyecto y probablemente lo corrompería.
Lo que los agentes hacen bien en iOS
Estas son las tareas en las que los agentes producen de forma consistente resultados correctos y listos para producción con una revisión humana mínima.
Vistas y modificadores de SwiftUI
Los agentes tienen un profundo reconocimiento de patrones para la sintaxis declarativa de SwiftUI. Composición de vistas, cadenas de modificadores, vinculaciones de estado y diseño: todo esto se mapea bien con los datos de entrenamiento del agente porque la superficie de API de SwiftUI está bien documentada y los patrones son altamente consistentes.
Donde los agentes destacan:
- Construir nuevas vistas a partir de una descripción (“crea una hoja de configuración con interruptores para X, Y, Z”)
- Aplicar cadenas de modificadores (.glassEffect(), .sensoryFeedback(), .navigationTitle())
- Convertir entre patrones de diseño (VStack a LazyVGrid, List a ScrollView)
- Implementar vinculaciones de formulario @Bindable a modelos de SwiftData
- Construir proveedores de vista previa con datos de muestra
Ejemplo de prompt que produce excelentes resultados:
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.
La especificidad importa. “Crea una vista de configuración” produce un resultado genérico. “Crea una SettingsView que coincida con el patrón existente en SettingsSheet.swift” produce un resultado consistente con tu base de código.
Modelos y consultas de SwiftData
Los agentes manejan de forma confiable el macro @Model de SwiftData, las relaciones y los patrones de @Query. La naturaleza declarativa del framework (similar a Django ORM o SQLAlchemy) se mapea bien con patrones que el agente ha visto en muchas bases de código.
Donde los agentes destacan:
- Definir clases @Model con relaciones
- Escribir @Query con descriptores de ordenamiento y predicados
- Implementar operaciones CRUD mediante modelContext
- Planes de migración entre versiones de esquema
- Datos de vista previa y fixtures de pruebas
Donde los agentes necesitan orientación:
- Expresiones complejas de #Predicate (el DSL de predicados de SwiftData tiene limitaciones que el agente no siempre conoce: documenta las limitaciones conocidas en CLAUDE.md)
- Configuración de sincronización con CloudKit (automática mediante SwiftData, pero el agente puede intentar implementar sincronización manual)
Pruebas unitarias
Las pruebas unitarias escritas por agentes son consistentemente de alta calidad para proyectos iOS. El agente comprende los patrones de XCTest, los métodos de prueba async y el ciclo de vida setup/teardown.
Write unit tests for TimerManager covering:
1. Initial state is .stopped
2. start() transitions to .running
3. pause() transitions to .paused
4. reset() returns to .stopped with original duration
5. Timer counts down correctly (test with 3-second duration)
El agente produce casos XCTest bien estructurados con setUp() y tearDown(), aserciones apropiadas y manejo async para pruebas basadas en temporizadores.
Refactorización y aplicación de patrones
Los agentes destacan en la refactorización mecánica: extraer vistas en componentes, convertir ObservableObject a @Observable, migrar de NavigationView a NavigationStack y aplicar patrones consistentes en múltiples archivos.
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.
El agente trabaja metódicamente a través de cada archivo, aplica la transformación correctamente y mantiene la funcionalidad existente. Este es un trabajo de alto impacto: una refactorización que tomaría una hora de edición manual se completa en minutos con una precisión casi perfecta.
Diagnóstico de errores de compilación mediante MCP
Con la salida estructurada de MCP, los agentes diagnostican errores de compilación más rápido que la mayoría de los desarrolladores. El agente lee el JSON del error, identifica el archivo y la línea exactos, comprende el mensaje de error y aplica la corrección, a menudo en un solo turno.
Errores que los agentes corrigen de forma autónoma: - Importaciones faltantes - Discordancias de tipos - Brechas en la conformidad de protocolos - Uso de API obsoletas (con reemplazo) - Parámetros de inicializador requeridos faltantes - Violaciones de control de acceso
Errores con los que los agentes necesitan ayuda: - Resolución ambigua de tipos (múltiples módulos definen el mismo tipo) - Fallas complejas de restricciones genéricas - Errores de expansión de macros (el agente no puede ver la salida expandida del macro)
Gestión de simuladores
Los agentes manejan bien el ciclo de vida del simulador mediante MCP:
Boot an iPhone 16 Pro simulator on iOS 26, install the app, and take a screenshot.
El agente llama a list_sims para encontrar los runtimes disponibles, boot_sim para iniciar el simulador, build_sim para compilar e instalar, y screenshot para capturar, todo mediante llamadas estructuradas a MCP.
Lo que los agentes hacen mal en iOS
Recuento honesto de dónde fallan los agentes. Conocer estos límites previene la frustración y el desperdicio de tokens.
Modificaciones de archivos .pbxproj — NUNCA
Esta es la regla más importante en el desarrollo de agentes para iOS. El archivo .pbxproj es la configuración del proyecto de Xcode — un archivo de texto estructurado con referencias UUID, listados de fases de compilación y pertenencia a targets. Es nominalmente legible para humanos pero en la práctica imposible de analizar para los agentes de IA.
Por qué los agentes fallan con .pbxproj: - El archivo usa un formato personalizado (no JSON, no YAML, no XML) con significado posicional - Cada entrada está referenciada de forma cruzada por UUID — agregar un archivo requiere actualizar 3-5 secciones diferentes de manera consistente - Un solo carácter mal colocado corrompe todo el archivo del proyecto - La resolución de conflictos de fusión de Xcode para .pbxproj ya es frágil — las ediciones del agente la empeoran
Qué sucede cuando un agente edita .pbxproj: 1. La edición parece tener éxito (el agente reporta “archivo actualizado”) 2. Xcode se niega a abrir el proyecto (“El archivo del proyecto está corrupto”) 3. Pasas entre 15 y 60 minutos recuperándote desde el historial de git 4. Aprendes a agregar el hook PreToolUse (consulta Hooks)
El flujo de trabajo: El agente crea archivos Swift. Tú los agregas al proyecto de Xcode manualmente (arrastrándolos a Xcode, o File > Add Files). Esto toma 5 segundos por archivo y previene horas de recuperación.
Para proyectos de Swift Package Manager: Esta limitación es menos severa. Package.swift es un archivo Swift estándar que los agentes pueden editar de forma fiable. Si tu proyecto usa SPM exclusivamente (sin .xcodeproj), el agente puede gestionar toda la estructura del proyecto.
Ediciones complejas de Interface Builder / Storyboard
Si tu proyecto usa Interface Builder (archivos .xib) o Storyboards (archivos .storyboard), los agentes no pueden editarlos de forma significativa. Estos son archivos XML con UUIDs autogenerados, referencias de restricciones y conexiones de outlets que están diseñadas para edición visual, no edición de texto.
La mitigación: Usa SwiftUI exclusivamente para vistas nuevas. Si tu proyecto tiene archivos heredados de Interface Builder, déjalos en paz y construye la nueva UI en SwiftUI.
Optimización de rendimiento
Los agentes escriben código correcto pero no necesariamente código eficiente. No pueden perfilar tu aplicación, identificar cuellos de botella ni medir tasas de fotogramas. La optimización de rendimiento requiere:
- Profiling con Instruments (herramienta visual, no accesible para agentes)
- Comprensión de las características específicas de GPU/CPU del dispositivo
- Cambios iterativos guiados por mediciones
Dónde aparece esto: - Optimización de shaders Metal (el agente escribe Metal válido pero no puede medir el tiempo de fotograma de la GPU) - Complejidad del body de vistas SwiftUI (el agente crea vistas profundamente anidadas que causan sobrecarga de redibujado) - Optimización de fetch de Core Data / SwiftData (el agente escribe consultas correctas que pueden ser lentas en conjuntos de datos grandes)
La mitigación: Usa agentes para la implementación, perfila manualmente con Instruments, luego pídele al agente que aplique optimizaciones específicas que hayas identificado.
Code signing y provisioning
Los agentes no pueden depurar problemas de code signing más allá de leer el mensaje de error. La gestión de perfiles de provisioning, la creación de certificados, la configuración de entitlements y el envío a la App Store son flujos de trabajo fundamentalmente operados por humanos que involucran el portal de Apple Developer, Keychain Access y la UI de signing de Xcode.
Lo que ve el agente: “Signing for ‘Return’ requires a development team.”
Lo que el agente no puede ver: Si tu certificado expiró, si el perfil de provisioning incluye el dispositivo, si el bundle ID coincide con el App ID o si tu archivo de entitlements es correcto.
La mitigación: Maneja todo el signing en la pestaña Signing & Capabilities de Xcode. No le pidas a los agentes que depuren fallos de signing.
Depuración compleja de shaders Metal
Los agentes escriben Metal Shading Language (MSL) sintácticamente correcto pero no pueden verificar la salida visual ni depurar problemas del lado de la GPU. Los shaders Metal se ejecutan en la GPU — el agente no tiene mecanismo de retroalimentación para saber si el shader produce resultados visuales correctos.
Lo que los agentes pueden hacer con Metal:
- Escribir shaders de vértices y fragmentos a partir de descripciones
- Configurar el render pipeline de Metal en Swift
- Crear compute shaders para operaciones paralelas de datos
- Corregir errores de compilación en archivos .metal
Lo que los agentes no pueden hacer con Metal: - Verificar la corrección visual de la salida del shader - Depurar el rendimiento de la GPU (tiempo de fotograma, occupancy, ancho de banda de memoria) - Diagnosticar artefactos visuales (banding, problemas de precisión, espacio de color incorrecto) - Probar en diferentes arquitecturas de GPU (diferencias de comportamiento entre serie A y serie M)
La mitigación: Prueba los shaders Metal en dispositivos físicos. La implementación de Metal del Simulator no es representativa del comportamiento de la GPU del dispositivo. Usa GPU Frame Capture de Xcode para depuración visual.
Verificación de layout visual
Los agentes no pueden ver la UI de tu aplicación. Escriben código de layout SwiftUI y pueden verificar que compile, pero no pueden saber si la pantalla resultante se ve correctamente. Una vista que se renderiza 10 píxeles descentrada, usa el peso de fuente equivocado o tiene elementos superpuestos no produce ningún error de compilación y pasa todas las pruebas de lógica.
La mitigación: Revisa los cambios de UI visualmente. Usa SwiftUI Previews en Xcode (o RenderPreview mediante Apple MCP para renderizado headless) para verificar el layout. Considera snapshot testing con bibliotecas como swift-snapshot-testing para detección automatizada de regresiones visuales.
Hooks para desarrollo en iOS
Los hooks son comandos de shell que se ejecutan de forma determinista en momentos específicos del flujo de trabajo del agente. Son el mecanismo de aplicación: la diferencia entre “por favor no edites .pbxproj” (una sugerencia que el agente puede ignorar) y “no puedes editar .pbxproj” (un bloqueo absoluto).
Para conocer los fundamentos del sistema de hooks, consulta la guía de hooks de Claude Code. Esta sección cubre patrones de hooks específicos para iOS.
PreToolUse: bloquear escrituras en .pbxproj
El hook más importante en cualquier proyecto iOS. Impide que el agente escriba en archivos .pbxproj, directorios .xcodeproj/ y otros archivos gestionados por 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'"
}
]
}
}
Coloca esto en .claude/settings.json en la raíz del proyecto o en ~/.claude/settings.json para protección global.
Cómo funciona: cuando el agente intenta usar la herramienta Edit o Write en cualquier archivo que coincida con el patrón, el hook se ejecuta, detecta la ruta del archivo, imprime una advertencia en stderr y sale con código 2 (lo que bloquea el uso de la herramienta). El agente recibe el mensaje de error y ajusta su enfoque.
Qué detecta:
- Ediciones directas de .pbxproj
- Cualquier archivo dentro de los directorios .xcodeproj/ o .xcworkspace/
- Archivos de Interface Builder (.xib, .storyboard)
PostToolUse: formatear al guardar con SwiftFormat
Formatea automáticamente los archivos Swift cada vez que el agente los escribe o los edita:
{
"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'"
}
]
}
}
Requisitos: SwiftFormat debe estar instalado (brew install swiftformat).
Por qué importa: los agentes producen Swift sintácticamente correcto, pero no siguen las convenciones de formato de manera consistente. SwiftFormat normaliza la indentación, la colocación de llaves y el orden de los imports. El hook de formatear al guardar significa que cada archivo Swift que el agente toca se formatea automáticamente antes de que lo veas.
Opcional: agrega un archivo de configuración .swiftformat en la raíz del proyecto para personalizar las reglas de formato:
# .swiftformat
--indent 4
--allman false
--stripunusedargs closure-only
--importgrouping testable-bottom
--header strip
PostToolUse: ejecutar SwiftLint automáticamente
Si usas SwiftLint, ejecútalo después de cada edición de un archivo 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'"
}
]
}
}
El || true evita que las advertencias del linter bloqueen al agente. Si quieres que las violaciones de lint bloqueen, elimínalo.
PostToolUse: compilación automática tras cambios
Para ciclos de retroalimentación agresivos, dispara una compilación después de cada cambio en un archivo 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'"
}
]
}
}
Advertencia: esto es costoso. Cada edición de archivo dispara una compilación. Úsalo con moderación: es más útil durante sesiones de depuración en las que quieres retroalimentación inmediata de la compilación. Para el desarrollo normal, deja que el agente dispare las compilaciones manualmente mediante MCP cuando esté listo.
PreToolUse: bloquear modificaciones de entitlements
Protege tu archivo de entitlements de modificaciones accidentales del agente:
{
"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'"
}
]
}
}
Configuración combinada de hooks para iOS
Este es el .claude/settings.json completo que uso en todos mis proyectos iOS:
{
"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'"
}
]
}
}
Esto te ofrece dos garantías: 1. El agente no puede corromper los archivos del proyecto Xcode (bloqueo PreToolUse) 2. Cada archivo Swift que toca el agente se formatea automáticamente (formato PostToolUse)
Patrones de Arquitectura que Funcionan con Agentes
No todas las arquitecturas de Swift son igualmente compatibles con agentes. Estos patrones producen los mejores resultados porque son explícitos, consistentes y están bien representados en los datos de entrenamiento.
@Observable (Nunca ObservableObject)
Los proyectos con destino iOS 26+ deben usar @Observable exclusivamente. Este es a la vez el patrón moderno y el patrón compatible con agentes:
// 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()
}
Por qué @Observable es compatible con agentes: el patrón es más simple (no se necesitan anotaciones @Published), el modelo de propiedad es más claro (@State en lugar de @StateObject vs. @ObservedObject), y los agentes producen menos errores con él porque hay menos partes móviles.
Documenta esto en CLAUDE.md: incluso con iOS 26 como destino, los agentes ocasionalmente vuelven a los patrones de ObservableObject provenientes de sus datos de entrenamiento. Una prohibición explícita lo evita.
NavigationStack (Nunca NavigationView)
// 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 es de iOS 16+ y el único patrón de navegación que deberías usar para código nuevo. El patrón con seguridad de tipos navigationDestination(for:) impide que el agente cree enlaces de navegación incorrectos.
SwiftData para Persistencia
Los modelos de SwiftData son el patrón de persistencia más limpio para el desarrollo asistido por agentes:
@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
}
}
Reglas clave para agentes que trabajan con SwiftData:
1. Las clases @Model son automáticamente Observable — no agregues @Observable
2. Usa @Bindable para los bindings de formularios: @Bindable var item: GroceryItem
3. Usa @Query en las vistas para datos reactivos: @Query var items: [GroceryItem]
4. Usa modelContext.fetch() en código que no sea de vista
5. Las eliminaciones de relaciones necesitan reglas explícitas: .cascade, .nullify, .deny
Concurrencia en Swift 6.2
Apunta a la concurrencia estricta de Swift 6.2 para los proyectos nuevos:
// 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
}
Orientación para agentes sobre concurrencia:
- Marca todos los view models como @MainActor (evita advertencias de carreras de datos)
- Usa async/await para todo el trabajo asíncrono (sin completion handlers)
- Haz que los tipos por valor sean Sendable para las transferencias entre actores
- Usa Task { } en las vistas para la inicialización asíncrona
- Usa nonisolated solo cuando hayas medido una necesidad de rendimiento
Sistema de Diseño Liquid Glass (iOS 26+)
iOS 26 introdujo el sistema de diseño Liquid Glass. Los agentes lo manejan bien cuando reciben orientación explícita:
// 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()
Inclúyelo en CLAUDE.md: “Usa .glassEffect() en los fondos de sección y los contenedores tipo tarjeta. Las barras de navegación adoptan automáticamente el material glass en iOS 26. No recrees manualmente los efectos glass con materiales personalizados — usa el modificador del sistema”.
Contexto Específico por Framework
Cada framework de Apple tiene consideraciones específicas para los agentes. Esta sección cubre los frameworks usados en las 8 apps.
HealthKit
Apps que lo usan: Return, Water
HealthKit requiere un manejo cuidadoso de los permisos y guardas de plataforma:
// 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
}
}
}
Reglas para agentes con HealthKit:
- Siempre protege con HKHealthStore.isHealthDataAvailable()
- Nunca asumas la autorización — verifícala en cada escritura
- Usa #if canImport(HealthKit) para código multiplataforma (HealthKit no está disponible en tvOS)
- Nunca almacenes datos de salud localmente más allá de lo que HealthKit proporciona
- Incluye tanto NSHealthShareUsageDescription como NSHealthUpdateUsageDescription en Info.plist
SpriteKit
Apps que lo usan: TappyColor, Starfield Destroyer
El modelo de grafo de escena de SpriteKit requiere orientación explícita para los agentes:
## 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)
Fortalezas de los agentes con SpriteKit: - Crear secuencias y grupos de SKAction - Configurar cuerpos físicos y detección de contactos - Implementar máquinas de estado de juego - Construir overlays de HUD
Debilidades de los agentes con SpriteKit: - Bucles de juego sensibles al rendimiento (el agente añade trabajo innecesario por cada frame) - Simulaciones físicas complejas (la física personalizada supera a SKPhysicsBody en precisión) - Ajuste fino de efectos de partículas (visual, requiere iteración)
Metal
Apps que lo usan: amp97, Water, Starfield Destroyer
Metal es el framework donde más sufren los agentes. El modelo de programación de GPU es fundamentalmente diferente del Swift en CPU, y los agentes no pueden verificar la salida visual.
## 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
Qué incluir en CLAUDE.md para los proyectos de Metal: - La definición del struct Uniforms (compartido entre Swift y MSL) - El patrón de configuración del estado del pipeline de renderizado - Los índices de los buffers y sus propósitos - Qué shaders existen y qué hace cada uno - Problemas conocidos de precisión (half vs. float)
Live Activities
Apps que lo usan: Return
Las Live Activities requieren una configuración específica que los agentes manejan bien una vez documentada:
## 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
Apps que lo usan: 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)
Patrones multiplataforma
Return abarca iOS, watchOS y tvOS. El desarrollo multiplataforma con agentes requiere documentación explícita de los límites entre plataformas.
Organización de código compartido
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
Regla para los agentes: “Si un archivo está en Shared/, los cambios afectan a todas las plataformas. Si un archivo está en una carpeta específica de plataforma, los cambios quedan aislados. Verifica siempre en qué carpeta se encuentra un archivo antes de modificarlo.”
Guardas de disponibilidad por plataforma
// 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
Guía para el agente: “Usa siempre guardas #if canImport() o #if os() cuando emplees frameworks específicos de una plataforma. No asumas que un framework está disponible en todos los targets.”
Adaptación de UI por plataforma
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
}
}
Flujos de trabajo avanzados
Bucles autónomos de build-test-fix
El patrón más poderoso: dale al agente una especificación de funcionalidad y deja que itere por ciclos de build-test-fix de forma autónoma.
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.
El agente escribe código, hace el build mediante MCP, lee los errores estructurados, los corrige y repite. Una funcionalidad que requeriría entre 5 y 10 ciclos humanos de build-error-fix se completa en un único bucle autónomo.
Cuándo funciona: funciones bien definidas con criterios de aceptación claros.
Cuándo se rompe: funciones abiertas (“haz que se vea bonito”), código sensible al rendimiento, o cualquier cosa que requiera verificación visual.
Delegación a subagentes para iOS
El sistema de subagentes de Claude Code funciona en proyectos de 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.
El subagente explora documentación y patrones de código en una ventana de contexto separada, devuelve un resumen, y la sesión principal implementa la recomendación. Esto evita que la investigación consuma tu contexto principal.
Aplicación de patrones entre apps
Cuando mantienes varias apps de iOS con patrones consistentes, los agentes pueden aplicar patrones de una app a otra:
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.
El agente lee el patrón fuente, comprende la estructura y crea una implementación consistente en el proyecto destino.
Revisión con doble agente (Claude + Codex)
Para cambios críticos, usa dos agentes de familias de modelos distintas:
- Claude Code escribe la implementación
- Codex CLI la revisa en una pasada separada
# 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."
Distintas familias de modelos detectan distintas clases de errores. Esto es especialmente valioso en Metal shaders y patrones de concurrencia, donde los bugs sutiles son fáciles de introducir.
Lo que detecta la revisión doble y se le escapa a la revisión única:
| Tipo de problema | Fortaleza de Claude | Fortaleza de Codex |
|---|---|---|
| Ciclos de relaciones en SwiftData | Moderada | Fuerte (GPT-4o) |
| Lagunas en aislamiento @MainActor | Fuerte | Moderada |
| Alineación de buffers en Metal | Moderada | Moderada |
| Detección de ciclos de retención | Fuerte (Opus) | Fuerte (o3) |
| Conciencia de deprecación de API | Fuerte (datos de entrenamiento más recientes) | Moderada |
| Condiciones de carrera en concurrencia | Fuerte | Fuerte (detecta patrones distintos) |
La revisión doble no se trata de encontrar más bugs, sino de encontrar bugs distintos. Cada familia de modelos tiene modos de fallo diferentes en su reconocimiento de patrones.
Operaciones por lotes en varias apps
Cuando un cambio de framework o patrón afecta a varias apps:
# 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
Úsalo con precaución. El flag --dangerously-skip-permissions es necesario para el modo no interactivo, pero omite todas las comprobaciones de seguridad. Asegúrate de tener tus hooks PreToolUse en su lugar para proteger los archivos .pbxproj.
Apps que usan LLM on-device de Apple
Si tu app llama al framework Foundation Models de Apple (por ejemplo, para resumen offline, clasificación o generación de salida estructurada), los agentes necesitan conocer el presupuesto de prompts. iOS 26.4 añadió dos API en SystemLanguageModel que reemplazaron la suposición previa de 4096 tokens: contextSize (máximo de tokens que el modelo acepta en una sola conversación) y tokenCount(for:) (async throws, devuelve cuántos tokens cuesta realmente un prompt determinado).16 Ambos son @backDeployed(before: iOS 26.4), así que están disponibles en todas las versiones de OS compatibles con FM sin necesidad de una escalera #available.
El patrón que un agente debe seguir al generar código de construcción de prompts:
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
}
Añade este patrón a tu CLAUDE.md si la app utiliza SystemLanguageModel. Sin él, los agentes recurren al antiguo hardcode de 4096 y truncan prompts silenciosamente en dispositivos que vienen con ventanas de contexto más amplias. La firma async throws de tokenCount(for:) es crítica: los agentes que peguen una versión síncrona no compilarán.
Casos de Estudio del Mundo Real
Los consejos abstractos son fáciles. Aquí tienes escenarios específicos de las 8 aplicaciones que ilustran cómo funciona en la práctica el desarrollo de iOS asistido por agentes — incluidos los fracasos.
Caso de Estudio 1: Agregar una App de TV a Return (Éxito)
La tarea: Agregar un target de tvOS a Return, un temporizador de meditación que ya tenía versiones para iOS y watchOS. La app de TV necesitaba navegación con Siri Remote, una interfaz para pantalla grande y sincronización de configuración con la app de iOS.
Lo que el agente hizo bien:
- Leyó el TimerManager existente de iOS y creó un TVTimerManager que omitía Live Activities y HealthKit (no disponibles en tvOS)
- Creó estilos de botón personalizados para la navegación con foco de Siri Remote (TVCapsuleButtonStyle, TVCircleButtonStyle)
- Construyó un componente TVStepper que reemplaza los selectores tipo rueda (no usables con Siri Remote) con botones +/-
- Implementó la sincronización de configuración mediante App Groups (group.com.941apps.Return)
- Agregó protecciones #if os(tvOS) en todo el código compartido
- Compiló y probó vía MCP con platform=tvOS Simulator,name=Apple TV
Lo que tuve que hacer manualmente: - Crear el target de tvOS en Xcode (File > New > Target > tvOS App) - Agregar el nuevo target al proyecto de Xcode (cambios en .pbxproj) - Configurar el entitlement de App Groups para el target de TV - Agregar el target de TV al esquema existente o crear uno nuevo - Agregar manualmente todos los archivos Swift creados por el agente al target de TV - Probar a mano la navegación con Siri Remote (el agente no puede evaluar el comportamiento del foco)
Resultado: 15 archivos Swift nuevos, una app de TV totalmente funcional, en aproximadamente 3 horas de trabajo asistido por agente. Según mi estimación, el agente se encargó de aproximadamente el 80% del trabajo de implementación; yo me ocupé de las partes que requerían interacción con la interfaz de Xcode (entitlements, configuración del target, banderas de capacidades) y de las pruebas manuales de foco en un Apple TV real. Un trabajo equivalente realizado en solitario en este codebase — basándome en funciones similares que he lanzado sin agentes — habría sido un esfuerzo de varios días.
Caso de Estudio 2: Depuración de Shader de Metal en amp97 (Fracaso Parcial)
La tarea: Agregar un sistema de intensidad basado en energía al shader del osciloscopio. La visualización debía pulsar con la energía del audio.
Lo que ocurrió:
1. El agente escribió una modificación válida del shader de Metal añadiendo un uniform uEnergy y tonemapping HDR
2. El código compiló sin errores
3. En el dispositivo, la visualización quedó completamente blanca — el coeficiente de intensidad era 10 veces demasiado alto (3,5 en lugar de 0,30)
4. El agente no podía ver la pantalla blanca, por lo que no tenía señal de retroalimentación
5. Identifiqué el problema visualmente y le pedí al agente que redujera el coeficiente
6. El agente lo redujo, pero la máquina de estados de energía en general era demasiado compleja y rompió el visualizador de otras formas
7. Se revirtió por completo — dos commits (67959ed y cda4830) revertidos en 869d914
La lección: Los shaders de Metal son el dominio más difícil para el desarrollo asistido por agente porque el ciclo de retroalimentación está roto. El agente puede verificar la sintaxis (compila) y la semántica (tipos correctos) pero no puede verificar la salida (se ve bien). Cualquier modificación de shader que cambie el comportamiento visual requiere verificación humana en el dispositivo.
Lo que añadí a CLAUDE.md después de esto: “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.”
Caso de Estudio 3: Migración de SwiftData en Banana List (Éxito)
La tarea: Migrar el modelo de datos de V1 a V2, agregando un campo quantity a GroceryItem y un nuevo modelo Category con relaciones.
Lo que hizo el agente:
1. Leyó las definiciones del modelo V1 existente
2. Creó las definiciones del modelo V2 con los nuevos campos y relaciones
3. Escribió un GroceryMigrationPlan que cumple con el protocolo SchemaMigrationPlan
4. Implementó la etapa de migración V1toV2: agregó valores predeterminados quantity: 1 y category: nil
5. Actualizó todas las vistas para admitir los nuevos campos
6. Actualizó SampleData.swift para los previews
7. Compiló y ejecutó las pruebas vía MCP — todas pasaron
8. Creó pruebas unitarias específicas para la migración
La clave: El agente tuvo éxito porque las migraciones de SwiftData siguen un patrón de protocolo bien definido que está exhaustivamente representado en la documentación de Apple y en los datos de entrenamiento. El CLAUDE.md documentaba explícitamente el modelo V1, por lo que el agente entendía desde qué estaba migrando.
Caso de Estudio 4: Sincronización de Sesiones por iCloud en Return (Éxito con Complejidad)
La tarea: Implementar el registro de sesiones de meditación entre dispositivos. Las sesiones completadas en Apple TV o Mac deben sincronizarse al iPhone para registrarse en HealthKit.
Lo que produjo el agente:
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ tvOS │ │ Mac │ │ Watch │
│ TVTimerMgr │ │ TimerMgr │ │ WatchTimer │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└───────────────────┼───────────────────┘
│
▼
┌────────────────────────┐
│ SessionStore │
│ (iCloud Key-Value) │
└───────────┬────────────┘
│
▼
┌────────────────────────┐
│ iPhone (on foreground)│
│ → Write to HealthKit │
└────────────────────────┘
El agente:
1. Creó el modelo de datos MeditationSession con UUID, fechas, duración, dispositivo de origen y estado de sincronización con HealthKit
2. Construyó un singleton SessionStore que gestiona NSUbiquitousKeyValueStore para la sincronización con iCloud
3. Implementó la resolución de conflictos de fusión (deduplicación basada en UUID)
4. Agregó SessionHistoryView con adaptaciones específicas por plataforma (swipe-to-delete en iOS, basado en foco en tvOS)
5. Conectó la sincronización con HealthKit en el lado del iPhone para sesiones provenientes de otros dispositivos
Lo que requirió iteración: La implementación inicial no manejaba el caso en que la app del iPhone se inicia en segundo plano (sin notificación en primer plano para sincronizar). El agente necesitaba una orientación específica: “Use NSUbiquitousKeyValueStore.didChangeExternallyNotification to trigger sync on background KV changes.” Tras esa indicación, la implementación fue correcta.
La lección: Los agentes manejan bien los patrones arquitectónicos multiplataforma cuando la arquitectura está claramente descrita. El patrón de sincronización con iCloud no es trivial, pero sigue un patrón documentado de Apple que el agente entendió. El caso límite (sincronización en segundo plano) requirió conocimiento humano del dominio porque no está bien documentado.
Caso de Estudio 5: Integración de Game Center en Starfield Destroyer (Éxito)
La tarea: Agregar tablas de clasificación y logros de Game Center al juego de naves espaciales.
Lo que el agente hizo bien:
- Implementó GKLocalPlayer.local.authenticateHandler en el punto de entrada de la app
- Creó un GameCenterManager con métodos para envío de puntuaciones y reporte de logros
- Agregó verificación del estado de autenticación antes de todas las operaciones de Game Center
- Manejó con elegancia el caso sin conexión (el juego funciona sin Game Center y envía cuando se reconecta)
- Creó definiciones de logros que coinciden con el sistema de progresión de 8 naves
Lo que requirió trabajo manual: - Crear las tablas de clasificación y los logros en App Store Connect (portal web, no accesible para el agente) - Configurar el entitlement de Game Center en Xcode - Probar con una cuenta sandbox de Game Center (requiere inicio de sesión manual en el dispositivo)
Ciclo de vida del proyecto con agentes
Iniciar un nuevo proyecto de iOS
El flujo de trabajo óptimo para iniciar un nuevo proyecto con asistencia de agentes:
Fase 1: Configuración humana (15-30 minutos) 1. Crea el proyecto de Xcode (File > New > Project) 2. Configura el signing y las capabilities 3. Establece el deployment target y los destinos compatibles 4. Agrega los entitlements necesarios (HealthKit, Game Center, etc.) 5. Crea el CLAUDE.md inicial con la identidad y las reglas del proyecto
Fase 2: Implementación por el agente (de horas a días) 1. El agente crea el modelo de datos (SwiftData, Core Data o structs simples) 2. El agente construye las vistas siguiendo los patrones documentados 3. El agente implementa la lógica de negocio en clases manager/service 4. El agente escribe pruebas unitarias 5. Bucle build-test-fix mediante MCP (autónomo)
Fase 3: Integración humana (30-60 minutos) 1. Agrega los archivos creados por el agente a los targets de Xcode 2. Verifica el signing y los entitlements 3. Prueba en un dispositivo físico 4. Revisa el diseño visual y la UX 5. Envía a App Store Connect
Mantener un proyecto existente
Para el desarrollo continuo de aplicaciones ya establecidas:
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]
La eficacia del agente escala con qué tan bien tu CLAUDE.md refleja el estado actual del proyecto. Actualiza tu CLAUDE.md cuando agregues nuevas funciones importantes, cambies los patrones arquitectónicos o introduzcas nuevos frameworks.
Cuándo involucrar al agente y cuándo no
| Tarea | ¿Agente? | Por qué |
|---|---|---|
| Nueva vista de SwiftUI | Sí | Los agentes destacan en UI declarativa |
| Cambios en modelos de SwiftData | Sí | Bien definidos, comprobables |
| Pruebas unitarias | Sí | Mecánicas, basadas en patrones |
| Refactorización | Sí | Sistemática, multiarchivo |
| Diagnóstico de errores de build | Sí (vía MCP) | Bucle de retroalimentación estructurado |
| Nuevo target de Xcode | No | Requiere la UI de Xcode, cambios en .pbxproj |
| Signing y provisioning | No | Basado en el portal, no accesible para el agente |
| Pulido visual | No | Requiere juicio estético humano |
| Ajuste de shaders de Metal | No | Requiere pruebas en dispositivo GPU |
| Envío a la App Store | No | Portal y Xcode Organizer |
| Profiling de rendimiento | No | Requiere Instruments |
| Auditoría de accesibilidad | Parcial | El agente puede agregar etiquetas, el humano verifica VoiceOver |
Configurar definiciones de agentes
Si usas el sistema de definiciones de agentes de Claude Code (.claude/agents/), crea un agente específico para iOS:
---
name: ios-developer
description: iOS development agent with MCP build tools and SwiftUI expertise
tools:
- XcodeBuildMCP
- xcode
---
# iOS Developer Agent
You are an iOS development agent for apps targeting iOS 26+ with SwiftUI.
## Architecture Rules
- @Observable for all view models (NEVER ObservableObject)
- NavigationStack for all navigation (NEVER NavigationView)
- SwiftData for persistence
- Swift 6.2 strict concurrency
- @MainActor on all Observable classes
## Build & Test — Always Use MCP
Prefer MCP tools over raw shell commands for ALL build operations:
- **Build**: `build_sim` / `build_device` (NOT `xcodebuild` via Bash)
- **Test**: `test_sim` / `test_device` (NOT `xcodebuild test` via Bash)
- **Simulators**: `list_sims`, `boot_sim`, `open_sim`
- **Debug**: `debug_attach_sim`, `debug_stack`, `debug_variables`
- **Apple docs**: `DocumentationSearch` (NOT WebSearch for Apple APIs)
- **Swift verification**: `ExecuteSnippet` (NOT `swift` via Bash)
MCP returns structured JSON. Bash returns unstructured text.
## File Management Rules
- NEVER modify .pbxproj, .xcodeproj/, .xcworkspace/, .xib, .storyboard
- Create Swift files in the correct directory
- Report files that need manual addition to Xcode targets
## SwiftData Rules
- @Model classes are automatically Observable — do not add @Observable
- Use @Bindable for form bindings to model properties
- Use @Query in views, modelContext.fetch() elsewhere
- Document relationship delete rules
## When You Get Stuck
- Build errors: use `build_sim` via MCP for structured output
- API questions: use `DocumentationSearch` via Apple MCP
- Swift verification: use `ExecuteSnippet` via Apple MCP
- Never guess — verify with tools
Haz referencia a este agente con @ios-developer en las sesiones de Claude Code.
Patrones de pruebas para iOS asistido por agentes
Los agentes escriben excelentes pruebas unitarias cuando se les da una guía clara. Estos son los patrones que producen los mejores resultados.
Organización de los archivos de prueba
# 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`
Cómo redactar prompts para pruebas
Prompt eficaz para pruebas:
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.
Por qué funciona: los criterios de aceptación numerados le dan al agente una lista de verificación. Hacer referencia a un archivo de prueba existente establece el patrón. Especificar el uso de setUp() evita que el agente cree un estado de prueba enredado.
Prompt ineficaz para pruebas:
Write tests for TimerManager.
Esto produce pruebas genéricas y superficiales que omiten casos límite y pueden no seguir los patrones de tu proyecto.
Patrones de pruebas asíncronas
Para probar código basado en temporizadores y código asíncrono:
// 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)
}
}
Patrones clave que los agentes necesitan que se les recuerden:
- @MainActor en métodos de prueba que prueban clases @MainActor
- async throws para pruebas que usan Task.sleep u operaciones asíncronas
- Tolerancia en aserciones basadas en tiempo (1,1 segundos, no exactamente 1,0)
- setUp() / tearDown() limpios para el aislamiento de pruebas
Pruebas de snapshot
Para la detección de regresiones visuales, considera agregar 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.
Los agentes configuran las pruebas de snapshot correctamente, pero no pueden revisar las imágenes de referencia. Tú revisas los snapshots iniciales, y luego las pruebas del agente detectan regresiones visuales en cambios futuros.
Gestión de la ventana de contexto para proyectos iOS
La ventana de contexto de 1M (Opus 4.6) es grande, pero no infinita. Los proyectos iOS tienen consideraciones específicas de gestión de contexto.
Costo en tokens de los archivos iOS
| Tipo de archivo | Tamaño típico | Tokens aproximados |
|---|---|---|
| Vista SwiftUI (simple) | 50-100 líneas | 500-1.000 |
| Vista SwiftUI (compleja) | 200-400 líneas | 2.000-4.000 |
| Modelo SwiftData | 30-80 líneas | 300-800 |
| Clase manager/service | 100-300 líneas | 1.000-3.000 |
| Shader Metal (.metal) | 50-200 líneas | 500-2.000 |
| Archivo de pruebas unitarias | 50-200 líneas | 500-2.000 |
| CLAUDE.md | 100-300 líneas | 1.000-3.000 |
| Respuesta MCP (build) | varía | 200-2.000 |
| Respuesta MCP (test) | varía | 500-5.000 |
Para un proyecto de 50 archivos: leer todos los archivos consume aproximadamente 50.000-100.000 tokens, muy dentro de la ventana de 1M. El agente puede mantener todo el proyecto en contexto.
Para un proyecto de 100+ archivos: la lectura selectiva se vuelve necesaria. El agente lee CLAUDE.md primero (por las anotaciones de la estructura de archivos) y luego lee archivos específicos según se necesite. Por eso las anotaciones de archivos en CLAUDE.md son críticas: guían al agente a los archivos correctos sin tener que leerlo todo.
Estrategias para proyectos grandes
- Anotaciones detalladas de archivos en CLAUDE.md — el agente lee el mapa de archivos y navega directamente a los archivos relevantes
- Delegación a subagentes — enruta la exploración y la investigación a subagentes (contexto limpio, devuelven resúmenes)
- Prompts enfocados — “Modifica SettingsView.swift para añadir un nuevo toggle” es mejor que “actualiza la configuración”
- Límites de sesión — inicia nuevas sesiones para funciones no relacionadas en lugar de extender una sesión larga
- Usa
/compact— el comando de compactación de Claude Code resume la conversación y libera contexto
Eficiencia de tokens con MCP
Uno de los argumentos más sólidos a favor de MCP: las respuestas estructuradas de JSON consumen muchos menos tokens que la salida cruda de xcodebuild.
| Escenario | Tokens en Bash crudo | Tokens con MCP | Ahorro |
|---|---|---|---|
| Compilación exitosa | 3.000-10.000 | 200-500 | 85-95% |
| Compilación fallida (1 error) | 3.000-10.000 | 300-800 | 90-92% |
| Resultados de pruebas (20 pruebas) | 2.000-5.000 | 500-1.000 | 75-80% |
| Lista de simuladores | 500-2.000 | 200-400 | 60-80% |
A lo largo de una sesión típica de desarrollo con 10-20 ciclos de compilación, MCP ahorra 30.000-150.000 tokens en comparación con xcodebuild crudo, tokens que quedan disponibles para razonar sobre el código real.
Solución de problemas
“build_sim falló — scheme no encontrado”
El agente está adivinando el nombre del scheme. Solución:
Use discover_projs and list_schemes to find the correct scheme name
for this project before building.
O añade el nombre del scheme explícitamente a tu CLAUDE.md:
## Build
Primary scheme: `Return` (iOS)
Watch scheme: `ReturnWatch` (watchOS)
TV scheme: `ReturnTV` (tvOS)
“xcrun mcpbridge — command not found”
Necesitas Xcode 26.3 o posterior. Verifica con xcodebuild -version. Si tienes Xcode 26.3+ pero el comando sigue fallando:
# Ensure Xcode command line tools are selected
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
# Verify
xcrun mcpbridge --help
“Las herramientas de MCP no aparecen en Claude Code”
Las herramientas de MCP registradas a mitad de sesión pueden no aparecer hasta reiniciar. Sal de Claude Code e inicia una sesión nueva:
# Exit current session (Ctrl+C or /exit)
# Start fresh
claude
Luego verifica:
You: List all available MCP tools from XcodeBuildMCP.
“El agente sigue usando xcodebuild vía Bash en lugar de MCP”
El agente no está descubriendo las herramientas de MCP vía Tool Search. Dos soluciones:
- Añade orientación explícita a CLAUDE.md (consulta Enseñar al agente a usar MCP)
- Pide directamente: “Use the build_sim MCP tool, not xcodebuild via Bash”
“La compilación tiene éxito pero el agente reporta fallo”
XcodeBuildMCP analiza la salida de xcodebuild. Si la compilación produce advertencias que parecen errores (común con advertencias de deprecación), el agente puede malinterpretar el resultado. Revisa el campo de estado real en la respuesta de MCP.
“El simulador se cuelga durante el arranque”
Cierra todos los simuladores y reinicia:
xcrun simctl shutdown all
xcrun simctl boot "iPhone 16 Pro"
O pídele al agente:
Shut down all simulators, then boot a fresh iPhone 16 Pro.
“El agente intentó modificar .pbxproj a pesar de las reglas en CLAUDE.md”
Las reglas en CLAUDE.md son sugerencias. Los hooks son aplicación efectiva. Si no tienes el hook PreToolUse bloqueando escrituras a .pbxproj, el agente eventualmente lo intentará. Instala el 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'"
}
]
}
}
Las reglas dicen “por favor, no lo hagas.” Los hooks dicen “no puedes.”
Preguntas frecuentes
¿Con qué runtime de agente debería empezar?
Claude Code CLI con XcodeBuildMCP. Tiene la integración más profunda con MCP, el sistema de hooks más maduro y la ventana de contexto de 1M (Opus 4.6) que puede mantener proyectos iOS completos en memoria de trabajo. Empieza aquí y luego añade Codex para revisión y los agentes nativos de Xcode para ediciones rápidas en línea a medida que tu flujo de trabajo madura.
¿Necesito ambos servidores MCP?
Para la mayoría de los desarrolladores, XcodeBuildMCP por sí solo cubre el 90% de las necesidades (compilaciones, pruebas, simuladores, depuración). Añade el MCP de Xcode de Apple si quieres búsqueda en la documentación, verificación con Swift REPL o renderizado de previsualizaciones de SwiftUI. Siempre puedes añadirlo después: los dos servidores son independientes.
¿Pueden los agentes crear un nuevo proyecto de Xcode desde cero?
XcodeBuildMCP incluye una herramienta create_project que genera nuevos proyectos de Xcode. Sin embargo, para apps de producción, recomiendo crear el proyecto en Xcode (para que la firma, las capabilities y la configuración del target queden correctas) y luego usar agentes para toda la implementación de código. Los 5 minutos que pasas en el asistente de nuevo proyecto de Xcode te ahorran horas de problemas de configuración de proyecto generados por el agente.
¿Cómo manejan los agentes las dependencias de Swift Package Manager?
Bien. Package.swift es un archivo Swift estándar que los agentes pueden leer y editar de forma confiable. Añadir dependencias, actualizar rangos de versión y configurar targets funciona. La limitación es la gestión de dependencias basada en .xcodeproj (la UI de resolución de paquetes de Xcode): eso lo gestiona Xcode y no debería editarse por agentes.
¿Pueden los agentes enviar a la App Store?
No. El envío a la App Store implica el Organizer de Xcode, perfiles de aprovisionamiento, capturas de pantalla, metadata y el portal de App Store Connect. Nada de esto es accesible vía MCP o herramientas de línea de comandos de una manera en la que los agentes puedan operar de forma significativa. Los agentes manejan todo hasta el archive: implementación, pruebas, corrección de errores y documentación. La última milla del envío sigue siendo operada por humanos.
Sin embargo, los agentes pueden ayudar con la metadata de la App Store. Pide al agente que escriba la descripción de la app, palabras clave y el texto de “novedades” basándose en los cambios más recientes. Este es un trabajo de generación de texto donde los agentes destacan.
¿Cómo manejo secretos y claves API en el desarrollo iOS asistido por agentes?
Nunca hagas commit de secretos. Para apps iOS que se conectan a APIs backend:
- Usa archivos
.xcconfigpara la configuración específica del entorno - Añade los archivos
.xcconfiga.gitignore - Referencia los valores de configuración vía build settings de
Info.plist - Documenta los secretos requeridos en CLAUDE.md sin incluir los valores reales
## 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`.
El agente sabe que las claves existen y dónde se usan, pero nunca ve los valores reales.
¿Y las animaciones de SwiftUI? ¿Pueden los agentes escribirlas?
Los agentes escriben código de animación bien sintácticamente, pero no pueden verificar el resultado visualmente. Las animaciones simples (.animation(.spring()), .transition(.slide), withAnimation { }) producen resultados correctos. Las animaciones complejas de varios pasos con timing preciso requieren iteración visual que los agentes no pueden hacer.
Efectivo: “Add a spring animation when the timer transitions between states.”
Inefectivo: “Make the timer animation feel satisfying.” (Subjetivo, requiere ajuste visual.)
¿Cómo manejan los agentes los patrones de manejo de errores?
Muy bien. Los agentes entienden los patrones do/catch, Result y async throws de Swift:
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
Los agentes producen manejo de errores estructurado con mensajes apropiados orientados al usuario. A veces sobre-manejan errores (capturando excepciones que deberían propagarse), así que revisa los bloques catch.
¿Puedo usar agentes para la implementación de accesibilidad?
Parcialmente. Los agentes añaden etiquetas, sugerencias y traits de accesibilidad correctamente:
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
Lo que los agentes no pueden hacer: verificar que el orden de navegación con VoiceOver sea correcto, probar el escalado de Dynamic Type o evaluar las relaciones de contraste de color. Usa el Accessibility Inspector de Xcode para verificación.
¿Cómo manejan los agentes la migración de Core Data (si no usas SwiftData)?
Los agentes escriben los mapeos de migración y las versiones de modelo de Core Data, pero los pasos manuales en Xcode (crear nuevas versiones del modelo, seleccionar la versión actual) no se pueden automatizar. Si todavía estás en Core Data en lugar de SwiftData, documenta el historial de versiones del modelo en CLAUDE.md:
## Versiones del Modelo de Core Data
- V1: Inicial (GroceryList, GroceryItem)
- V2: Modelo Category añadido (actual)
- Migración: Lightweight automática para V1→V2
¿Cómo manejan los agentes las previews de SwiftUI?
De dos maneras:
1. La herramienta RenderPreview de Apple Xcode MCP renderiza las previews sin interfaz y devuelve el resultado. El agente puede verificar que una preview compile y se renderice sin errores, pero no puede evaluar la corrección visual.
2. Verificación basada en build mediante build_sim confirma que los preview providers compilan. Si una preview falla en tiempo de ejecución, la build aún tiene éxito — el fallo solo se manifiesta cuando Xcode intenta renderizar la preview.
Para la verificación visual de las previews, todavía necesitas tener Xcode abierto.
¿Qué pasa con visionOS y Apple Vision Pro?
Aplican los mismos patrones. XcodeBuildMCP admite simuladores de visionOS, y los patrones arquitectónicos (@Observable, NavigationStack, SwiftData) son idénticos. El código específico de RealityKit (contenido 3D, espacios inmersivos, hand tracking) sigue las mismas limitaciones que Metal — los agentes pueden escribir código correcto pero no pueden verificar la salida espacial.
¿Qué tan grande puede ser un proyecto antes de que los agentes tengan dificultades?
El tamaño de la ventana de contexto es el factor limitante. Con la ventana de 1M tokens de Opus 4.6, Claude Code puede mantener aproximadamente 50-70 archivos Swift en memoria de trabajo activa simultáneamente. Para proyectos más grandes, el agente usa búsqueda de archivos y lectura selectiva para trabajar con subconjuntos del codebase. Los proyectos con más de 100 archivos funcionan bien — el agente simplemente lee los archivos bajo demanda en lugar de mantener todo en contexto.
El límite práctico no es la cantidad de archivos sino la coherencia del codebase. Un proyecto de 200 archivos bien documentado con un CLAUDE.md detallado produce mejores resultados que un proyecto de 30 archivos sin documentar.
¿Necesito saber Swift para usar agentes en el desarrollo de iOS?
Necesitas poder revisar la salida del agente y tomar decisiones arquitectónicas. No necesitas escribir cada línea tú mismo, pero necesitas entender Swift lo suficientemente bien como para detectar cuando el agente toma decisiones incorrectas — especialmente en torno a concurrencia, gestión de memoria y patrones específicos del framework. Un agente es un amplificador 10x de tu habilidad existente, no un reemplazo de ella.
¿Cómo manejan los agentes los conflictos de merge en archivos Swift?
Los agentes resuelven los conflictos de merge en archivos fuente Swift de forma fiable. Los marcadores estándar de conflicto (<<<<<<<, =======, >>>>>>>) son bien comprendidos por todos los runtimes de agentes. Sin embargo, los conflictos de merge en archivos .pbxproj siguen siendo una tarea de resolución manual — no le pidas a los agentes que resuelvan conflictos de .pbxproj.
¿Cuál es el costo de ejecutar agentes para el desarrollo de iOS?
Con el plan Max de Anthropic (Opus 4.6, contexto de 1M), una sesión típica de desarrollo iOS dura entre 30 y 120 minutos y procesa entre 200K y 800K tokens. Las llamadas a herramientas de MCP añaden una sobrecarga mínima (las respuestas estructuradas en JSON son eficientes en tokens comparadas con la salida de build sin procesar). El costo es comparable a ejecutar Claude Code en cualquier otro codebase — el desarrollo de iOS no es significativamente más caro ni más barato que el desarrollo web.
¿Puedo usar agentes con proyectos de UIKit?
Sí, pero los agentes son más efectivos con SwiftUI. UIKit requiere más boilerplate, tiene menos estructura declarativa y a menudo involucra archivos de Interface Builder que los agentes no pueden editar. Si tienes un proyecto UIKit, considera usar agentes para la capa de modelo y la lógica de negocio mientras manejas la UI manualmente, o migrar las vistas a SwiftUI de forma incremental.
¿Cómo manejan los agentes la localización?
Los agentes crean y editan archivos .xcstrings (catálogo de strings de Xcode) de manera efectiva. Pueden añadir nuevas claves de localización, proporcionar traducciones y mantener la consistencia entre idiomas. El formato JSON estructurado de los archivos .xcstrings es amigable para los agentes. Para los archivos .strings (formato legacy), los agentes también funcionan bien — el formato clave-valor es directo.
Errores Comunes de los Agentes en iOS (y Cómo Prevenirlos)
Estos son los errores recurrentes que he observado en miles de interacciones con agentes en 8 proyectos de iOS. Cada uno tiene una estrategia de prevención.
Error 1: Mezclar Patrones de Observable
Qué ocurre: El agente usa @Observable en un archivo y ObservableObject en otro, o añade @Observable a una clase @Model (que ya es Observable).
Prevención: Reglas explícitas en 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
Error 2: Crear Retain Cycles en Closures
Qué ocurre: El agente crea closures que capturan self de forma fuerte, especialmente en Timer.publish, NotificationCenter y completion handlers.
Prevención: Incluye un patrón de closure en 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
Error 3: Ignorar los Requisitos de @MainActor
Qué ocurre: El agente crea clases @Observable sin aislamiento @MainActor, lo que causa advertencias de concurrencia de Swift 6.2 o fallos en tiempo de ejecución cuando las actualizaciones de UI ocurren fuera del hilo principal.
Prevención:
## Concurrency Rule
ALL @Observable classes MUST be @MainActor:
```swift
@Observable
@MainActor
final class SomeManager { }
```
Error 4: Usar NavigationLink con Closure de Destination
Qué ocurre: El agente usa el NavigationLink(destination:label:) deprecado en lugar del patrón type-safe NavigationLink(value:) + .navigationDestination(for:).
Prevención:
## 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)) { }`
Error 5: Hardcodear Nombres de Simuladores
Qué ocurre: El agente escribe comandos de build con nombres específicos de simuladores (“iPhone 16 Pro”) que pueden no existir en tu sistema.
Prevención: MCP se encarga de esto — list_sims descubre los simuladores disponibles. En 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.
Error 6: Crear Archivos en Directorios Incorrectos
Qué ocurre: El agente crea un nuevo archivo de vista en la raíz del proyecto en lugar del subdirectorio Views/, o coloca un modelo en el grupo equivocado.
Prevención: Las anotaciones de estructura de archivos en CLAUDE.md guían la ubicación. Adicionalmente:
## File Placement Rules
- Views → `AppName/Views/`
- Models → `AppName/Models/`
- Managers → `AppName/Managers/`
- Extensions → `AppName/Extensions/`
- Tests → `AppNameTests/`
Error 7: No Manejar la Disponibilidad de Plataformas
Qué ocurre: El agente usa HealthKit en código compartido que compila para tvOS (donde HealthKit no está disponible), o usa ActivityKit en código de watchOS.
Prevención:
## 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)
Error 8: Sobreingeniería de Funciones Simples
Qué ocurre: El agente crea un protocolo, una extensión de protocolo, una implementación concreta, un factory y un contenedor de inyección de dependencias para lo que debería ser una función utilitaria de 20 líneas.
Prevención: Incluye un principio de simplicidad:
## 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
La evaluación honesta
Después de lanzar 8 aplicaciones de iOS con agentes de IA, este es el resumen:
Lo que los agentes transformaron: la velocidad de implementación. Lo que tomaba días ahora toma horas. Vistas SwiftUI, modelos SwiftData, pruebas unitarias, refactorización — todo esto ahora es producido principalmente por agentes y revisado por humanos.
Lo que los agentes no transformaron: las decisiones arquitectónicas, el diseño visual, la optimización de rendimiento o el envío a la App Store. Estas siguen siendo responsabilidad humana.
El multiplicador es real pero acotado. Mi estimación subjetiva en el portafolio de 8 aplicaciones: una mejora de 3 a 5 veces en el tiempo de implementación de funciones en proyectos bien documentados con la configuración adecuada de MCP y hooks. Esto no se mide contra un grupo de control; es una comparación de tiempo real entre funciones asistidas por agentes y trabajo equivalente en solitario en las mismas bases de código. Los proyectos sin documentación ni hooks ven quizás una mejora de 1,5 a 2 veces — el agente pasa demasiado tiempo adivinando en lugar de construir.18
La inversión que vale la pena: el tiempo dedicado a la configuración de CLAUDE.md, hooks y MCP. Cada hora de configuración ahorra muchas horas corrigiendo errores del agente. La configuración es el producto — el agente es el motor de ejecución.
Lo que me sorprendió: cuánto cambiaron los servidores MCP la dinámica. Antes de MCP, los agentes eran editores de texto sofisticados que casualmente entendían Swift. Después de MCP, son socios de desarrollo que escriben, compilan, prueban, depuran e iteran. El bucle de retroalimentación estructurado es la diferencia entre un agente que escribe código y uno que envía código.
Lo que le diría a mi yo del pasado: comienza con la aplicación más pequeña (Reps, 14 archivos), configura bien MCP y los hooks, escribe un CLAUDE.md exhaustivo y luego escala los patrones a proyectos más grandes. No empieces con la aplicación multiplataforma de 63 archivos. La inversión en infraestructura es la misma sin importar el tamaño del proyecto — hazla una vez en un proyecto pequeño y luego cópiala a todo lo demás.
El futuro: la integración nativa de agentes en Xcode 26.3 es el comienzo, no el final. Que Apple incorpore soporte para MCP significa que la cadena de herramientas avanza hacia un desarrollo centrado en agentes. Los desarrolladores que inviertan ahora en estructuras de proyecto compatibles con agentes — archivos CLAUDE.md limpios, arquitecturas testeables, hooks automatizados — verán esa inversión multiplicarse a medida que las herramientas mejoren.
Tarjeta de referencia rápida
Instalación (configuración única)
# 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
Secciones esenciales de 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 esenciales
{
"PreToolUse": [{ "matcher": "Edit|Write", "command": "block .pbxproj" }],
"PostToolUse": [{ "matcher": "Edit|Write", "command": "swiftformat" }]
}
Reglas de arquitectura
@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+)
Prioridades de herramientas MCP
Build: build_sim (not xcodebuild via Bash)
Test: test_sim (not xcodebuild test via Bash)
Sim: list_sims/boot_sim (not xcrun simctl via Bash)
Docs: DocumentationSearch (not WebSearch)
REPL: ExecuteSnippet (not swift via Bash)
Registro de cambios
| Fecha | Cambios |
|---|---|
| 2026-04-28 | Se actualizó la versión recomendada de Xcode a 26.4+ para flujos de trabajo con agentes (26.4.1, 2026-04-16, build 17E202 es la última estable, solo correcciones de errores). Se citaron las funciones de Xcode 26.4 (2026-03-24, build 17E192) útiles para pruebas y localización generadas por agentes: adjuntos de imágenes en Swift Testing, severidad en Issue.record, advertencias de fallos en pruebas de UI con crashlogs adjuntos (específicamente para apps XCUIApplication(bundleIdentifier:) / XCUIApplication(url:)), mejoras en el editor de String Catalog. Se agregó el instalador automático xcodebuildmcp init (v2.1.0+, 2026-02-23) como alternativa a la configuración manual de MCP. |
| 2026-04-27 | App Store Connect: los envíos con Xcode 26+ son obligatorios a partir del 2026-04-28. Foundation Models incorporó las APIs SystemLanguageModel.contextSize y tokenCount(for:) (con back-deployment a iOS 26.4) — se agregó un patrón para código generado por agentes que gestiona el presupuesto de prompts en FM. iOS 26.4.2 (22 de abril) y iOS 26.5 beta 3 (20 de abril) se lanzaron sin cambios que afecten la cadena de herramientas de agentes. |
| 2026-04-13 | Publicación inicial. 8 aplicaciones, 3 runtimes, configuración de MCP, patrones de CLAUDE.md, hooks, casos de estudio. |
Referencias
-
XcodeBuildMCP incluye telemetría de Sentry de forma predeterminada. La documentación de privacidad del proyecto detalla qué se envía: mensajes de error, stack traces y, en algunos casos, rutas de archivos. La variable de entorno
XCODEBUILDMCP_SENTRY_DISABLED=truedesactiva la telemetría por completo. ↩ -
Anthropic, “Model Context Protocol Specification,” modelcontextprotocol.io/specification. La especificación de MCP define el transporte JSON-RPC, el descubrimiento de herramientas y el protocolo de recursos que tanto XcodeBuildMCP como el MCP de Xcode de Apple implementan. ↩
-
XcodeBuildMCP, github.com/getsentry/XcodeBuildMCP. Código abierto, mantenido por Sentry. 59 herramientas que abarcan flujos de trabajo de simulador, dispositivo, depuración y automatización de UI. Versionado semántico con changelogs. ↩
-
Apple introdujo el servidor MCP de Xcode como parte de la iniciativa de herramientas inteligentes para desarrolladores de Xcode 26.3, posicionando MCP como la capa de interfaz entre los asistentes de codificación de IA y la cadena de herramientas de Xcode. Consulta las Notas de la versión de Xcode para la documentación oficial. ↩
-
Rudrank Riyam, “Exploring Xcode Using MCP Tools,” rudrank.com/exploring-xcode-using-mcp-tools-cursor-external-clients, 2026. Confirmación independiente del recuento de herramientas MCP de Apple, la dependencia de XPC y las capacidades de búsqueda en la documentación. ↩
-
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. Los agentes con acceso estructurado a herramientas superaron significativamente a los agentes limitados a comandos de shell no estructurados. El hallazgo valida las interfaces MCP estructuradas para la efectividad de los agentes. ↩
-
Documentación de Claude Code CLI, code.claude.com. Sistema de hooks, configuración de MCP, delegación de subagentes y definiciones de agentes. ↩
-
SwiftFormat, github.com/nicklockwood/SwiftFormat. La herramienta de formateo de Swift utilizada en los hooks PostToolUse para mantener un estilo de código consistente. ↩
-
Sitio oficial de XcodeBuildMCP, xcodebuildmcp.com. Confirma 59 herramientas MCP mediante el ejemplo de salida de CLI. Categorías de herramientas: simulador, dispositivo, depuración y automatización de UI. Instalación mediante Homebrew o npx. ↩
-
Swiftjective-C, “Agentic Coding in Xcode 26.3 with Claude Code and Codex,” swiftjectivec.com, febrero de 2026. Confirma que Xcode 26.3 incluye soporte nativo para Claude Agent y el runtime de Codex mediante Settings > Intelligence. 20 herramientas MCP expuestas a través de
xcrun mcpbridge. ↩ -
Blake Crosley, “Two MCP Servers Made Claude Code an iOS Build System,” blakecrosley.com/blog/xcode-mcp-claude-code, febrero de 2026. Tutorial de configuración y resultados reales del flujo de trabajo de desarrollo iOS del mismo autor. ↩
-
Apple Developer News, “Upcoming Requirements”. La entrada del 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 no aparece en el conjunto de plataformas listadas en este requisito. ↩
-
Apple, “Xcode 26.4 Release Notes”. Xcode 26.4 (2026-03-24, build 17E192). Funciones citadas de las notas de la versión: Swift Testing ahora admite adjuntos de imágenes mediante
CGImage,NSImage,UIImageyCIImage;Issue.recordacepta niveles de severidad; algunos fallos de aplicaciones en pruebas de UI —específicamente aplicaciones con las que se interactúa medianteXCUIApplication(bundleIdentifier:)oXCUIApplication(url:)— se reportan como advertencias con crashlogs adjuntos en lugar de hacer fallar la prueba; el editor de String Catalog añade cortar/copiar/pegar de entradas, eliminación de idiomas y pre-llenado de traducciones desde un idioma existente, además del ajusteBUILD_ONLY_KNOWN_LOCALIZATIONS. ↩ -
Apple Developer News, “Xcode 26.4.1 (Build 17E202) Now Available”, 2026-04-16. Versión puntual solo de corrección de errores: arregla un fallo de MetricKit por símbolos faltantes en iOS / macOS / visionOS anteriores a 26.4, y un error de asignación de pila asíncrona de Swift (“freed pointer was not the last allocation” en
swift_asyncLet_finish). ↩ -
release v2.1.0 de getsentry/XcodeBuildMCP, 2026-02-23. Se añadió el comando CLI
xcodebuildmcp initpara instalar las skills del agente y la configuración de MCP en un solo paso, reemplazando el script independienteinstall-skill.sh. Detecta automáticamente Claude Code, Cursor y Codex; admite--print(escribe la configuración a stdout para clientes no compatibles) y--uninstall(eliminar). ↩ -
InfoQ, “Apple Adds Context Window Management to Foundation Models”, marzo de 2026. Documenta las nuevas APIs
SystemLanguageModel.contextSizeytokenCount(for:), y confirma las anotaciones@backDeployed(before: iOS 26.4). Reemplaza la suposición previa de la comunidad sobre un límite codificado de 4096 tokens. ↩ -
Recuentos de archivos derivados de
find . -name '*.swift' -not -path '*/Tests/*' | wc -lejecutado contra cada uno de los ocho repositorios privados de aplicaciones el 2026-04-27. Archivos de prueba excluidos. El total es internamente consistente con la tabla de desglose por aplicación en §The Portfolio. ↩ -
Estimación subjetiva de tiempo real, no una medición contra un grupo de control. La cifra de 3-5x es el recuerdo del autor sobre comparaciones de tiempo hasta función entre funciones asistidas por agentes en 2026 y funciones equivalentes desarrolladas en solitario en los mismos repositorios antes del flujo de trabajo con agentes. Considéralo una heurística de qué esperar tras la configuración de MCP + hooks, no como un benchmark. ↩