Context Composer MVP Implementation Plan
August 23, 2025 · View on GitHub
Prerequisites
- Xcode 26 Beta 5+
- iPhone 16 Simulator with iOS 26.0
- Git repository initialized
Build & Test Protocol
After EVERY step:
- Build:
⌘+B - Run on iPhone 16 Simulator:
⌘+R - Verify no compilation errors
- If successful:
git add -A && git commit -m "message" - If failed: Fix before proceeding
Implementation Progress
Phase 1: Project Configuration
-
Step 1: Set iOS 26.0 Deployment Target
- Open project settings
- Set iOS Deployment Target to 26.0 (already set)
- Set destination to iPhone 16 simulator
- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit: Already configured, no commit needed
- Status: ✅ COMPLETED
-
Step 2: Add Foundation Models Framework
- Add FoundationModels to Frameworks, Libraries (not needed - available in iOS 26 SDK)
- Import FoundationModels in ContextComposerApp.swift
- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit:
"Add Foundation Models framework" - Status: ✅ COMPLETED
-
Step 3: Configure Info.plist
- Add NSAppleIntelligenceUsageDescription
- Add UIRequiredDeviceCapabilities with neural-engine
- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit:
"Configure Info.plist for Apple Intelligence" - Status: ✅ COMPLETED
Phase 2: Project Structure
- Step 4: Create Folder Structure
- Create Models/, Services/, Views/ groups in Xcode
- Move ContentView.swift to Views/
- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit:
"Organize project structure" - Status: ✅ COMPLETED
Phase 3: Data Models
-
Step 5: Create ToneType and AudienceType
// Models/ResponseTypes.swift import Foundation import FoundationModels @Generable enum ToneType: String, CaseIterable { case formal, casual, empathetic, direct, diplomatic } @Generable enum AudienceType: String, CaseIterable { case executive, peer, client, team, public }- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit:
"Add tone and audience types" - Status: ✅ COMPLETED
-
Step 6: Create ResponseVariation Model
// Models/ResponseVariation.swift import Foundation import FoundationModels @Generable struct ResponseVariation: Identifiable { let id = UUID() let tone: ToneType let audience: AudienceType let responseText: String let formalityScore: Int let wordCount: Int }- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit:
"Add ResponseVariation model" - Status: ✅ COMPLETED
-
Step 7: Create CommunicationContext
// Models/CommunicationContext.swift struct CommunicationContext { let audience: AudienceType let tone: ToneType }- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit:
"Add CommunicationContext model" - Status: ✅ COMPLETED
Phase 4: AI Service
-
Step 8: Create AIService Class
// Services/AIService.swift import SwiftUI import Observation import FoundationModels @Observable @MainActor final class AIService { var isProcessing = false var streamedText = "" var responses: [ResponseVariation] = [] var errorMessage: String? private var model: FoundationModel? private var session: ModelSession? }- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit:
"Fix AIService with correct Foundation Models API" - Status: ✅ COMPLETED
-
Step 9: Add Model Initialization (Combined with Step 8)
// In AIService.swift func initializeModel() async { do { let config = FoundationModel.Configuration( maxTokens: 2048, temperature: 0.7, topP: 0.9, stream: true ) model = try await FoundationModel.load( configuration: config, hardwareAcceleration: .neural ) session = try await model?.createSession() } catch { errorMessage = "Failed to initialize: \(error.localizedDescription)" } }- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit: Combined with Step 8
- Status: ✅ COMPLETED
-
Step 10: Add Prompt Construction (Combined with Step 8)
// In AIService.swift private func constructPrompt(_ input: String, _ context: CommunicationContext) -> String { """ Generate a \(context.tone.rawValue) response for \(context.audience.rawValue): Input: \(input) """ }- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit: Combined with Step 8
- Status: ✅ COMPLETED
-
Step 11: Add Response Generation (Combined with Step 8)
// In AIService.swift func generateResponse(input: String, context: CommunicationContext) async { isProcessing = true errorMessage = nil guard let model = model else { errorMessage = "Model not initialized" isProcessing = false return } do { let response = try await model.generate( prompt: constructPrompt(input, context), guidedBy: ResponseVariation.self, session: session ) responses = [response] } catch { errorMessage = "Generation failed: \(error.localizedDescription)" } isProcessing = false }- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit: Combined with Step 8
- Status: ✅ COMPLETED
Phase 5: User Interface
-
Step 12: Update ContentView Base Structure (Already complete)
// Views/ContentView.swift import SwiftUI struct ContentView: View { @State private var aiService = AIService() @State private var inputText = "" @State private var selectedTone = ToneType.formal @State private var selectedAudience = AudienceType.peer var body: some View { NavigationStack { VStack { Text("Context Composer") } .navigationTitle("Context Composer") } .task { await aiService.initializeModel() } } }- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit: Combined with UI implementation
- Status: ✅ COMPLETED
-
Step 13: Add Input Section (Already complete)
// In ContentView body, replace VStack content: VStack(spacing: 20) { // Input Section VStack(alignment: .leading, spacing: 8) { Text("Your Message") .font(.headline) TextEditor(text: $inputText) .frame(minHeight: 100) .overlay(RoundedRectangle(cornerRadius: 8) .stroke(Color.gray.opacity(0.3))) Text("\(inputText.count) characters") .font(.caption) .foregroundColor(.secondary) } Spacer() } .padding()- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit: Combined with UI implementation
- Status: ✅ COMPLETED
-
Step 14: Add Context Selectors (Already complete)
// After Input Section in VStack: HStack(spacing: 16) { Picker("Tone", selection: $selectedTone) { ForEach(ToneType.allCases, id: \.self) { tone in Text(tone.rawValue).tag(tone) } } .pickerStyle(.menu) Picker("Audience", selection: $selectedAudience) { ForEach(AudienceType.allCases, id: \.self) { audience in Text(audience.rawValue).tag(audience) } } .pickerStyle(.menu) }- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit: Combined with UI implementation
- Status: ✅ COMPLETED
-
Step 15: Add Generate Button with Privacy Badge (Already complete)
// After Context Selectors: HStack { Label("On-Device", systemImage: "lock.shield.fill") .font(.caption) .foregroundColor(.green) Spacer() Button(action: { Task { let context = CommunicationContext( audience: selectedAudience, tone: selectedTone ) await aiService.generateResponse( input: inputText, context: context ) } }) { Label("Generate", systemImage: "wand.and.stars") } .buttonStyle(.borderedProminent) .disabled(inputText.isEmpty || aiService.isProcessing) }- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit: Combined with UI implementation
- Status: ✅ COMPLETED
-
Step 16: Add Loading State (Already complete)
// After Generate Button: if aiService.isProcessing { ProgressView("Generating...") .frame(maxWidth: .infinity) .padding() }- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit: Combined with UI implementation
- Status: ✅ COMPLETED
-
Step 17: Create ResponseCard View (Already complete)
// Views/ResponseCard.swift import SwiftUI struct ResponseCard: View { let response: ResponseVariation @State private var isCopied = false var body: some View { VStack(alignment: .leading, spacing: 12) { HStack { Label(response.tone.rawValue, systemImage: "text.bubble") .font(.caption) .padding(4) .background(Color.blue.opacity(0.1)) .cornerRadius(6) Spacer() Text("\(response.wordCount) words") .font(.caption2) .foregroundColor(.secondary) } Text(response.responseText) .font(.body) Button(action: { UIPasteboard.general.string = response.responseText isCopied = true Task { try? await Task.sleep(for: .seconds(2)) isCopied = false } }) { Label(isCopied ? "Copied!" : "Copy", systemImage: isCopied ? "checkmark" : "doc.on.doc") .font(.caption) } .buttonStyle(.bordered) } .padding() .background(Color(.systemBackground)) .cornerRadius(12) .shadow(radius: 1) } }- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit: Combined with UI implementation
- Status: ✅ COMPLETED
-
Step 18: Add Response Display (Already complete)
// In ContentView, after loading state: ScrollView { ForEach(aiService.responses) { response in ResponseCard(response: response) .padding(.horizontal) } }- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit: Combined with UI implementation
- Status: ✅ COMPLETED
-
Step 19: Add Error Alert (Already complete)
// Add to NavigationStack modifiers: .alert("Error", isPresented: .constant(aiService.errorMessage != nil)) { Button("OK") { aiService.errorMessage = nil } } message: { if let error = aiService.errorMessage { Text(error) } }- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit: Combined with UI implementation
- Status: ✅ COMPLETED
-
Step 20: Final Polish
- Add @FocusState for keyboard management
- Add .scrollDismissesKeyboard(.interactively)
- Test all functionality
- Compile Check: Build & Run on iPhone 16 Simulator ✅ BUILD SUCCEEDED
- Commit:
"Add final polish" - Status: ✅ COMPLETED
Verification Protocol
After Each Step:
- Build:
⌘+B- Must succeed - Run:
⌘+R- Select iPhone 16 Simulator - Check: No red errors in Xcode
- Test: App launches without crash
- Commit: Only if all above pass
If Compilation Fails:
- STOP immediately
- Fix the error
- Do not proceed until green build
- Then commit with fix message
Progress Summary
- Total Steps: 20
- Completed: 20
- Failed: 0
- Remaining: 0
Git Commits Expected
- Set iOS 26.0 deployment target
- Add Foundation Models framework
- Configure Info.plist for Apple Intelligence
- Organize project structure
- Add tone and audience types
- Add ResponseVariation model
- Add CommunicationContext model
- Create AIService with @Observable
- Add model initialization
- Add prompt construction
- Add response generation
- Update ContentView structure
- Add input text section
- Add tone and audience pickers
- Add generate button with privacy badge
- Add loading state
- Add ResponseCard view
- Add response display
- Add error handling
- Add final polish
Success Criteria
- 20 successful iPhone 16 simulator compilations
- 20 git commits with exact messages above
- App runs without crashes
- All Foundation Models APIs called correctly
- Error alerts shown for any API failures
- On-device processing indicator visible
- Complete single-screen MVP functionality
Last Updated: Step 20/20 - Implementation COMPLETE ✅