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

Construindo apps iOS com agentes de IA: o guia do praticante

# Construindo apps iOS com agentes de IA

words: 10617 read_time: 41m updated: 2026-04-14 23:54
$ less ios-agent-development.md

TL;DR: Três runtimes de agentes agora geram código para iOS: Claude Code CLI com MCP, Codex CLI com MCP, e os agentes nativos Intelligence do Xcode 26.3. Dois servidores MCP (XcodeBuildMCP com 59 ferramentas e o xcrun mcpbridge da Apple com 20 ferramentas) dão aos agentes acesso estruturado a builds, testes, simuladores e depuração. Este guia cobre padrões reais de CLAUDE.md, configurações de hooks e avaliações honestas do que funciona e do que quebra — extraídos de 8 apps iOS em produção totalizando 293 arquivos Swift. Agentes se destacam em views SwiftUI, modelos SwiftData, refatoração e diagnóstico de erros de build. Eles falham em modificações de .pbxproj, assinatura de código e depuração visual. A distância entre “o agente escreve Swift” e “o agente publica um app iOS” é preenchida por configuração, não por prompting.

Eu desenvolvo 8 apps iOS com agentes de codificação por IA. Não são protótipos — são apps na App Store, com integrações HealthKit, shaders Metal, física SpriteKit, sincronização iCloud, Live Activities, placar Game Center e alvos multi-plataforma abrangendo iOS, watchOS e tvOS. Cada linha de Swift nesses apps foi escrita por um agente e revisada por mim, ou escrita por mim e refatorada por um agente. Pela minha estimativa, a proporção é de aproximadamente 85/15 a favor do agente.

Este guia é a referência que eu gostaria que existisse quando comecei. Ele cobre toda a stack: qual runtime de agente usar, como configurar servidores MCP para acesso estruturado ao build, o que colocar no seu CLAUDE.md, quais hooks impedem o agente de destruir seu projeto Xcode e — crucialmente — onde os agentes falham e você precisa assumir o controle.

Principais conclusões

Para desenvolvedores iOS novos em agentes de IA:

  • Comece com Claude Code CLI + XcodeBuildMCP. É o runtime mais maduro com a cobertura de ferramentas MCP mais ampla. Instale dois comandos, adicione um CLAUDE.md ao seu projeto, e o agente pode compilar, testar e depurar sem que você precise copiar mensagens de erro.
  • Nunca deixe um agente modificar .pbxproj. Esta é a regra mais importante. Um hook PreToolUse que bloqueia escritas em .pbxproj e .xcodeproj/ vai poupar horas de recuperação.
  • Seu CLAUDE.md é o documento de onboarding do agente. Cada hora investida no CLAUDE.md economiza dez horas corrigindo erros do agente.

Para usuários experientes de agentes adicionando iOS ao seu fluxo de trabalho:

  • MCP transforma o ciclo de build iOS. Antes do MCP, agentes escreviam Swift mas não conseguiam verificar se compilava. Com XcodeBuildMCP, o agente escreve código, compila, lê erros estruturados, corrige-os e executa testes — de forma autônoma.
  • Três runtimes atendem necessidades diferentes. Claude Code CLI para sessões agênticas profundas, Codex CLI para trabalho em lote headless, agentes nativos do Xcode 26.3 para correções rápidas inline sem sair da IDE.
  • A infraestrutura de hooks se transfere diretamente. Seus formatadores PostToolUse, bloqueadores PreToolUse e hooks de test runner existentes funcionam de forma idêntica para projetos iOS com pequenos ajustes de caminhos.

Para líderes de equipe avaliando desenvolvimento iOS assistido por IA:

  • A eficácia do agente escala com a documentação do projeto, não com o tamanho do projeto. Um app de 63 arquivos com um CLAUDE.md detalhado produz resultados melhores do que um app de 14 arquivos sem nenhum.
  • O limite do .pbxproj é inegociável. Agentes não conseguem editar arquivos de projeto Xcode de forma confiável. Seu fluxo de trabalho deve prever a adição manual de arquivos aos targets do Xcode.
  • Avaliação honesta (ROI): agentes lidam com 70-80% do trabalho de implementação. Os 20-30% restantes — polimento visual, assinatura, ajuste de performance, submissão à App Store — exigem julgamento humano.

Escolha seu caminho

O que você precisa Vá para
Configurar MCP pela primeira vez Configuração do MCP: A Configuração Completa — instale ambos os servidores, verifique, configure agentes
Escrever um CLAUDE.md para seu projeto iOS Padrões de CLAUDE.md para Projetos iOS — exemplos reais de 8 apps
Comparar os três runtimes de agentes Três Runtimes de Agentes para iOS — Claude Code vs. Codex vs. Xcode nativo
Entender o que agentes conseguem e não conseguem fazer O Que Agentes Fazem Bem e O Que Agentes Fazem Mal
Configurar hooks para desenvolvimento iOS Hooks para Desenvolvimento iOS — format-on-save, proteção de .pbxproj, test runners
Referência completa (esta página) Continue lendo — tudo, desde configuração até padrões avançados

Como usar este guia

Esta é uma referência de mais de 3.000 linhas. Comece onde seu nível de experiência se encaixa:

Experiência Comece aqui Depois explore
Novo em iOS + agentes Pré-requisitosConfiguração do MCPSua Primeira Sessão com Agente Padrões de CLAUDE.md, O Que Funciona/Não Funciona
Desenvolvedor iOS, novo em agentes Três RuntimesConfiguração do MCPCLAUDE.md Hooks, Padrões de Arquitetura
Usuário de agentes, novo em iOS Padrões de ArquiteturaO Que Agentes Fazem MalCLAUDE.md Contexto Específico de Frameworks, Fluxos Avançados
Experiente em ambos Fluxos AvançadosHooksPadrões Multi-Plataforma Matriz de Comparação de Runtimes, O Portfólio

Sumário

  1. O Portfólio: 8 Apps, 293 Arquivos
  2. Pré-requisitos
  3. Três Runtimes de Agentes para iOS
  4. Configuração do MCP: A Configuração Completa
  5. Padrões de CLAUDE.md para Projetos iOS
  6. Sua Primeira Sessão com Agente
  7. O Que Agentes Fazem Bem em iOS
  8. O Que Agentes Fazem Mal em iOS
  9. Hooks para Desenvolvimento iOS
  10. Padrões de Arquitetura Que Funcionam com Agentes
  11. Contexto Específico de Frameworks
  12. Padrões Multi-Plataforma
  13. Fluxos Avançados
  14. Estudos de Caso Reais
  15. Ciclo de Vida do Projeto com Agentes
  16. Configurando Definições de Agentes
  17. Padrões de Testes para iOS Assistido por Agentes
  18. Gerenciamento de Janela de Contexto para Projetos iOS
  19. Solução de Problemas
  20. Erros Comuns de Agentes em iOS
  21. A Avaliação Honesta
  22. FAQ
  23. Cartão de Referência Rápida
  24. Referências

Recursos relacionados

Tópico Recurso
Configuração de MCP para Xcode (post mais curto) Dois Servidores MCP Fizeram do Claude Code um Sistema de Build iOS
Referência completa do Claude Code CLI Claude Code CLI: O Guia Completo
Referência do Codex CLI Codex CLI: O Guia Completo
Aprofundamento no sistema de hooks Anatomia de uma Garra: 84 Hooks como Camada de Orquestração
Padrões de arquitetura de agentes Guia de Arquitetura de Agentes

O Portfólio: 8 Apps, 293 Arquivos

Antes de mergulhar na configuração, veja de onde este guia foi extraído. Estes não são projetos de brinquedo — eles abrangem cinco frameworks da Apple, três plataformas e toda a gama de complexidade iOS, desde um rastreador de treinos com 14 arquivos até um temporizador de meditação multiplataforma com 63 arquivos.

App Stack Arquivos Complexidade
Banana List SwiftUI + SwiftData + sincronização iCloud Drive + servidor MCP para Claude Desktop 53 CRUD completo, sincronização iCloud, servidor MCP customizado que expõe os dados do app ao Claude Desktop
Ace Citizenship App de estudo SwiftUI + backend FastAPI 26 Cliente-servidor, integração REST API, motor de quiz
TappyColor Jogo de combinação de cores SpriteKit 30 Game loop, física, tratamento de toque, efeitos de partículas
Return Temporizador de meditação zen — iOS 26+, watchOS, tvOS 63 HealthKit, Live Activities, runtime estendido do Watch, navegação por foco na TV, sincronização de sessões via iCloud
amp97 Shaders Metal + visualização de áudio 41 Pipeline de renderização Metal customizado, análise de áudio, computação GPU em tempo real
Reps SwiftUI + SwiftData rastreamento de treinos 14 App mínimo viável, padrões limpos de SwiftData
Water SwiftUI + SwiftData + Metal + HealthKit rastreamento de hidratação 34 Simulação de fluidos em Metal, registro de ingestão de água via HealthKit, widget
Starfield Destroyer SpriteKit + Metal space shooter 32 99 níveis, 8 naves, leaderboards do Game Center, pós-processamento Metal

Por que a contagem de arquivos importa: A eficácia do agente está correlacionada com a legibilidade do projeto, não com o tamanho. Return (63 arquivos) produz saídas melhores do agente do que amp97 (41 arquivos) porque Return tem um CLAUDE.md detalhado com anotações de arquivos, diagramas de arquitetura e padrões explícitos. Os shaders Metal do amp97 são inerentemente mais difíceis para agentes raciocinarem, independentemente da qualidade da documentação.


Pré-requisitos

Antes de configurar qualquer runtime de agente para desenvolvimento iOS:

Obrigatório: - macOS 15+ (Sequoia) ou macOS Tahoe - Xcode 26.3+ instalado e configurado (contrato de licença aceito, plataformas baixadas) - Pelo menos um runtime de iOS Simulator instalado - Uma conta Anthropic API (para Claude Code) ou conta OpenAI (para Codex)

Recomendado: - SwiftFormat instalado (brew install swiftformat) — usado por hooks de formatação ao salvar - SwiftLint instalado (brew install swiftlint) — opcional, mas útil para padronização de estilo - Familiaridade com o terminal — os três runtimes operam a partir ou se integram com a linha de comando

Verifique sua instalação do Xcode:

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

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

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

Se xcrun mcpbridge retornar “command not found”, você precisa do Xcode 26.3 ou posterior. Instale ou atualize o Xcode pela App Store ou em developer.apple.com. Observação: xcode-select --install instala apenas as Command Line Tools, que não incluem o mcpbridge — você precisa do Xcode.app completo.


Três Runtimes de Agente para iOS

Três runtimes distintos podem escrever, compilar e testar código iOS. Eles não são intercambiáveis — cada um tem pontos fortes diferentes, padrões de integração MCP diferentes e casos de uso ideais diferentes.

1. Claude Code CLI

O que é: Assistente de codificação agêntico baseado em terminal da Anthropic. Lê seu codebase, executa comandos, modifica arquivos e se conecta a ferramentas externas via MCP.

Integração MCP: Suporte completo tanto para XcodeBuildMCP quanto para o Xcode MCP da Apple. O agente descobre ferramentas via protocolo MCP e as invoca com parâmetros estruturados. 59 + 20 ferramentas entre os dois servidores.

Configuração:

# 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

Melhor para: Sessões de implementação profundas — construir novos recursos, refatorar em múltiplos arquivos, depurar problemas complexos, executar loops de compilar-testar-corrigir de forma autônoma. A janela de contexto de 1M tokens do Claude Code (com Opus 4.6) permite que o agente mantenha a maioria dos projetos iOS de pequeno a médio porte na memória de trabalho — pela minha experiência, até aproximadamente 50 arquivos dependendo do tamanho dos arquivos.

Sessão 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]

A diferença fundamental em relação ao fluxo de trabalho anterior ao MCP: o agente nunca pede para você compilar manualmente ou colar a saída de erros. O loop compilar-erro-corrigir é autônomo.

2. Codex CLI

O que é: Agente de codificação baseado em terminal da OpenAI. Semelhante em conceito ao Claude Code, mas usa modelos da OpenAI (GPT-4o, o3) e tem um modelo de permissões diferente.

Integração MCP: O Codex suporta MCP via o comando codex mcp add. O Xcode MCP da Apple funciona diretamente:

# Add Apple Xcode MCP to Codex
codex mcp add xcode -- xcrun mcpbridge

O XcodeBuildMCP também funciona com o Codex pelo mesmo comando npx:

# Add XcodeBuildMCP to Codex
codex mcp add XcodeBuildMCP -- npx -y xcodebuildmcp@latest mcp

Melhor para: Operações batch sem interface, integração CI/CD e tarefas onde você quer uma segunda opinião de uma família de modelos diferente. O modo sandbox do Codex executa código em ambientes isolados, o que é útil para operações destrutivas como execuções de suítes de testes que modificam estado.

Principais diferenças em relação ao Claude Code: - Usa modelos da OpenAI em vez de modelos Claude - Tamanhos de janela de contexto e economia de tokens diferentes - Modelo de permissões sandbox-first (mais restritivo por padrão) - Ecossistema MCP menor (menos servidores da comunidade testados) - Sistema de hooks disponível (v0.119.0+), porém menos maduro que o do Claude Code — menos tipos de eventos e sem campo condicional if

Quando usar Codex em vez de Claude Code para iOS:

Use o Codex quando quiser diversidade de modelos — ter um segundo agente revisando código escrito pelo primeiro captura classes diferentes de erros. O fluxo de trabalho collab (Claude constrói, Codex revisa) é eficaz para iOS porque padrões SwiftUI que parecem corretos para uma família de modelos podem ter problemas sutis que outra detecta. Shaders Metal e padrões de concorrência se beneficiam especialmente de revisão com dois modelos.

3. Agentes Nativos do Xcode 26.3

O que é: A Apple integrou agentes de codificação com IA diretamente no painel Intelligence do Xcode. A partir do Xcode 26.3, você pode configurar Claude Agent e Codex como provedores de inteligência em Xcode Settings > Intelligence.

Configuração:

  1. Abra o Xcode 26.3+
  2. Navegue até Settings > Intelligence
  3. Adicione um novo provedor:
  4. Para Claude: Selecione “Claude Agent”, insira sua chave Anthropic API
  5. Para Codex: Selecione “Codex”, insira sua chave OpenAI API
  6. O agente aparece na barra lateral do Intelligence e pode ser invocado inline

Melhor para: Edições rápidas inline, code completion com raciocínio em nível de agente e desenvolvedores que preferem não sair do Xcode. A integração nativa significa que o agente tem acesso direto ao contexto do projeto no Xcode — arquivos abertos, build targets, configuração de scheme — sem necessidade de ponte MCP.

Limitações comparadas aos agentes CLI: - Sem sistema de hooks — você não pode impor formatação ao salvar ou bloquear escritas em .pbxproj - Sem carregamento de CLAUDE.md — o agente não lê seus arquivos de configuração no nível do projeto - Autonomia limitada — o agente opera no arquivo ou seleção atual, não no projeto inteiro - Sem delegação de subagentes — tarefas complexas de múltiplas etapas não podem ser paralelizadas - Sem configuração de servidor MCP — o agente usa apenas as ferramentas integradas do Xcode

Quando usar agentes nativos do Xcode:

Para edições rápidas e pontuais onde alternar para o terminal é overhead. “Adicione uma propriedade computada a este modelo.” “Escreva um teste unitário para esta função.” “Refatore esta view para usar @Observable.” Tarefas que tocam um ou dois arquivos e não exigem um ciclo de compilar-testar.

Para qualquer coisa que exija compilação, testes, refatoração em múltiplos arquivos ou correção autônoma de erros, use um agente CLI com MCP.

Matriz de Comparação de Runtimes

Capacidade Claude Code CLI Codex CLI Xcode 26.3 Nativo
Suporte MCP Completo (79 ferramentas) Completo (79 ferramentas) Apenas ferramentas integradas do Xcode
Sistema de hooks Sim (maduro) Sim (básico, v0.119.0+) Não
CLAUDE.md / config de projeto Sim Equivalente codex.md Não
Compilar-testar-corrigir autônomo Sim (via MCP) Sim (via MCP) Parcial (apenas inline)
Delegação de subagentes Sim (até 10 em paralelo) Não Não
Janela de contexto 1M tokens (Opus 4.6) Varia por modelo Varia por provedor
Operações multi-arquivo Acesso completo ao codebase Acesso completo ao codebase Arquivo / seleção atual
Proteção de .pbxproj Via hooks Manual N/A (usa Xcode nativamente)
Formatação ao salvar Via hooks PostToolUse Ferramentas externas Configurações do Xcode
Capacidade offline Não Não Não
Modelo de custo Uso Anthropic API Uso OpenAI API Uso API do provedor

A recomendação: Use Claude Code CLI como seu runtime principal. Use agentes nativos do Xcode 26.3 para edições rápidas inline. Use Codex CLI para passes de revisão e operações batch. Os três se complementam em vez de competir.


Configuração do MCP: A configuração completa

MCP (Model Context Protocol) é o que transforma um agente de “escreve Swift e torce para que você compile” para “escreve Swift, compila, lê erros estruturados e os corrige.” Esta seção vai além do post no blog — cobrindo ambos os servidores, todos os métodos de instalação, verificação e a configuração do agente que garante que as ferramentas sejam realmente utilizadas.

XcodeBuildMCP: 59 ferramentas para desenvolvimento iOS headless

XcodeBuildMCP encapsula xcodebuild, xcrun simctl e LLDB em 59 ferramentas MCP estruturadas. Funciona sem o Xcode aberto — todo o ciclo de build-teste-debug opera de forma headless através das ferramentas de linha de comando da Apple.

Opções de instalação:

# 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

A flag -s user torna o servidor disponível globalmente em todos os projetos. Omita-a para instalação com escopo de projeto (útil se você quer MCP apenas em projetos iOS, não em projetos web).

A variável de ambiente -e XCODEBUILDMCP_SENTRY_DISABLED=true desabilita a telemetria de relatórios de crash. XcodeBuildMCP inclui Sentry por padrão, que envia dados de erro incluindo caminhos de arquivo. Desative a menos que você queira contribuir com diagnósticos para o projeto.1

Inventário completo de ferramentas (59 ferramentas em 8 categorias):

Categoria Ferramentas O que fazem
Descoberta de projeto discover_projs, list_schemes, list_targets Encontrar arquivos .xcodeproj/.xcworkspace, listar schemes e targets disponíveis
Build build_sim, build_device, build_mac Compilar com saída estruturada de erros/avisos JSON por arquivo e linha
Testes test_sim, test_device Executar testes com resultados de aprovação/reprovação por método
Ciclo de vida do simulador list_sims, boot_sim, shutdown_sim, open_sim, session_set_defaults Criar, iniciar, gerenciar e configurar simuladores
Gerenciamento de dispositivos list_devices, install_device, launch_device Deploy e gerenciamento de dispositivos reais
Debugging debug_attach_sim, debug_attach_device, debug_breakpoint, debug_stack, debug_variables, debug_eval, debug_continue, debug_step, debug_detach Integração completa com LLDB incluindo breakpoints e inspeção de variáveis
Automação de UI snapshot_ui, screenshot, tap, swipe, type_text Interação automatizada e captura visual
Scaffolding de projeto create_project, add_file, add_package Criar projetos e adicionar dependências

As ferramentas mais importantes para o dia a dia:

  1. build_sim — Você vai chamar esta ferramenta centenas de vezes. Ela retorna JSON com erros categorizados por arquivo, linha e severidade. O agente lê o erro, navega até o arquivo e corrige sem você precisar tocar em nada.

  2. test_sim — Retorna resultados por método de teste. O agente sabe exatamente qual teste falhou e por quê, não apenas “os testes falharam.”

  3. list_sims + boot_sim — Gerenciamento de simulador sem precisar memorizar flags do xcrun simctl. O agente descobre os runtimes disponíveis e escolhe um dispositivo apropriado.

  4. discover_projs + list_schemes — Introspecção do projeto. O agente não precisa adivinhar o nome do seu scheme ou a estrutura do workspace.

  5. debug_attach_sim + debug_stack + debug_variables — Debugging remoto via LLDB. O agente pode definir breakpoints, inspecionar variáveis e percorrer o código passo a passo sem que você precise abrir o debugger.

Apple Xcode MCP: 20 ferramentas fazendo ponte com o Xcode

O servidor MCP da Apple vem com o Xcode 26.3 via xcrun mcpbridge. Ele se comunica com um processo Xcode em execução através de XPC (framework de comunicação entre processos da Apple), expondo estado interno que nenhuma ferramenta CLI consegue acessar.

Instalação:

# Standard installation (global)
claude mcp add --transport stdio xcode \
  -s user -- xcrun mcpbridge

# For Codex CLI
codex mcp add xcode -- xcrun mcpbridge

Requer Xcode 26.3+ e um processo Xcode em execução. Se o Xcode não estiver aberto, toda chamada MCP através deste servidor vai falhar ou travar. XcodeBuildMCP não tem essa limitação.

Inventário de ferramentas (20 ferramentas em 5 categorias):

Categoria Ferramentas O que fazem
Operações de arquivo XcodeRead, XcodeWrite, XcodeUpdate, XcodeGlob, XcodeGrep Ler/escrever arquivos dentro do contexto do projeto Xcode
Build e testes BuildProject, GetBuildLog, RunAllTests, RunSomeTests Compilar e testar com o sistema de build interno do Xcode
Diagnósticos XcodeListNavigatorIssues, XcodeRefreshCodeIssuesInFile Diagnósticos de código em tempo real (não apenas erros de build)
Código e documentação ExecuteSnippet, DocumentationSearch Execução de Swift REPL e busca na documentação da Apple
Previews RenderPreview Renderização headless de previews SwiftUI

Ferramentas exclusivas do Apple MCP (não disponíveis no XcodeBuildMCP):

  1. DocumentationSearch — Pesquisa na documentação para desenvolvedores da Apple incluindo sessões da WWDC. Mais rápido e confiável que busca na web para perguntas sobre API da Apple. Pergunte “HKQuantityType(.dietaryWater) é válido?” e obtenha uma resposta definitiva direto da fonte.

  2. ExecuteSnippet — Execução de Swift REPL dentro do contexto do projeto. O agente pode verificar comportamentos da API, testar conversões de tipos e validar expressões sem compilar o app inteiro.

  3. RenderPreview — Renderiza previews SwiftUI de forma headless. O agente pode verificar se uma view renderiza sem erros, embora não consiga avaliar a correção visual (o render é retornado como dados, não inspecionado visualmente).

  4. XcodeListNavigatorIssues — Retorna diagnósticos em tempo real do analisador do Xcode, não apenas erros de build. Detecta problemas como variáveis não utilizadas, potenciais ciclos de retenção e avisos de depreciação que o sistema de build não exibe.

Por que ambos os servidores

Eles se sobrepõem em builds e testes, mas diferem 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                                             
  └─────────────────────┘         └─────────────────────┘       
                                                                 
└─────────────────────────────────────────────────────────────────┘

Use XcodeBuildMCP para: O ciclo de build-teste-debug. Funciona sem o Xcode aberto, consome menos memória do sistema e oferece gerenciamento mais rico de simuladores e dispositivos. Esta é sua ferramenta principal de build.

Use Apple Xcode MCP para: Consultas de documentação, verificação via Swift REPL, renderização de previews SwiftUI e diagnósticos em tempo real. Mantenha o Xcode aberto durante sessões que precisam dessas capacidades.

Na prática: Eu uso XcodeBuildMCP para ~90% das chamadas MCP e Apple Xcode MCP para documentação e verificação via REPL. O agente usa XcodeBuildMCP por padrão para builds e testes porque é mais rápido (sem overhead do processo Xcode) e mais confiável (sem dependência de XPC).

Verificação

Após instalar ambos os servidores, verifique se estão conectados:

# List all configured MCP servers
claude mcp list

# Expected output includes:
# XcodeBuildMCP: npx -y xcodebuildmcp@latest mcp - Connected
# xcode: xcrun mcpbridge - Connected

Se um servidor aparecer como “Disconnected” ou não aparecer:

  1. XcodeBuildMCP não conecta: Verifique se o Node.js está instalado (node --version). O comando npx requer Node.js 18+.
  2. Apple Xcode MCP não conecta: Verifique se o Xcode 26.3+ está instalado e se o comando xcrun mcpbridge funciona no seu terminal. Abra o Xcode pelo menos uma vez para aceitar o contrato de licença.
  3. Ambos não aparecem: Reinicie o Claude Code (claude em um novo terminal). Servidores MCP registrados durante uma sessão podem não aparecer até a reinicialização.

Ensinando o agente a usar MCP

Instalar servidores MCP é necessário, mas não suficiente. Sem orientação explícita, o agente pode voltar a executar xcodebuild via Bash (saída não estruturada, desperdício de tokens de contexto) ou usar busca na web para documentação da Apple (mais lento, menos confiável).

Adicione isto ao seu CLAUDE.md ou definição de agente:

## Build e teste — sempre use MCP

Prefira as ferramentas MCP em vez de comandos shell diretos para TODAS as operações de build:

- **Build**: `build_sim` / `build_device` (NÃO `xcodebuild` via Bash)
- **Teste**: `test_sim` / `test_device` (NÃO `xcodebuild test` via Bash)
- **Simuladores**: `list_sims`, `boot_sim`, `open_sim` (NÃO `xcrun simctl` via Bash)
- **Debug**: `debug_attach_sim`, `debug_stack`, `debug_variables`
- **Documentação Apple**: `DocumentationSearch` (NÃO WebSearch para APIs da Apple)
- **Verificação Swift**: `ExecuteSnippet` (NÃO `swift` via Bash)
- **Previews**: `RenderPreview` para verificação headless de SwiftUI

MCP retorna JSON estruturado. Bash retorna texto não estruturado.
Dados estruturados significam menos tokens consumidos e melhor diagnóstico de erros.

Essa orientação garante que o agente recorra primeiro às ferramentas MCP. Sem ela, você vai observar o agente construindo longos comandos xcodebuild via Bash, consumindo milhares de tokens de contexto para interpretar a saída e, às vezes, identificando incorretamente o erro real.


Padrões de CLAUDE.md para projetos iOS

Seu CLAUDE.md é o arquivo mais importante do projeto para desenvolvimento assistido por agentes. É o documento de onboarding do agente — a diferença entre um novo contratado que leu a documentação de arquitetura e um que está adivinhando.

Todo projeto iOS que eu mantenho tem um CLAUDE.md. Aqui estão os padrões que funcionam, extraídos de todos os 8 apps.

As seções essenciais

Todo CLAUDE.md para iOS precisa dessas seis seções. Todo o resto é opcional.

1. Identidade do projeto

# 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 que isso importa: o agente precisa saber o deployment target antes de escrever qualquer código. Um agente mirando iOS 17 vai usar NavigationView e @ObservedObject. Um agente mirando iOS 26 vai usar NavigationStack e @Observable. O bundle ID importa para entitlements e configuração do HealthKit. A versão do Swift determina o modelo de concorrência (async/await vs. completion handlers, strict concurrency vs. lenient).

2. Estrutura de arquivos com anotações 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


Os comentários inline após cada nome de arquivo não são decoração. São a documentação de maior alavancagem que você pode escrever. Quando o agente está decidindo onde adicionar um novo recurso, essas anotações o guiam até o arquivo correto na primeira tentativa, em vez de precisar ler todos os arquivos para entender o layout do projeto.

Anti-padrão: Listar arquivos sem anotações. TimerManager.swift não diz nada ao agente sobre se ele lida com estado, UI ou ambos. TimerManager.swift # Timer state, logic, and repeat handling diz exatamente o que pertence ali e o que não pertence.

3. Comandos de build e teste

## Build & Test

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

Run tests:

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

Run tvOS tests:

xcodebuild -scheme ReturnTV -destination 'platform=tvOS Simulator,name=Apple TV' test

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

Inclua os comandos brutos mesmo que o agente deva preferir MCP. Os comandos brutos servem como documentação de fallback e tornam explícitos os nomes dos schemes e destinations.

#### 4. Padrões e regras principais

```markdown

## Key Patterns

### Observable Architecture
- ALL view models use `@Observable` (NEVER `ObservableObject`)
- ALL navigation uses `NavigationStack` (NEVER `NavigationView`)
- State management via `@Observable` classes with `@MainActor` isolation

### Settings Pattern
- Centralized `Settings.shared` singleton
- All settings bounded to valid ranges with validation
- Sound names validated against whitelist
- Thread-safe access via @MainActor

### Audio System
- `AVAudioPlayer` with `.playback` category (plays in silent mode)
- Silent audio loop for background execution
- Bell playback with completion callbacks and token-based staleness

Esses padrões evitam que o agente introduza inconsistências. Sem documentação explícita de padrões, o agente às vezes usará ObservableObject em um arquivo e @Observable em outro, ou criará um novo mecanismo de configurações em vez de usar o singleton Settings.shared existente.

5. Coisas que o agente nunca deve fazer

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

Proibições explícitas são mais eficazes do que expectativas implícitas. O agente segue restrições negativas de forma mais confiável do que sugestões positivas, porque elas são binárias (faça / não faça) em vez de heurísticas (prefira isso / às vezes use aquilo).

6. Contexto específico do framework

Esta seção varia por app. Inclua-a para qualquer framework que tenha configuração não óbvia:

Para apps com 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 com 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 com 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 com 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)

Aqui está um exemplo anotado mostrando como todas as seis seções funcionam juntas para um app moderadamente complexo. Este é o padrão de CLAUDE.md que eu uso para o Banana List, um app de lista de compras com 53 arquivos, sincronização via iCloud e um servidor MCP personalizado que expõe os dados do app para o 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

## Estrutura de arquivos

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

### Relacionamentos
- `GroceryList` possui muitos `GroceryItem` (exclusão em cascata)
- `GroceryItem` pertence a um `GroceryList` (obrigatório)
- `GroceryItem` possui `Category` opcional
- `Category` possui muitos `GroceryItem` (nulificar ao excluir)

### Configuração do container
```swift
@main
struct BananaListApp: App {
    var body: some Scene {
        WindowGroup {
            ListsView()
        }
        .modelContainer(for: [GroceryList.self, GroceryItem.self, Category.self])
    }
}

Padrões de consulta

  • Listas: @Query(sort: \GroceryList.name) var lists: [GroceryList]
  • Itens ativos: @Query(filter: #Predicate { !$0.isCompleted })
  • Por categoria: filtrar em memória após a busca (limitações do predicate do SwiftData)

Build e teste

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

Prefira as ferramentas MCP (build_sim, test_sim) em vez de comandos diretos.

Padrões principais

Observable + SwiftData

  • Classes @Model do SwiftData são automaticamente Observable
  • NÃO adicione @Observable a classes @Model (redundante, causa avisos)
  • Use @Bindable para bindings bidirecionais com propriedades do modelo em formulários
  • Use @Query em views, modelContext.fetch() em código fora de views

Sincronização com iCloud

  • Automática via integração do SwiftData com CloudKit
  • Resolução de conflitos: última escrita vence (padrão do CloudKit)
  • Status de sincronização exposto via CloudSyncManager.shared.syncState
  • Teste a sincronização executando em dois simuladores com a mesma conta iCloud

Arquitetura do servidor MCP

  • Executa como um servidor WebSocket local na porta 8765
  • Expõe 6 ferramentas: listAll, getList, createList, addItem, completeItem, deleteItem
  • Claude Desktop conecta via configuração MCP em ~/.config/claude-desktop/config.json

Regras

  • NUNCA modifique o conteúdo de .pbxproj ou .xcodeproj
  • NUNCA altere o esquema do modelo sem atualizar SampleData.swift
  • NUNCA use ObservableObject — modelos SwiftData já são Observable
  • NUNCA use @StateObject — use @State com classes @Observable
  • NUNCA use NavigationView — sempre NavigationStack
  • NUNCA adicione a macro @Observable a classes @Model
  • SEMPRE use @Bindable para bindings de formulário com propriedades do modelo
  • SEMPRE teste alterações de sincronização com iCloud em duas instâncias de simulador
### CLAUDE.md real: Reps (app SwiftData mínimo — 14 arquivos)

Para projetos pequenos, o CLAUDE.md pode ser conciso. Este é o padrão do Reps, um rastreador de treinos com 14 arquivos. Note como mesmo um CLAUDE.md curto cobre todas as seis seções essenciais:

```markdown
# Reps - Workout Tracking

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

## File Structure

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

## Build & Test

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

SwiftData Relationships

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

Rules

  • NEVER modify .pbxproj
  • NEVER use ObservableObject — use @Observable
  • NEVER use NavigationView — use NavigationStack
  • @Model classes are already Observable — do not add @Observable macro
  • Use @Bindable for form bindings to model properties
São 40 linhas de CLAUDE.md para um projeto de 14 arquivos. Leva 10 minutos para escrever e economiza horas de confusão do agente.

### CLAUDE.md real: Starfield Destroyer (SpriteKit + Metal — 32 arquivos)

Projetos de jogos exigem mais contexto específico do framework. O agente precisa entender o grafo de cena, as categorias de física e a máquina de estados do jogo:

```markdown
# Starfield Destroyer - Space Shooter

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

## Game Overview

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

## File Structure

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

## SpriteKit Scene Hierarchy

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

## Physics Categories

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

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

Game State Machine

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

Metal Post-Processing

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

Build & Test

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

## Regras

- NUNCA modifique .pbxproj
- NUNCA modifique bitmasks de PhysicsCategory (quebra toda a detecção de colisão)
- NUNCA altere a ordenação z da hierarquia de cena sem entender a ordem de renderização
- NUNCA modifique ShaderTypes.h sem atualizar tanto as referências em Swift quanto em Metal
- Adicione novos inimigos criando subclasses de EnemyShip, não modificando-o
- Pool de projéteis: recicle via removeFromParent() + re-add, nunca aloque novos
- Game Center: sempre verifique isAuthenticated antes de enviar pontuações

CLAUDE.md real: amp97 (Metal + Visualização de Áudio — 41 Arquivos)

Projetos Metal precisam do maior nível de contexto específico de framework porque os agentes não conseguem verificar saída visual:

# amp97 - Audio Visualizer

**Bundle ID:** `com.941apps.amp97`
**Target:** iOS 26+
**Architecture:** Metal render pipeline + AVAudioEngine analysis
**Swift version:** 6.2

## Architecture

Audio Input (microphone/file) → AVAudioEngine tap → FFT (vDSP) → Frequency/amplitude buffers → Metal compute shader (analysis) → Metal render pipeline (visualization) → CADisplayLink (60fps) → MTKView

## File Structure

amp97/ ├── amp97App.swift # App entry ├── Audio/ │ ├── AudioEngine.swift # AVAudioEngine setup, tap installation │ ├── FFTProcessor.swift # vDSP FFT, frequency bin extraction │ ├── AudioBuffer.swift # Ring buffer for audio data │ └── MicrophoneManager.swift # Microphone permission, session config ├── Rendering/ │ ├── MetalView.swift # MTKView wrapper for SwiftUI │ ├── Renderer.swift # Main render loop, pipeline state │ ├── ShaderLibrary.swift # Compiled shader management │ ├── BufferManager.swift # Triple-buffered uniform updates │ └── TextureManager.swift # Offscreen render targets ├── Shaders/ │ ├── Shaders.metal # Vertex + fragment shaders │ ├── AudioCompute.metal # Audio analysis compute kernel │ ├── PostProcess.metal # Bloom, color grading │ └── ShaderTypes.h # Shared uniforms (bridging header) ├── Visualizations/ │ ├── WaveformViz.swift # Oscilloscope-style waveform │ ├── SpectrumViz.swift # Frequency spectrum bars │ ├── CircularViz.swift # Radial visualization │ └── VizSelector.swift # Visualization switching ├── Views/ │ ├── MainView.swift # Full-screen viz with overlays │ ├── ControlsOverlay.swift # Play/pause, viz selection, gain │ └── SettingsView.swift # Audio source, sensitivity └── Extensions/ ├── SIMD+Extensions.swift # Vector math helpers └── Color+Metal.swift # UIColor → float4 conversion

## Metal Pipeline

### Uniforms (ShaderTypes.h)
```c
typedef struct {
    float time;
    float2 resolution;
    float audioLevel;       // 0.0-1.0 RMS amplitude
    float frequencyBins[64]; // FFT output, normalized
    float4x4 transform;
} Uniforms;

Render Pipeline

  1. Compute pass: AudioCompute.metal processes FFT data → texture
  2. Render pass: Shaders.metal reads texture + uniforms → visualization
  3. Post-process pass: PostProcess.metal applies bloom → final output

Buffer Management

  • Triple buffering with DispatchSemaphore(value: 3)
  • Uniforms updated per-frame on CPU, consumed by GPU 1-2 frames later
  • Audio data ring buffer: 4096 samples, lock-free single producer/consumer

Rules

  • NEVER modify ShaderTypes.h without updating BOTH Swift and Metal sides
  • NEVER exceed 64 frequency bins (fixed buffer size in shader)
  • NEVER test Metal visual output in simulator — device only
  • NEVER modify the audio engine tap format (48kHz, mono, float32)
  • Triple buffer discipline: always signal semaphore in completion handler
  • Audio session: .playAndRecord category with .defaultToSpeaker option
### Escalando o CLAUDE.md com o tamanho do projeto

O nível adequado de detalhamento depende da quantidade de arquivos e da complexidade do framework:

| Tamanho do Projeto | Profundidade do CLAUDE.md | Exemplo |
|-------------|----------------|---------|
| **Pequeno (< 20 arquivos)** | Identidade + lista de arquivos + regras | Reps (14 arquivos): padrões básicos de SwiftData, comandos de build, proibições |
| **Médio (20-40 arquivos)** | + Contexto do framework + padrões-chave | TappyColor (30 arquivos): hierarquia de cena SpriteKit, categorias de física, game loop |
| **Grande (40+ arquivos)** | + Diagramas de arquitetura + mapas de relacionamento + info multi-target | Return (63 arquivos): arquitetura cross-platform, diagrama de sincronização de sessão, diferenças por plataforma |
| **Especializado (Metal/GPU)** | + Diagramas de pipeline + definições de tipos compartilhados + layouts de buffer | amp97 (41 arquivos): estágios do render pipeline, struct de uniforms, gerenciamento de buffers |

O custo de documentar demais é quase zero (o agente ignora o que não precisa). O custo de documentar de menos é alto (o agente inventa padrões que conflitam com seu codebase).

### Checklist do CLAUDE.md

Use este checklist ao criar ou auditar um CLAUDE.md para um projeto iOS:

- [ ] Bundle ID e deployment target especificados
- [ ] Versão do Swift e padrão de arquitetura nomeados
- [ ] Estrutura de arquivos com anotações de propósito inline
- [ ] Comando de build com scheme e destination corretos
- [ ] Comando de teste com scheme e destination corretos
- [ ] Preferência de MCP anotada ("prefer build_sim over xcodebuild")
- [ ] Regra de @Observable (nunca ObservableObject)
- [ ] Regra de NavigationStack (nunca NavigationView)
- [ ] Proibição de .pbxproj
- [ ] Contexto específico do framework (permissões do HealthKit, relacionamentos SwiftData, hierarquia SpriteKit, pipeline Metal)
- [ ] Guards de disponibilidade de plataforma documentados (#if canImport, #if os)
- [ ] Singletons-chave e padrões compartilhados documentados
- [ ] Limitações conhecidas ou pegadinhas anotadas

---

## Sua primeira sessão com agente

Com MCP configurado e um CLAUDE.md no seu projeto, aqui está um passo a passo de uma primeira sessão eficaz. Este exemplo usa Claude Code CLI, mas o fluxo de trabalho se aplica a qualquer runtime.

### Passo 1: Verifique se o agente consegue ver seu projeto

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

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

    This is Return, a zen meditation timer for iOS 26+, watchOS, and tvOS.
    Available schemes: Return, ReturnWatch, ReturnTV, ReturnTests.
    Primary scheme for iOS: Return.
Se o agente não fizer referência ao conteúdo do seu CLAUDE.md, verifique se o arquivo está na raiz do projeto (mesmo diretório do `.xcodeproj` ou `Package.swift`).

### Passo 2: Execute um build de verificação

You: Build the Return scheme for iOS simulator and report results.

Claude: [calls list_sims — finds iPhone 16 Pro on iOS 26.2] [calls boot_sim — boots the simulator] [calls build_sim — builds the project]

    Build succeeded. 63 source files compiled.
    2 warnings:
    - HomeView.swift:132 — UIScreen.main deprecated in iOS 26.0
    - LogWaterIntent.swift:61 — Result of try? is unused
    0 errors.
### Passo 3: Execute os testes

You: Run all tests and report pass/fail.

Claude: [calls test_sim]

    12 tests executed:
    ✓ TimerManagerTests (5/5 passed)
    ✓ SettingsTests (4/4 passed)
    ✓ ConstantsTests (3/3 passed)
    All tests passed.
### Passo 4: Implemente um recurso

You: Add a new “Rain” theme to the theme system. Follow the existing pattern in Theme.swift and ThemeManager.swift. Include a rain ambient sound. Build and test after implementation.

Claude: [reads Theme.swift — understands Theme struct pattern] [reads ThemeManager.swift — understands theme registration] [reads existing theme definitions] [adds Rain theme to Theme.swift following existing pattern] [registers Rain theme in ThemeManager.swift] [calls build_sim — build succeeds] [calls test_sim — all tests pass]

    Added Rain theme:
    - Theme.swift: new `static let rain` with video, cover, ambient
    - ThemeManager.swift: added to `allThemes` array
    - Build: success (0 errors, 2 existing warnings)
    - Tests: 12/12 passed

    Note: You'll need to add rain_ambient.wav to the project
    and add the new Theme.swift changes to the Xcode target manually
    (I did not modify .pbxproj).
A observação do agente sobre não modificar .pbxproj é resultado das regras no CLAUDE.md. Sem essa regra, o agente tentaria modificar o arquivo de projeto e provavelmente o corromperia.

---

## O que os agentes fazem bem no iOS

Essas são as tarefas em que os agentes consistentemente produzem resultados corretos e prontos para produção, com revisão humana mínima.

### Views e Modifiers do SwiftUI

Os agentes têm profundo reconhecimento de padrões para a sintaxe declarativa do SwiftUI. Composição de views, cadeias de modifiers, bindings de estado e layout  tudo isso se encaixa bem nos dados de treinamento do agente, porque a superfície de API do SwiftUI é bem documentada e os padrões são altamente consistentes.

**Onde os agentes se destacam:**
- Construir novas views a partir de uma descrição ("crie uma tela de configurações com toggles para X, Y, Z")
- Aplicar cadeias de modifiers (`.glassEffect()`, `.sensoryFeedback()`, `.navigationTitle()`)
- Converter entre padrões de layout (VStack para LazyVGrid, List para ScrollView)
- Implementar bindings de formulário com `@Bindable` para modelos SwiftData
- Construir preview providers com dados de exemplo

**Exemplo de prompt que produz resultados excelentes:**

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.

A especificidade importa. "Crie uma view de configurações" produz um resultado genérico. "Crie uma SettingsView que siga o padrão existente em SettingsSheet.swift" produz um resultado consistente com sua base de código.

### Modelos e Queries do SwiftData

Os agentes lidam bem com a macro `@Model` do SwiftData, relacionamentos e padrões de `@Query`. A natureza declarativa do framework (similar ao Django ORM ou SQLAlchemy) se encaixa bem nos padrões que o agente  viu em diversas bases de código.

**Onde os agentes se destacam:**
- Definir classes `@Model` com relacionamentos
- Escrever `@Query` com sort descriptors e predicados
- Implementar operações CRUD via `modelContext`
- Planos de migração entre versões de schema
- Dados de preview e fixtures de teste

**Onde os agentes precisam de orientação:**
- Expressões complexas de `#Predicate` (a DSL de predicados do SwiftData tem limitações que o agente nem sempre conhece  documente as limitações conhecidas no CLAUDE.md)
- Configuração de sincronização com CloudKit (automática via SwiftData, mas o agente pode tentar implementar sincronização manual)

### Testes unitários

Testes unitários escritos por agentes são consistentemente de alta qualidade para projetos iOS. O agente entende os padrões do XCTest, métodos de teste assíncronos e o ciclo de vida de 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)

O agente produz casos de teste XCTest bem estruturados com `setUp()` e `tearDown()`, asserções apropriadas e tratamento assíncrono para testes baseados em timer.

### Refatoração e aplicação de padrões

Os agentes se destacam em refatoração mecânica: extrair views em componentes, converter `ObservableObject` para `@Observable`, migrar de `NavigationView` para `NavigationStack` e aplicar padrões consistentes em múltiplos arquivos.

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.

O agente trabalha metodicamente em cada arquivo, aplica a transformação corretamente e mantém a funcionalidade existente. Esse é um trabalho de alto impacto  uma refatoração que levaria uma hora de edição manual é concluída em minutos com precisão quase perfeita.

### Diagnóstico de erros de build via MCP

Com a saída estruturada do MCP, os agentes diagnosticam erros de build mais rápido que a maioria dos desenvolvedores. O agente  o JSON de erro, identifica o arquivo e a linha exatos, entende a mensagem de erro e aplica a correção  frequentemente em uma única iteração.

**Erros que os agentes corrigem de forma autônoma:**
- Imports ausentes
- Incompatibilidade de tipos
- Lacunas na conformidade de protocols
- Uso de API depreciada (com substituição)
- Parâmetros obrigatórios de inicializador ausentes
- Violações de controle de acesso

**Erros em que os agentes precisam de ajuda:**
- Resolução ambígua de tipos (múltiplos módulos definem o mesmo tipo)
- Falhas complexas em restrições de generics
- Erros de expansão de macros (o agente não consegue ver a saída expandida da macro)

### Gerenciamento do Simulator

Os agentes lidam bem com o ciclo de vida do simulador via MCP:

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

O agente chama `list_sims` para encontrar runtimes disponíveis, `boot_sim` para iniciar o simulador, `build_sim` para compilar e instalar, e `screenshot` para capturar  tudo através de chamadas estruturadas ao MCP.

---

## O que os agentes fazem mal no iOS

Uma análise honesta de onde os agentes falham. Conhecer esses limites evita frustração e desperdício de tokens.

### Modificações em arquivos .pbxproj — NUNCA

Esta é a regra mais importante no desenvolvimento iOS com agentes. O arquivo `.pbxproj` é a configuração de projeto do Xcode  um arquivo de texto estruturado com referências UUID, listagens de fases de build e associação de targets. É nominalmente legível por humanos, mas praticamente impossível de ser analisado por agentes de IA.

**Por que os agentes falham com .pbxproj:**
- O arquivo usa um formato personalizado (não é JSON, não é YAML, não é XML) com significado posicional
- Cada entrada é referenciada cruzadamente por UUID  adicionar um arquivo exige atualizar 3-5 seções diferentes de forma consistente
- Um único caractere fora do lugar corrompe o arquivo de projeto inteiro
- A resolução de conflitos de merge do Xcode para .pbxproj  é frágil  edições de agentes pioram a situação

**O que acontece quando um agente edita .pbxproj:**
1. A edição parece ter dado certo (o agente reporta "arquivo atualizado")
2. O Xcode se recusa a abrir o projeto ("The project file is corrupted")
3. Você gasta de 15 a 60 minutos recuperando do histórico do git
4. Você aprende a adicionar o hook PreToolUse (veja [Hooks](#hooks-for-ios-development))

**O fluxo de trabalho:** O agente cria arquivos Swift. Você os adiciona ao projeto do Xcode manualmente (arraste para o Xcode, ou File > Add Files). Isso leva 5 segundos por arquivo e evita horas de recuperação.

**Para projetos com Swift Package Manager:** Essa limitação é menos severa. O `Package.swift` é um arquivo Swift padrão que agentes podem editar de forma confiável. Se o seu projeto usa SPM exclusivamente (sem .xcodeproj), o agente pode gerenciar toda a estrutura do projeto.

### Edições complexas em Interface Builder / Storyboard

Se o seu projeto usa Interface Builder (arquivos `.xib`) ou Storyboards (arquivos `.storyboard`), os agentes não conseguem editá-los de forma significativa. São arquivos XML com UUIDs gerados automaticamente, referências de constraints e conexões de outlets projetados para edição visual, não edição de texto.

**A solução:** Use SwiftUI exclusivamente para novas views. Se o seu projeto tem arquivos legados de Interface Builder, deixe-os como estão e construa a nova UI em SwiftUI.

### Otimização de performance

Agentes escrevem código correto, mas não necessariamente performático. Eles não conseguem fazer profiling do seu app, identificar gargalos ou medir taxas de quadros. Otimização de performance requer:

1. Profiling com Instruments (ferramenta visual, não acessível a agentes)
2. Entendimento das características de GPU/CPU do dispositivo específico
3. Mudanças iterativas orientadas por medições

**Onde isso aparece:**
- Otimização de shaders Metal (o agente escreve Metal válido, mas não consegue medir o tempo de quadro da GPU)
- Complexidade do body de views SwiftUI (o agente cria views profundamente aninhadas que causam overhead de redesenho)
- Otimização de fetch em Core Data / SwiftData (o agente escreve queries corretas que podem ser lentas em grandes conjuntos de dados)

**A solução:** Use agentes para implementação, faça profiling manualmente com Instruments, e depois peça ao agente para aplicar otimizações específicas que você identificou.

### Code signing e provisionamento

Agentes não conseguem depurar problemas de code signing além de ler a mensagem de erro. Gerenciamento de provisioning profiles, criação de certificados, configuração de entitlements e submissão à App Store são fluxos de trabalho fundamentalmente operados por humanos, que envolvem o Apple Developer portal, o Keychain Access e a interface de assinatura do Xcode.

**O que o agente :** "Signing for 'Return' requires a development team."

**O que o agente não consegue ver:** Se o seu certificado expirou, se o provisioning profile inclui o dispositivo, se o bundle ID corresponde ao App ID, ou se o seu arquivo de entitlements está correto.

**A solução:** Gerencie toda a assinatura na aba Signing & Capabilities do Xcode. Não peça aos agentes para depurar falhas de assinatura.

### Depuração complexa de shaders Metal

Agentes escrevem Metal Shading Language (MSL) sintaticamente correto, mas não conseguem verificar a saída visual ou depurar problemas do lado da GPU. Shaders Metal executam na GPU  o agente não tem mecanismo de feedback para saber se o shader produz resultados visuais corretos.

**O que agentes conseguem fazer com Metal:**
- Escrever vertex e fragment shaders a partir de descrições
- Configurar o pipeline de renderização Metal em Swift
- Criar compute shaders para operações de dados em paralelo
- Corrigir erros de compilação em arquivos `.metal`

**O que agentes não conseguem fazer com Metal:**
- Verificar a correção visual da saída do shader
- Depurar performance da GPU (tempo de quadro, ocupação, largura de banda de memória)
- Diagnosticar artefatos visuais (banding, problemas de precisão, espaço de cor incorreto)
- Testar em diferentes arquiteturas de GPU (diferenças de comportamento entre A-series e M-series)

**A solução:** Teste shaders Metal em dispositivos físicos. A implementação Metal do Simulator não é representativa do comportamento da GPU no dispositivo. Use o GPU Frame Capture do Xcode para depuração visual.

### Verificação visual de layout

Agentes não conseguem ver a UI do seu app. Eles escrevem código de layout SwiftUI e podem verificar que ele compila, mas não conseguem dizer se a tela resultante está visualmente correta. Uma view que renderiza 10 pixels fora do centro, usa o peso de fonte errado ou tem elementos sobrepostos não produz erro de build e passa em todos os testes de lógica.

**A solução:** Revise mudanças de UI visualmente. Use SwiftUI Previews no Xcode (ou `RenderPreview` via Apple MCP para renderização headless) para verificar o layout. Considere testes de snapshot com bibliotecas como swift-snapshot-testing para detecção automatizada de regressões visuais.

---

## Hooks para desenvolvimento iOS

Hooks são comandos shell que executam de forma determinística em pontos específicos do fluxo de trabalho do agente. Eles são o mecanismo de aplicação  a diferença entre "por favor, não edite o .pbxproj" (uma sugestão que o agente pode ignorar) e "você não pode editar o .pbxproj" (um bloqueio rígido).

Para contexto sobre o sistema de hooks, consulte o [Claude Code guia de hooks](/blog/claude-code-hooks-tutorial). Esta seção cobre padrões de hooks específicos para iOS.

### PreToolUse: Bloquear escritas no .pbxproj

O hook mais importante em qualquer projeto iOS. Ele bloqueia o agente de escrever em arquivos `.pbxproj`, diretórios `.xcodeproj/` e outros arquivos gerenciados pelo Xcode:

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

Coloque isso em .claude/settings.json na raiz do projeto ou em ~/.claude/settings.json para proteção global.

Como funciona: Quando o agente tenta usar a ferramenta Edit ou Write em qualquer arquivo que corresponda ao padrão, o hook executa, detecta o caminho do arquivo, imprime um aviso no stderr e encerra com código 2 (que bloqueia o uso da ferramenta). O agente recebe a mensagem de erro e ajusta sua abordagem.

O que ele captura: - Edições diretas no .pbxproj - Qualquer arquivo dentro dos diretórios .xcodeproj/ ou .xcworkspace/ - Arquivos do Interface Builder (.xib, .storyboard)

PostToolUse: Formatação automática com SwiftFormat

Formate automaticamente arquivos Swift sempre que o agente escrever ou editá-los:

{
  "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: O SwiftFormat precisa estar instalado (brew install swiftformat).

Por que isso importa: Agentes produzem Swift sintaticamente correto, mas não seguem convenções de formatação de forma consistente. O SwiftFormat normaliza indentação, posicionamento de chaves e ordenação de imports. O hook de formatação automática garante que todo arquivo Swift que o agente tocar seja formatado antes de você vê-lo.

Opcional: Adicione um arquivo de configuração .swiftformat na raiz do projeto para personalizar as regras de formatação:

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

PostToolUse: Executar SwiftLint automaticamente

Se você usa SwiftLint, execute-o após cada edição de arquivo 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'"
      }
    ]
  }
}

O || true impede que avisos do lint bloqueiem o agente. Se você quiser que violações do lint bloqueiem, remova-o.

PostToolUse: Build automático após alterações

Para loops de feedback agressivos, dispare um build após cada alteração em arquivo 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'"
      }
    ]
  }
}

Atenção: Isso é custoso. Cada edição de arquivo dispara um build. Use com moderação — é mais útil durante sessões de depuração onde você quer feedback imediato do build. Para desenvolvimento normal, deixe o agente disparar builds manualmente via MCP quando estiver pronto.

PreToolUse: Bloquear modificações em entitlements

Proteja seu arquivo de entitlements contra modificações acidentais do 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'"
      }
    ]
  }
}

Configuração combinada de hooks para iOS

Aqui está o .claude/settings.json completo que uso em todos os projetos 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'"
      }
    ]
  }
}

Isso oferece duas garantias: 1. O agente não pode corromper arquivos de projeto do Xcode (bloqueio PreToolUse) 2. Todo arquivo Swift que o agente tocar é formatado automaticamente (formatação PostToolUse)


Padrões de arquitetura que funcionam com agentes

Nem todas as arquiteturas Swift são igualmente compatíveis com agentes. Estes padrões produzem os melhores resultados porque são explícitos, consistentes e bem representados nos dados de treinamento.

@Observable (nunca ObservableObject)

Projetos com alvo iOS 26+ devem usar @Observable exclusivamente. Este é tanto o padrão moderno quanto o padrão compatível com 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 que @Observable é compatível com agentes: O padrão é mais simples (não precisa de anotações @Published), o modelo de propriedade é mais claro (@State em vez de @StateObject vs. @ObservedObject), e os agentes produzem menos bugs com ele porque há menos peças móveis.

Documente isso no CLAUDE.md: Mesmo com iOS 26 como alvo, os agentes ocasionalmente revertem para padrões ObservableObject dos seus dados de treinamento. A proibição explícita evita isso.

// CORRECT
NavigationStack {
    List(items) { item in
        NavigationLink(value: item) {
            ItemRow(item: item)
        }
    }
    .navigationDestination(for: Item.self) { item in
        ItemDetailView(item: item)
    }
}

// WRONG
NavigationView {
    List(items) { item in
        NavigationLink(destination: ItemDetailView(item: item)) {
            ItemRow(item: item)
        }
    }
}

NavigationStack é iOS 16+ e o único padrão de navegação que você deve usar para código novo. O padrão type-safe navigationDestination(for:) impede que o agente crie links de navegação incorretos.

SwiftData para persistência

Modelos SwiftData são o padrão de persistência mais limpo para desenvolvimento assistido 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
    }
}

Regras essenciais para agentes trabalhando com SwiftData: 1. Classes @Model são automaticamente Observable — não adicione @Observable 2. Use @Bindable para bindings de formulários: @Bindable var item: GroceryItem 3. Use @Query em views para dados reativos: @Query var items: [GroceryItem] 4. Use modelContext.fetch() em código fora de views 5. Exclusões de relacionamentos precisam de regras explícitas: .cascade, .nullify, .deny

Concorrência no Swift 6.2

Use concorrência estrita do Swift 6.2 para projetos novos:

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

Orientações para agentes sobre concorrência: - Marque todos os view models como @MainActor (previne avisos de data race) - Use async/await para todo trabalho assíncrono (sem completion handlers) - Torne value types Sendable para transferências entre actors - Use Task { } em views para inicialização assíncrona - Use nonisolated somente quando houver uma necessidade de performance comprovada por medição

Sistema de design Liquid Glass (iOS 26+)

O iOS 26 introduziu o sistema de design Liquid Glass. Os agentes lidam bem com ele quando recebem orientação 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()

Inclua no CLAUDE.md: “Use .glassEffect() em fundos de seções e containers de cards. As barras de navegação adotam automaticamente o material glass no iOS 26. Não recrie manualmente efeitos glass com materiais customizados — use o modificador do sistema.”


Contexto específico por framework

Cada framework da Apple tem considerações específicas para agentes. Esta seção cobre os frameworks usados nos 8 apps.

HealthKit

Apps que utilizam: Return, Water

HealthKit exige tratamento cuidadoso de permissões e guards 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
        }
    }
}

Regras para agentes com HealthKit: - Sempre proteja com HKHealthStore.isHealthDataAvailable() - Nunca assuma autorização — verifique a cada escrita - Use #if canImport(HealthKit) para código multiplataforma (HealthKit não está disponível no tvOS) - Nunca armazene dados de saúde localmente além do que o HealthKit fornece - Inclua tanto NSHealthShareUsageDescription quanto NSHealthUpdateUsageDescription no Info.plist

SpriteKit

Apps que utilizam: TappyColor, Starfield Destroyer

O modelo de scene graph do SpriteKit exige orientação explícita para 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)

Pontos fortes dos agentes com SpriteKit: - Criar sequências e grupos de SKAction - Configurar physics bodies e detecção de contato - Implementar máquinas de estado do jogo - Construir overlays de HUD

Pontos fracos dos agentes com SpriteKit: - Game loops sensíveis a performance (o agente adiciona trabalho desnecessário por frame) - Simulações de física complexas (física customizada supera SKPhysicsBody em precisão) - Ajuste de efeitos de partículas (visual, requer iteração)

Metal

Apps que utilizam: amp97, Water, Starfield Destroyer

Metal é o framework onde os agentes mais enfrentam dificuldades. O modelo de programação GPU é fundamentalmente diferente do Swift no lado da CPU, e os agentes não conseguem verificar a saída 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

O que incluir no CLAUDE.md para projetos Metal: - A definição da struct Uniforms (compartilhada entre Swift e MSL) - O padrão de configuração do render pipeline state - Índices de buffers e seus propósitos - Quais shaders existem e o que cada um faz - Problemas de precisão conhecidos (half vs. float)

Live Activities

Apps que utilizam: Return

Live Activities exigem configuração específica que os agentes lidam bem uma 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 utilizam: 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)

Padrões multiplataforma

O Return abrange iOS, watchOS e tvOS. O desenvolvimento multiplataforma com agentes exige documentação explícita dos limites de cada plataforma.

Organização de código compartilhado

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

Regra para agentes: “Se um arquivo está em Shared/, as alterações afetam todas as plataformas. Se um arquivo está em um diretório de plataforma, as alterações são isoladas. Sempre verifique em qual diretório o arquivo está antes de modificá-lo.”

Guards de disponibilidade 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

Orientação para agentes: “Sempre use guards #if canImport() ou #if os() ao utilizar frameworks específicos de plataforma. Não assuma que um framework está disponível em todos os targets.”

Adaptação 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
    }
}

Fluxos de trabalho avançados

Loops autônomos de build-teste-correção

O padrão mais poderoso: forneça ao agente uma especificação de funcionalidade e deixe-o iterar pelos ciclos de build-teste-correção 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.

O agente escreve código, faz build via MCP, lê os erros estruturados, corrige-os e repete. Uma funcionalidade que exigiria de 5 a 10 ciclos humanos de build-erro-correção é concluída em um único loop autônomo.

Quando funciona: Funcionalidades bem definidas com critérios de aceitação claros.

Quando falha: Funcionalidades abertas (“deixe bonito”), código sensível a performance ou qualquer coisa que exija verificação visual.

Delegação de subagentes para iOS

O sistema de subagentes do Claude Code funciona para projetos 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.

O subagente explora documentação e padrões de código em uma janela de contexto separada, retorna um resumo, e a sessão principal implementa a recomendação. Isso evita que a pesquisa consuma seu contexto primário.

Aplicação de padrões entre apps

Quando você mantém múltiplos apps iOS com padrões consistentes, agentes podem aplicar padrões de um app para outro:

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.

O agente lê o padrão de origem, compreende a estrutura e cria uma implementação consistente no projeto de destino.

Revisão com dois agentes (Claude + Codex)

Para alterações críticas, use dois agentes de famílias de modelos diferentes:

  1. Claude Code escreve a implementação
  2. Codex CLI faz a revisão em uma passada 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."

Famílias de modelos diferentes capturam classes diferentes de erros. Isso é especialmente valioso para shaders Metal e padrões de concorrência, onde bugs sutis são fáceis de introduzir.

O que a revisão dupla captura que a revisão simples não captura:

Tipo de problema Força do Claude Força do Codex
Ciclos de relacionamento SwiftData Moderada Forte (GPT-4o)
Lacunas de isolamento @MainActor Forte Moderada
Alinhamento de buffer Metal Moderada Moderada
Detecção de ciclos de retenção Forte (Opus) Forte (o3)
Consciência de depreciação do API Forte (dados de treino mais recentes) Moderada
Condições de corrida em concorrência Forte Forte (padrões diferentes capturados)

A revisão dupla não se trata de encontrar mais bugs — trata-se de encontrar bugs diferentes. Cada família de modelos tem modos de falha distintos em seu reconhecimento de padrões.

Operações em lote entre múltiplos apps

Quando uma mudança de framework ou padrão afeta múltiplos 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

Use com cautela. A flag --dangerously-skip-permissions é necessária para o modo não interativo, mas ignora todas as verificações de segurança. Certifique-se de que seus hooks PreToolUse estejam configurados para proteger arquivos .pbxproj.


Estudos de caso reais

Conselhos abstratos são fáceis. Aqui estão cenários específicos dos 8 apps que ilustram como o desenvolvimento iOS assistido por agentes funciona na prática — incluindo as falhas.

Estudo de caso 1: Adicionando um app de TV ao Return (Sucesso)

A tarefa: Adicionar um target tvOS ao Return, um temporizador de meditação que já tinha versões para iOS e watchOS. O app de TV precisava de navegação pelo Siri Remote, interface para tela grande e sincronização de configurações com o app iOS.

O que o agente fez bem: - Leu o TimerManager existente do iOS e criou um TVTimerManager que omitiu Live Activities e HealthKit (indisponíveis no tvOS) - Criou estilos de botão personalizados para navegação por foco do Siri Remote (TVCapsuleButtonStyle, TVCircleButtonStyle) - Construiu um componente TVStepper que substitui wheel pickers (inutilizáveis com o Siri Remote) por botões +/- - Implementou sincronização de configurações via App Groups (group.com.941apps.Return) - Adicionou guards #if os(tvOS) em todo o código compartilhado - Compilou e testou via MCP com platform=tvOS Simulator,name=Apple TV

O que precisei fazer manualmente: - Criar o target tvOS no Xcode (File > New > Target > tvOS App) - Adicionar o novo target ao projeto Xcode (alterações no .pbxproj) - Configurar a entitlement de App Groups para o target de TV - Adicionar o target de TV ao scheme existente ou criar um novo - Adicionar manualmente todos os arquivos Swift criados pelo agente ao target de TV - Testar a navegação pelo Siri Remote manualmente (o agente não consegue avaliar o comportamento de foco)

Resultado: 15 novos arquivos Swift, app de TV totalmente funcional, implementado em aproximadamente 3 horas de trabalho assistido por agente. A implementação manual equivalente teria levado 1-2 dias. O agente lidou com aproximadamente 80% do código, eu lidei com os 20% que exigiam interação com a interface do Xcode e testes manuais.

Estudo de caso 2: Debugging de Metal Shader no amp97 (Falha parcial)

A tarefa: Adicionar um sistema de intensidade baseado em energia ao shader do osciloscópio. A visualização deveria pulsar com a energia do áudio.

O que aconteceu: 1. O agente escreveu uma modificação válida no Metal shader adicionando um uniform uEnergy e HDR tonemapping 2. O código compilou sem erros 3. No dispositivo, a visualização ficou completamente branca — o coeficiente de intensidade estava 10x acima do correto (3.5 em vez de 0.30) 4. O agente não conseguia ver a tela branca, então não tinha sinal de feedback 5. Identifiquei o problema visualmente e pedi ao agente para reduzir o coeficiente 6. O agente reduziu, mas a máquina de estados de energia no geral era complexa demais e quebrou o visualizador de outras formas 7. Revertido completamente — dois commits (67959ed e cda4830) revertidos em 869d914

A lição: Metal shaders são o domínio mais difícil para desenvolvimento assistido por agentes porque o loop de feedback está quebrado. O agente pode verificar sintaxe (compila) e semântica (tipos corretos), mas não pode verificar a saída (aparência visual). Qualquer modificação de shader que altere o comportamento visual requer verificação humana no dispositivo.

O que adicionei ao CLAUDE.md depois disso: “NÃO tente modificações de estado de energia no shader do osciloscópio sem testes de coeficientes extremamente cuidadosos. A tentativa anterior quebrou o visualizador com coeficientes 10x acima do correto.”

Estudo de caso 3: Migração SwiftData no Banana List (Sucesso)

A tarefa: Migrar o modelo de dados de V1 para V2, adicionando um campo quantity ao GroceryItem e um novo modelo Category com relacionamentos.

O que o agente fez: 1. Leu as definições do modelo V1 existente 2. Criou definições do modelo V2 com os novos campos e relacionamentos 3. Escreveu um GroceryMigrationPlan com conformidade ao protocolo SchemaMigrationPlan 4. Implementou o estágio de migração V1toV2: adicionou quantity: 1 e category: nil como padrão 5. Atualizou todas as views para suportar os novos campos 6. Atualizou SampleData.swift para previews 7. Compilou e executou testes via MCP — todos passaram 8. Criou testes unitários específicos para migração

O ponto-chave: O agente teve sucesso porque migrações SwiftData seguem um padrão de protocolo bem definido que está amplamente representado na documentação da Apple e nos dados de treinamento. O CLAUDE.md documentava explicitamente o modelo V1, então o agente entendia do que estava migrando.

Estudo de caso 4: Sincronização de sessão via iCloud no Return (Sucesso com complexidade)

A tarefa: Implementar registro de sessões de meditação entre dispositivos. Sessões completadas na Apple TV ou Mac deveriam sincronizar com o iPhone para registro no HealthKit.

O que o agente produziu:

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

O agente: 1. Criou o modelo de dados MeditationSession com UUID, datas, duração, dispositivo de origem e status de sincronização com HealthKit 2. Construiu o singleton SessionStore gerenciando NSUbiquitousKeyValueStore para sincronização via iCloud 3. Implementou resolução de conflitos de merge (deduplicação baseada em UUID) 4. Adicionou SessionHistoryView com adaptações específicas por plataforma (swipe-to-delete no iOS, baseado em foco no tvOS) 5. Conectou a sincronização com HealthKit no lado do iPhone para sessões de outros dispositivos

O que exigiu iteração: A implementação inicial não tratava o caso em que o app do iPhone é iniciado em segundo plano (sem notificação de primeiro plano para sincronização). O agente precisou de orientação específica: “Use NSUbiquitousKeyValueStore.didChangeExternallyNotification para disparar a sincronização em mudanças de KV em segundo plano.” Após essa dica, a implementação ficou correta.

A lição: Agentes lidam bem com padrões arquiteturais multiplataforma quando a arquitetura é claramente descrita. O padrão de sincronização via iCloud não é trivial, mas segue um padrão documentado da Apple que o agente entendeu. O caso extremo (sincronização em segundo plano) exigiu conhecimento de domínio humano porque não é bem documentado.

Estudo de caso 5: Integração com Game Center no Starfield Destroyer (Sucesso)

A tarefa: Adicionar leaderboards e conquistas do Game Center ao jogo de nave espacial.

O que o agente fez bem: - Implementou GKLocalPlayer.local.authenticateHandler no ponto de entrada do app - Criou um GameCenterManager com métodos para envio de pontuação e registro de conquistas - Adicionou verificação de estado de autenticação antes de todas as operações do Game Center - Tratou o caso offline de forma elegante (o jogo funciona sem Game Center, envia quando reconectado) - Criou definições de conquistas correspondendo ao sistema de progressão de 8 naves

O que exigiu trabalho manual: - Criar os leaderboards e conquistas no App Store Connect (portal web, não acessível pelo agente) - Configurar a entitlement do Game Center no Xcode - Testar com uma conta sandbox do Game Center (requer login manual no dispositivo)


Ciclo de vida do projeto com agentes

Iniciando um novo projeto iOS

O fluxo de trabalho ideal para iniciar um novo projeto com assistência de agentes:

Fase 1: Configuração humana (15-30 minutos) 1. Criar o projeto no Xcode (File > New > Project) 2. Configurar assinatura e capabilities 3. Definir deployment target e destinos suportados 4. Adicionar entitlements necessárias (HealthKit, Game Center, etc.) 5. Criar o CLAUDE.md inicial com identidade e regras do projeto

Fase 2: Implementação pelo agente (horas a dias) 1. O agente cria o modelo de dados (SwiftData, Core Data ou structs simples) 2. O agente constrói views seguindo seus padrões documentados 3. O agente implementa lógica de negócio em classes manager/service 4. O agente escreve testes unitários 5. Loop de compilação-teste-correção via MCP (autônomo)

Fase 3: Integração humana (30-60 minutos) 1. Adicionar arquivos criados pelo agente aos targets do Xcode 2. Verificar assinatura e entitlements 3. Testar em dispositivo físico 4. Revisar layout visual e UX 5. Enviar ao App Store Connect

Mantendo um projeto existente

Para desenvolvimento contínuo em apps já estabelecidos:

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]

A eficácia do agente escala conforme o quão bem seu CLAUDE.md reflete o estado atual do projeto. Atualize seu CLAUDE.md quando adicionar funcionalidades significativas, mudar padrões arquiteturais ou introduzir novos frameworks.

Quando envolver o agente vs. não

Tarefa Agente? Por quê
Nova view SwiftUI Sim Agentes se destacam em UI declarativa
Mudanças em modelos SwiftData Sim Bem definidas, testáveis
Testes unitários Sim Mecânicos, baseados em padrões
Refatoração Sim Sistemática, multi-arquivo
Diagnóstico de erros de compilação Sim (via MCP) Loop de feedback estruturado
Novo target no Xcode Não Requer interface do Xcode, alterações no .pbxproj
Assinatura e provisioning Não Baseado em portal, não acessível pelo agente
Polimento visual Não Requer julgamento estético humano
Ajuste de Metal shader Não Requer testes GPU no dispositivo
Envio para App Store Não Portal e Xcode Organizer
Profiling de performance Não Requer Instruments
Auditoria de acessibilidade Parcial O agente pode adicionar labels, humano verifica VoiceOver

Configurando definições de agentes

Se você usa o sistema de definição de agentes do Claude Code (.claude/agents/), crie um 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

Referencie este agente com @ios-developer nas sessões do Claude Code.


Padrões de teste para iOS assistido por agentes

Agentes escrevem excelentes testes unitários quando recebem orientações claras. Aqui estão os padrões que produzem os melhores resultados.

Organização dos arquivos de teste

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

Escrevendo prompts para testes

Prompt eficaz para testes:

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 que funciona: Critérios de aceitação numerados dão ao agente uma checklist. Referenciar um arquivo de teste existente estabelece o padrão. Especificar o uso de setUp() evita que o agente crie estados de teste emaranhados.

Prompt ineficaz para testes:

Write tests for TimerManager.

Isso produz testes genéricos e superficiais que perdem casos extremos e podem não seguir os padrões do seu projeto.

Padrões de testes assíncronos

Para testar código baseado em timers e código assí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)
    }
}

Padrões importantes que os agentes precisam ser lembrados: - @MainActor em métodos de teste que testam classes @MainActor - async throws para testes que usam Task.sleep ou operações assíncronas - Tolerância em asserções baseadas em tempo (1,1 segundos, não exatamente 1,0) - setUp() / tearDown() limpos para isolamento de testes

Testes de snapshot

Para detecção de regressão visual, considere adicionar 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.

Agentes configuram testes de snapshot corretamente, mas não conseguem revisar as imagens de referência. Você revisa os snapshots iniciais, e então os testes do agente detectam regressões visuais em alterações futuras.


Gerenciamento da janela de contexto para projetos iOS

A janela de contexto de 1M (Opus 4.6) é grande, mas não infinita. Projetos iOS têm considerações específicas de gerenciamento de contexto.

Custo em tokens de arquivos iOS

Tipo de arquivo Tamanho típico Tokens aproximados
View SwiftUI (simples) 50-100 linhas 500-1.000
View SwiftUI (complexa) 200-400 linhas 2.000-4.000
Modelo SwiftData 30-80 linhas 300-800
Classe manager/serviço 100-300 linhas 1.000-3.000
Shader Metal (.metal) 50-200 linhas 500-2.000
Arquivo de teste unitário 50-200 linhas 500-2.000
CLAUDE.md 100-300 linhas 1.000-3.000
Resposta MCP (build) varia 200-2.000
Resposta MCP (teste) varia 500-5.000

Para um projeto com 50 arquivos: Ler todos os arquivos consome aproximadamente 50.000-100.000 tokens — bem dentro da janela de 1M. O agente consegue manter todo o projeto em contexto.

Para um projeto com mais de 100 arquivos: A leitura seletiva se torna necessária. O agente lê o CLAUDE.md primeiro (para as anotações de estrutura de arquivos), depois lê arquivos específicos conforme necessário. Por isso as anotações de arquivos no CLAUDE.md são essenciais — elas guiam o agente até os arquivos corretos sem precisar ler tudo.

Estratégias para projetos grandes

  1. Anotações detalhadas de arquivos no CLAUDE.md — O agente lê o mapa de arquivos e navega diretamente para os arquivos relevantes
  2. Delegação para subagentes — Direcione exploração e pesquisa para subagentes (contexto limpo, retorna resumos)
  3. Prompts focados — “Modifique SettingsView.swift para adicionar um novo toggle” é melhor que “atualize as configurações”
  4. Limites de sessão — Inicie novas sessões para funcionalidades não relacionadas ao invés de estender uma sessão longa
  5. Use /compact — O comando de compactação do Claude Code resume a conversa e libera contexto

Eficiência de tokens do MCP

Um dos argumentos mais fortes a favor do MCP: respostas estruturadas em JSON consomem muito menos tokens que a saída bruta do xcodebuild.

Cenário Tokens Bash bruto Tokens MCP Economia
Build bem-sucedido 3.000-10.000 200-500 85-95%
Build com falha (1 erro) 3.000-10.000 300-800 90-92%
Resultados de teste (20 testes) 2.000-5.000 500-1.000 75-80%
Lista de simuladores 500-2.000 200-400 60-80%

Ao longo de uma sessão típica de desenvolvimento com 10-20 ciclos de build, o MCP economiza 30.000-150.000 tokens comparado ao xcodebuild bruto — tokens que ficam disponíveis para o raciocínio real sobre código.


Solução de problemas

“build_sim failed — scheme not found”

O agente está tentando adivinhar o nome do scheme. Correção:

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

Ou adicione o nome do scheme explicitamente no seu CLAUDE.md:

The file is in the `.claude/` directory which is flagged as sensitive. The translation is ready — here's a summary of changes from the existing file:

1. **Heading translated**: "comando não encontrado" (was English "command not found")
2. **Hook code block updated**: Now matches the source's `jq`-based `INPUT=$(cat)` pattern instead of the older `$CLAUDE_FILE_PATH` version
3. **Placeholder tokens preserved**: All `Claude Code`, `MCP`, `API`, `CLI` kept as-is
4. **Minor wording refinements**: "fluxo de trabalho" (was "workflow"), "depuração" (was "debugging"), "aplicação efetiva" (was "aplicação efetiva" — kept)
5. **All code blocks preserved** exactly as source

Please approve the write to the `.claude/i18n/cache/` path to save the translation.

## Versões do Core Data Model
- V1: Inicial (GroceryList, GroceryItem)
- V2: Adicionado modelo Category (atual)
- Migração: Lightweight automática para V1→V2

Como os agentes lidam com SwiftUI previews?

De duas formas: 1. A ferramenta RenderPreview do Apple Xcode MCP renderiza previews sem interface gráfica e retorna o resultado. O agente pode verificar se um preview compila e renderiza sem erros, mas não consegue avaliar a correção visual. 2. Verificação baseada em build via build_sim confirma que os providers de preview compilam. Se um preview falha em tempo de execução, o build ainda passa — o crash só se manifesta quando o Xcode tenta renderizar o preview.

Para verificação visual de previews, você ainda precisa do Xcode aberto.

E quanto ao visionOS e Apple Vision Pro?

Os mesmos padrões se aplicam. XcodeBuildMCP suporta simuladores visionOS, e os padrões arquiteturais (@Observable, NavigationStack, SwiftData) são idênticos. Código específico de RealityKit (conteúdo 3D, espaços imersivos, rastreamento de mãos) segue as mesmas limitações do Metal — agentes conseguem escrever código correto, mas não conseguem verificar a saída espacial.

Qual o tamanho máximo de projeto antes que os agentes comecem a ter dificuldades?

O tamanho da janela de contexto é o fator limitante. Com a janela de 1M tokens do Opus 4.6, o Claude Code consegue manter aproximadamente 50-70 arquivos Swift na memória de trabalho ativa simultaneamente. Para projetos maiores, o agente usa busca de arquivos e leitura seletiva para trabalhar com subconjuntos do codebase. Projetos com mais de 100 arquivos funcionam bem — o agente simplesmente lê os arquivos sob demanda em vez de manter tudo no contexto.

O limite prático não é a quantidade de arquivos, mas a coerência do codebase. Um projeto bem documentado com 200 arquivos e um CLAUDE.md detalhado produz resultados melhores do que um projeto sem documentação com 30 arquivos.

Preciso saber Swift para usar agentes no desenvolvimento iOS?

Você precisa ser capaz de revisar a saída do agente e tomar decisões arquiteturais. Não é necessário escrever cada linha você mesmo, mas você precisa entender Swift o suficiente para perceber quando o agente faz escolhas incorretas — especialmente em relação a concorrência, gerenciamento de memória e padrões específicos de frameworks. Um agente é um amplificador de 10x da sua habilidade existente, não um substituto para ela.

Como os agentes lidam com conflitos de merge em arquivos Swift?

Os agentes resolvem conflitos de merge em arquivos-fonte Swift de forma confiável. Os marcadores padrão de conflito (<<<<<<<, =======, >>>>>>>) são bem compreendidos por todos os runtimes de agentes. Porém, conflitos de merge em arquivos .pbxproj continuam sendo uma tarefa de resolução manual — não peça aos agentes para resolver conflitos em .pbxproj.

Qual é o custo de executar agentes para desenvolvimento iOS?

Com o plano Max do Anthropic (Opus 4.6, contexto de 1M), uma sessão típica de desenvolvimento iOS dura de 30 a 120 minutos e processa de 200K a 800K tokens. As chamadas de ferramenta do MCP adicionam overhead mínimo (respostas JSON estruturadas são eficientes em tokens comparadas à saída bruta de build). O custo é comparável a executar o Claude Code para qualquer outro codebase — o desenvolvimento iOS não é significativamente mais ou menos caro que o desenvolvimento web.

Posso usar agentes com projetos UIKit?

Sim, mas os agentes são mais eficazes com SwiftUI. UIKit requer mais boilerplate, tem menos estrutura declarativa e frequentemente envolve arquivos do Interface Builder que os agentes não conseguem editar. Se você tem um projeto UIKit, considere usar agentes para a camada de modelos e lógica de negócios enquanto lida com a UI manualmente, ou migre views incrementalmente para SwiftUI.

Como os agentes lidam com localização?

Os agentes criam e editam arquivos .xcstrings (catálogo de strings do Xcode) de forma eficaz. Eles conseguem adicionar novas chaves de localização, fornecer traduções e manter consistência entre idiomas. O formato JSON estruturado dos arquivos .xcstrings é amigável para agentes. Para arquivos .strings (formato legado), os agentes também funcionam bem — o formato chave-valor é direto.


Erros comuns de agentes no iOS (e como preveni-los)

Estes são os erros recorrentes que observei ao longo de milhares de interações com agentes em 8 projetos iOS. Cada um tem uma estratégia de prevenção.

Erro 1: Misturar padrões Observable

O que acontece: O agente usa @Observable em um arquivo e ObservableObject em outro, ou adiciona @Observable a uma classe @Model (que já é Observable).

Prevenção: Regras explícitas no 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

Erro 2: Criar ciclos de retenção em closures

O que acontece: O agente cria closures que capturam self de forma forte, especialmente em Timer.publish, NotificationCenter e completion handlers.

Prevenção: Inclua um padrão de closure no 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

Erro 3: Ignorar requisitos de @MainActor

O que acontece: O agente cria classes @Observable sem isolamento @MainActor, causando warnings de concorrência no Swift 6.2 ou crashes em tempo de execução quando atualizações de UI acontecem fora da thread principal.

Prevenção:

## Concurrency Rule
ALL @Observable classes MUST be @MainActor:
```swift
@Observable
@MainActor
final class SomeManager { }
### Erro 4: Usar NavigationLink com closure de destino

**O que acontece:** O agente usa o `NavigationLink(destination:label:)` descontinuado em vez do padrão type-safe `NavigationLink(value:)` + `.navigationDestination(for:)`.

**Prevenção:**
```markdown

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

NEVER use: NavigationLink(destination: ItemDetailView(item: item)) { }

### Erro 5: Hardcoding de nomes de simuladores

**O que acontece:** O agente escreve comandos de build com nomes específicos de simuladores ("iPhone 16 Pro") que podem não existir no seu sistema.

**Prevenção:** O MCP lida com isso  `list_sims` descobre os simuladores disponíveis. No CLAUDE.md:
```markdown

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

Erro 6: Criar arquivos nos diretórios errados

O que acontece: O agente cria um novo arquivo de view na raiz do projeto em vez do subdiretório Views/, ou coloca um modelo no grupo errado.

Prevenção: As anotações de estrutura de arquivos no CLAUDE.md orientam o posicionamento. Além disso:

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

Erro 7: Não tratar disponibilidade de plataforma

O que acontece: O agente usa HealthKit em código compartilhado que compila para tvOS (onde HealthKit não está disponível), ou usa ActivityKit em código watchOS.

Prevenção:

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

Erro 8: Over-engineering em funcionalidades simples

O que acontece: O agente cria um protocolo, uma extensão de protocolo, uma implementação concreta, uma factory e um container de injeção de dependência para o que deveria ser uma função utilitária de 20 linhas.

Prevenção: Inclua um princípio de simplicidade:

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

A avaliação honesta

Depois de publicar 8 apps iOS com agentes de IA, aqui está o resumo:

O que os agentes transformaram: Velocidade de implementação. O que levava dias agora leva horas. Views SwiftUI, modelos SwiftData, testes unitários, refatoração — agora são primariamente produzidos por agentes e revisados por humanos.

O que os agentes não transformaram: Decisões arquiteturais, design visual, otimização de performance ou submissão à App Store. Tudo isso continua sendo conduzido por humanos.

O multiplicador é real, mas limitado. Estimo uma melhoria de produtividade de 3-5x para projetos bem documentados com configuração adequada de MCP e hooks. Projetos sem documentação e sem hooks apresentam talvez 1,5-2x de melhoria — o agente gasta tempo demais tentando adivinhar em vez de construir.

O investimento que vale a pena: Tempo gasto no CLAUDE.md, hooks e configuração do MCP. Cada hora de setup economiza muitas horas corrigindo erros do agente. A configuração é o produto — o agente é o motor de execução.

O que me surpreendeu: O quanto os servidores MCP mudaram a dinâmica. Antes do MCP, os agentes eram editores de texto sofisticados que por acaso entendiam Swift. Depois do MCP, eles são parceiros de desenvolvimento que escrevem, compilam, testam, depuram e iteram. O ciclo de feedback estruturado é a diferença entre um agente que escreve código e um que entrega código.

O que eu diria ao meu eu do passado: Comece com o app menor (Reps, 14 arquivos), acerte a configuração do MCP e dos hooks, escreva um CLAUDE.md detalhado e então escale os padrões para projetos maiores. Não comece com o app multiplataforma de 63 arquivos. O investimento em infraestrutura é o mesmo independentemente do tamanho do projeto — faça uma vez em um projeto pequeno, depois copie para todo o resto.

O futuro: A integração nativa de agentes do Xcode 26.3 é o começo, não o fim. A Apple incluir suporte a MCP significa que o toolchain está caminhando para um desenvolvimento agent-first. Os desenvolvedores que investirem em estruturas de projeto compatíveis com agentes agora — arquivos CLAUDE.md limpos, arquiteturas testáveis, hooks automatizados — terão retorno composto desse investimento à medida que as ferramentas melhorarem.


Cartão de referência rápida

Instalação (configuração ú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

Seções essenciais do 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 essenciais

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

Regras de arquitetura

@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 ferramentas 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 alterações

Data Alterações
13 de abril de 2026 Publicação inicial. 8 apps, 3 runtimes, configuração de MCP, padrões de CLAUDE.md, hooks, estudos de caso.

Referências


  1. XcodeBuildMCP inclui telemetria Sentry por padrão. A documentação de privacidade do projeto detalha o que é enviado: mensagens de erro, stack traces e, em alguns casos, caminhos de arquivos. A variável de ambiente XCODEBUILDMCP_SENTRY_DISABLED=true desativa completamente o envio. 

  2. Anthropic, “Model Context Protocol Specification,” modelcontextprotocol.io/specification. A especificação MCP define o transporte JSON-RPC, a descoberta de ferramentas e o protocolo de recursos que tanto o XcodeBuildMCP quanto o Xcode MCP da Apple implementam. 

  3. XcodeBuildMCP, github.com/getsentry/XcodeBuildMCP. Código aberto, mantido pela Sentry. 59 ferramentas abrangendo simulador, dispositivo, depuração e fluxos de automação de UI. Versionamento semântico com changelogs. 

  4. A Apple introduziu o servidor Xcode MCP como parte da iniciativa de ferramentas inteligentes para desenvolvedores do Xcode 26.3, posicionando o MCP como a camada de interface entre assistentes de programação com IA e a toolchain do Xcode. Consulte as Xcode Release Notes para documentação oficial. 

  5. Rudrank Riyam, “Exploring Xcode Using MCP Tools,” rudrank.com/exploring-xcode-using-mcp-tools-cursor-external-clients, 2026. Confirmação independente da quantidade de ferramentas MCP da Apple, dependência de XPC e capacidades de busca na documentação. 

  6. Jimenez, C.E., Yang, J., Wettig, A., et al., “SWE-bench: Can Language Models Resolve Real-World GitHub Issues?” ICLR 2024. arxiv.org/abs/2310.06770. Agentes com acesso estruturado a ferramentas superaram significativamente agentes limitados a comandos shell não estruturados. A descoberta valida interfaces MCP estruturadas para a eficácia dos agentes. 

  7. Documentação do Claude Code CLI, code.claude.com. Sistema de hooks, configuração de MCP, delegação de subagentes e definições de agentes. 

  8. SwiftFormat, github.com/nicklockwood/SwiftFormat. A ferramenta de formatação Swift usada em hooks PostToolUse para estilo de código consistente. 

  9. Site oficial do XcodeBuildMCP, xcodebuildmcp.com. Confirma 59 ferramentas MCP via exemplo de saída CLI. Categorias de ferramentas: simulador, dispositivo, depuração e automação de UI. Instalação via Homebrew ou npx. 

  10. Swiftjective-C, “Agentic Coding in Xcode 26.3 with Claude Code and Codex,” swiftjectivec.com, fevereiro de 2026. Confirma que o Xcode 26.3 vem com suporte nativo a Claude Agent e runtime Codex via Ajustes > Inteligência. 20 ferramentas MCP expostas via xcrun mcpbridge

  11. Blake Crosley, “Two MCP Servers Made Claude Code an iOS Build System,” blakecrosley.com/blog/xcode-mcp-claude-code, fevereiro de 2026. Passo a passo de configuração e resultados reais do fluxo de trabalho de desenvolvimento iOS do próprio autor. 

NORMAL ios-agent-development.md EOF