# Agent Guide for Swift and SwiftUI

This repository contains an Xcode project written with Swift and SwiftUI. Please follow the guidelines below so that the development experience is built on modern, safe API usage.

## Additional Context Files

Before starting work, read project documentation:

- `WORKSPACE.md` — (if present) Multi-project workspace overview and project relationships
- `README.md` — Project scope, features, and architecture
- In multi-project workspaces, each project folder has its own `README.md`

When making architectural changes, keep documentation files in sync with code changes.


## Role

You are a **Senior iOS Engineer**, specializing in SwiftUI, SwiftData, and related frameworks. Your code must always adhere to Apple's Human Interface Guidelines and App Review guidelines.


## Core Instructions

- Target iOS 26.0 or later. (Yes, it definitely exists.)
- Swift 6.2 or later, using modern Swift concurrency.
- SwiftUI backed up by `@Observable` classes for shared data.
- **Prioritize Protocol-Oriented Programming (POP)** for reusability and testability.
- **Follow Clean Architecture principles** for maintainable, testable code.
- Do not introduce third-party frameworks without asking first.
- Avoid UIKit unless requested.


## Clean Architecture

**Separation of concerns is mandatory.** Code should be organized into distinct layers with clear responsibilities and dependencies flowing inward.

### File Organization Principles

1. **One public type per file**: Each file should contain exactly one public struct, class, or enum. Private supporting types may be included if they are small and only used by the main type.

2. **Keep files lean**: Aim for files under 300 lines. If a file exceeds this:
   - Extract reusable sub-views into separate files in a `Components/` folder
   - Extract sheets/modals into a `Sheets/` folder
   - Move complex logic into dedicated types

3. **No duplicate code**: Before writing new code, search for existing implementations. Extract common patterns into reusable components.

4. **Logical grouping**: Organize files by feature, not by type:
   ```
   Feature/
   ├── Views/
   │   ├── FeatureView.swift
   │   ├── Components/
   │   │   ├── FeatureRowView.swift
   │   │   └── FeatureHeaderView.swift
   │   └── Sheets/
   │       └── FeatureEditSheet.swift
   ├── Models/
   │   └── FeatureModel.swift
   └── State/
       └── FeatureStore.swift
   ```

### Layer Responsibilities

| Layer | Contains | Depends On |
|-------|----------|------------|
| **Views** | SwiftUI views, UI components | State, Models |
| **State** | `@Observable` stores, view models | Models, Services |
| **Services** | Business logic, networking, persistence | Models |
| **Models** | Data types, entities, DTOs | Nothing |
| **Protocols** | Interfaces for services and stores | Models |

### Architecture Rules

1. **Views are dumb renderers**: No business logic in views. Views read state and call methods.
2. **State holds business logic**: All computations, validations, and data transformations.
3. **Services are stateless**: Pure functions where possible. Injected via protocols.
4. **Models are simple**: Plain data types. No dependencies on UI or services.

### Example Structure

```
App/
├── Design/           # Design constants, colors, typography
├── Localization/     # String helpers
├── Models/           # Data models (SwiftData, plain structs)
├── Protocols/        # Protocol definitions for DI
├── Services/         # Business logic, API clients, persistence
├── State/            # Observable stores, app state
└── Views/
    ├── Components/   # Reusable UI components
    ├── Sheets/       # Modal presentations
    └── [Feature]/    # Feature-specific views
```


## Protocol-Oriented Programming (POP)

**Protocol-first architecture is a priority.** When designing new features, always think about protocols and composition before concrete implementations.

### When Architecting New Code

1. **Start with the protocol**: Before writing a concrete type, ask "What capability am I defining?" and express it as a protocol.
2. **Identify shared behavior**: If multiple types will need similar functionality, define a protocol first.
3. **Use protocol extensions for defaults**: Provide sensible default implementations to reduce boilerplate.
4. **Prefer composition over inheritance**: Combine multiple protocols rather than building deep class hierarchies.

### When Reviewing Existing Code

1. **Look for duplicated patterns**: Similar logic across files is a candidate for protocol extraction.
2. **Identify common interfaces**: Types that expose similar properties/methods should conform to a shared protocol.
3. **Check before implementing**: Search for existing protocols that could be adopted or extended.
4. **Propose refactors proactively**: When you spot an opportunity to extract a protocol, mention it.

### Protocol Design Guidelines

- **Name protocols for capabilities**: Use `-able`, `-ing`, or `-Provider` suffixes (e.g., `Shareable`, `DataProviding`, `Persistable`).
- **Keep protocols focused**: Each protocol should represent one capability (Interface Segregation Principle).
- **Use associated types sparingly**: Prefer concrete types or generics at the call site when possible.
- **Constrain to `AnyObject` only when needed**: Prefer value semantics unless reference semantics are required.

### Benefits

- **Reusability**: Shared protocols work across features
- **Testability**: Mock types can conform to protocols for unit testing
- **Flexibility**: New features can adopt existing protocols immediately
- **Maintainability**: Fix a bug in a protocol extension, fix it everywhere
- **Discoverability**: Protocols document the expected interface clearly


## View/State Separation (MVVM-lite)

**Views should be "dumb" renderers.** All business logic belongs in stores or dedicated view models.

### What Belongs in State/Store

- **Business logic**: Calculations, validations, rules
- **Computed properties based on data**: Hints, recommendations, derived values
- **State checks**: `canSubmit`, `isLoading`, `hasError`
- **Data transformations**: Filtering, sorting, aggregations

### What is Acceptable in Views

- **Pure UI layout logic**: Adaptive layouts based on size class
- **Visual styling**: Color selection based on state
- **@ViewBuilder sub-views**: Breaking up complex layouts (keep in same file if small)
- **Accessibility labels**: Combining data into accessible descriptions

### Example

```swift
// ❌ BAD - Business logic in view
struct MyView: View {
    @Bindable var state: FeatureState
    
    private var isValid: Bool {
        !state.name.isEmpty && state.email.contains("@")
    }
}

// ✅ GOOD - Logic in State, view just reads
// In FeatureState:
var isValid: Bool {
    !name.isEmpty && email.contains("@")
}

// In View:
Button("Save") { state.save() }
    .disabled(!state.isValid)
```


## Swift Instructions

- Always mark `@Observable` classes with `@MainActor`.
- Assume strict Swift concurrency rules are being applied.
- Prefer Swift-native alternatives to Foundation methods where they exist.
- Prefer modern Foundation API (e.g., `URL.documentsDirectory`, `appending(path:)`).
- Never use C-style number formatting; use `format:` modifiers instead.
- Prefer static member lookup to struct instances (`.circle` not `Circle()`).
- Never use old-style GCD; use modern Swift concurrency.
- Filtering text based on user-input must use `localizedStandardContains()`.
- Avoid force unwraps and force `try` unless unrecoverable.


## SwiftUI Instructions

- Always use `foregroundStyle()` instead of `foregroundColor()`.
- Always use `clipShape(.rect(cornerRadius:))` instead of `cornerRadius()`.
- Always use the `Tab` API instead of `tabItem()`.
- Never use `ObservableObject`; always prefer `@Observable` classes.
- Never use `onChange()` in its 1-parameter variant.
- Never use `onTapGesture()` unless you need tap location/count; use `Button`.
- Never use `Task.sleep(nanoseconds:)`; use `Task.sleep(for:)`.
- Never use `UIScreen.main.bounds` to read available space.
- Do not break views up using computed properties; extract into new `View` structs.
- Do not force specific font sizes; prefer Dynamic Type.
- Use `NavigationStack` with `navigationDestination(for:)`.
- If using an image for a button label, always specify text alongside.
- Prefer `ImageRenderer` to `UIGraphicsImageRenderer`.
- Use `bold()` instead of `fontWeight(.bold)`.
- Avoid `GeometryReader` if newer alternatives work (e.g., `containerRelativeFrame()`).
- When enumerating in `ForEach`, don't convert to Array first.
- Hide scroll indicators with `.scrollIndicators(.hidden)`.
- Avoid `AnyView` unless absolutely required.
- **Never use raw numeric literals** for padding, spacing, opacity, etc.—use Design constants.
- **Never use inline colors**—define all colors with semantic names.
- Avoid UIKit colors in SwiftUI code.


## watchOS Development (CRITICAL)

**Read this entire section before implementing any watch functionality.**

### Creating a Watch Target

When adding a watchOS target to an existing iOS app:

1. **File → New → Target → "Watch App for watchOS"**
2. Choose **"Watch App for Existing iOS App"** (NOT standalone)
3. Name it appropriately (e.g., `AppNameWatch`)
4. Xcode creates a folder like `AppNameWatch Watch App/`

### CRITICAL: Embedding the Watch App

⚠️ **THIS IS THE #1 CAUSE OF "WATCH APP NOT INSTALLED" ERRORS** ⚠️

The watch app MUST be embedded in the iOS app for deployment to real devices:

1. Select the **iOS target** in Xcode
2. Go to **Build Phases** tab
3. Verify there's an **"Embed Watch Content"** phase
4. **CRITICAL**: Ensure **"Code Sign On Copy"** is CHECKED ✓

If "Embed Watch Content" doesn't exist:
1. Click **"+"** → **"New Copy Files Phase"**
2. Rename to **"Embed Watch Content"**
3. Set **Destination** to **"Products Directory"**
4. Set **Subpath** to `$(CONTENTS_FOLDER_PATH)/Watch`
5. Add the watch app (e.g., `AppNameWatch Watch App.app`)
6. **CHECK "Code Sign On Copy"** ← This is critical!

Without proper embedding, the iOS app installs but the watch app does NOT install on the paired Apple Watch.

### Bundle Identifiers

Watch app bundle IDs MUST be prefixed with the iOS app's bundle ID:

```
iOS app:    com.company.AppName
Watch app:  com.company.AppName.watchkitapp  ← MUST start with iOS bundle ID
```

Also verify `WKCompanionAppBundleIdentifier` in the watch target's build settings matches the iOS app's bundle ID exactly.

### Data Sync: WatchConnectivity (NOT App Groups)

**DO NOT use App Groups for iPhone ↔ Watch data sharing.**

App Groups:
- ❌ Do NOT work between iPhone and Apple Watch
- ❌ Different container paths on each device
- ❌ Will waste hours debugging why data isn't syncing
- ✅ Only work between an app and its extensions on the SAME device

**Use WatchConnectivity framework instead:**

```swift
// iOS side - WatchConnectivityService.swift
import WatchConnectivity

@MainActor
final class WatchConnectivityService: NSObject, WCSessionDelegate {
    static let shared = WatchConnectivityService()
    
    private override init() {
        super.init()
        if WCSession.isSupported() {
            WCSession.default.delegate = self
            WCSession.default.activate()
        }
    }
    
    func syncData(_ data: [String: Any]) {
        guard WCSession.default.activationState == .activated,
              WCSession.default.isPaired,
              WCSession.default.isWatchAppInstalled else { return }
        
        try? WCSession.default.updateApplicationContext(data)
    }
}
```

### WatchConnectivity Methods

| Method | Use Case |
|--------|----------|
| `updateApplicationContext` | Latest state that persists (use this for most syncs) |
| `sendMessage` | Immediate delivery when counterpart is reachable |
| `transferUserInfo` | Queued delivery, guaranteed but not immediate |

### watchOS Framework Limitations

These iOS frameworks are NOT available on watchOS:

- ❌ `CoreImage` - Generate QR codes on iOS, send image data to watch
- ❌ `UIKit` (mostly) - Use SwiftUI
- ❌ `AVFoundation` (limited)

### Simulator Limitations

WatchConnectivity on simulators is **unreliable**:

- `isWatchAppInstalled` often returns `false` even when running
- `isReachable` may be `false` even with both apps running
- `updateApplicationContext` may fail with "counterpart not installed"

**Workarounds for simulator testing:**
1. Add `#if targetEnvironment(simulator)` blocks with sample data
2. Test real sync functionality on physical devices only

### Debugging Watch Sync Issues

If `isWatchAppInstalled` returns `false`:

1. ✅ Check "Embed Watch Content" build phase exists
2. ✅ Check "Code Sign On Copy" is enabled
3. ✅ Verify bundle ID is prefixed correctly
4. ✅ Clean build folder (⇧⌘K) and rebuild
5. ✅ On iPhone, open Watch app → verify app appears under "Installed"

### NSObject Requirement

`WCSessionDelegate` is an Objective-C protocol, so conforming classes must inherit from `NSObject`:

```swift
final class WatchConnectivityService: NSObject, WCSessionDelegate {
    // NSObject is required for WCSessionDelegate conformance
}
```


## SwiftData Instructions

If SwiftData is configured to use CloudKit:

- Never use `@Attribute(.unique)`.
- Model properties must have default values or be optional.
- All relationships must be marked optional.
- Before changing any shipped `@Model` schema, follow `CLOUDKIT_SCHEMA_GUARDRAILS.md`.


## Model Design: Single Source of Truth

**Computed properties should be the single source of truth for derived data.**

### Name Fields Pattern

When a model has multiple name components (prefix, firstName, middleName, lastName, suffix, etc.), use a computed property for the display name:

```swift
// ✅ GOOD - Computed from individual fields
var fullName: String {
    var parts: [String] = []
    if !prefix.isEmpty { parts.append(prefix) }
    if !firstName.isEmpty { parts.append(firstName) }
    if !lastName.isEmpty { parts.append(lastName) }
    // ... etc
    return parts.joined(separator: " ")
}

// ❌ BAD - Stored displayName that can get out of sync
var displayName: String  // Never add this
```

### Benefits

- **Always up to date**: Changes to individual fields are immediately reflected
- **No sync bugs**: No risk of stored value diverging from component fields
- **Simpler code**: No need to update displayName when editing name fields

### Related Properties

If you need different formats for different purposes:

- `fullName` — For display (may include formatting like quotes, parentheses)
- `vCardName` — For export (plain format, no special formatting)


## Localization Instructions

- Use **String Catalogs** (`.xcstrings` files) for localization.
- SwiftUI `Text("literal")` views automatically look up strings in the catalog.
- For strings outside of `Text` views, use `String(localized:)` or a helper extension.
- Store all user-facing strings in the String Catalog.
- Support at minimum: English (en), Spanish-Mexico (es-MX), French-Canada (fr-CA).
- Never use `NSLocalizedString`; prefer `String(localized:)`.


## Design Constants

**Never use raw numeric literals or hardcoded colors directly in views.**

### Values That MUST Be Constants

- **Spacing & Padding**: `Design.Spacing.medium` not `.padding(12)`
- **Corner Radii**: `Design.CornerRadius.large` not `cornerRadius: 16`
- **Font Sizes**: `Design.BaseFontSize.body` not `size: 14`
- **Opacity Values**: `Design.Opacity.strong` not `.opacity(0.7)`
- **Colors**: `Color.Primary.accent` not `Color(red:green:blue:)`
- **Line Widths**: `Design.LineWidth.medium` not `lineWidth: 2`
- **Shadow Values**: `Design.Shadow.radiusLarge` not `radius: 10`
- **Animation Durations**: `Design.Animation.quick` not `duration: 0.3`
- **Component Sizes**: `Design.Size.avatar` not `frame(width: 56)`

### Organization

- Create a `DesignConstants.swift` file using enums for namespacing.
- Extend `Color` with semantic color definitions.
- View-specific constants go at the top of the view struct with a comment.
- Name constants semantically: `accent` not `pointSix`, `large` not `sixteen`.


## App Identifiers (xcconfig)

**Centralize all company-specific identifiers** using xcconfig files for true single-source configuration. This enables one-line migration between developer accounts.

### Why xcconfig?

- **Single source of truth**: Change one file, everything updates
- **Build-time resolution**: Bundle IDs, entitlements, and Swift code all derive from same source
- **No manual updates**: Entitlements use variable substitution
- **Environment support**: Easy Debug/Release/Staging configurations

### Setup Instructions

#### Step 1: Create xcconfig Files

Create `Configuration/Base.xcconfig`:

```
// Base.xcconfig - Source of truth for all identifiers
// MIGRATION: Update COMPANY_IDENTIFIER and DEVELOPMENT_TEAM below

// =============================================================================
// COMPANY IDENTIFIER - CHANGE THIS FOR MIGRATION
// =============================================================================

COMPANY_IDENTIFIER = com.yourcompany
APP_NAME = YourAppName
DEVELOPMENT_TEAM = YOUR_TEAM_ID

// =============================================================================
// DERIVED IDENTIFIERS - DO NOT EDIT
// =============================================================================

APP_BUNDLE_IDENTIFIER = $(COMPANY_IDENTIFIER).$(APP_NAME)
WATCH_BUNDLE_IDENTIFIER = $(APP_BUNDLE_IDENTIFIER).watchkitapp
APPCLIP_BUNDLE_IDENTIFIER = $(APP_BUNDLE_IDENTIFIER).Clip
TESTS_BUNDLE_IDENTIFIER = $(COMPANY_IDENTIFIER).$(APP_NAME)Tests
UITESTS_BUNDLE_IDENTIFIER = $(COMPANY_IDENTIFIER).$(APP_NAME)UITests

APP_GROUP_IDENTIFIER = group.$(COMPANY_IDENTIFIER).$(APP_NAME)
CLOUDKIT_CONTAINER_IDENTIFIER = iCloud.$(COMPANY_IDENTIFIER).$(APP_NAME)

APPCLIP_DOMAIN = yourapp.example.com
```

Create `Configuration/Debug.xcconfig`:

```
// Debug.xcconfig
#include "Base.xcconfig"
// Add debug-specific settings here
```

Create `Configuration/Release.xcconfig`:

```
// Release.xcconfig
#include "Base.xcconfig"
// Add release-specific settings here
```

#### Step 2: Configure Xcode Project

In `project.pbxproj`, add file references and set `baseConfigurationReference` for each build configuration:

**1. Add xcconfig file references to PBXFileReference section:**

```
/* Use SOURCE_ROOT and full path from project root */
EACONFIG001 /* Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppName/Configuration/Base.xcconfig; sourceTree = SOURCE_ROOT; };
EACONFIG002 /* Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppName/Configuration/Debug.xcconfig; sourceTree = SOURCE_ROOT; };
EACONFIG003 /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppName/Configuration/Release.xcconfig; sourceTree = SOURCE_ROOT; };
```

**IMPORTANT**: Use `sourceTree = SOURCE_ROOT` (not `"<group>"`) and include the full path from project root (e.g., `AppName/Configuration/Base.xcconfig`).

**2. Set `baseConfigurationReference` on project-level Debug/Release configurations:**

```
EA123456 /* Debug */ = {
    isa = XCBuildConfiguration;
    baseConfigurationReference = EACONFIG002 /* Debug.xcconfig */;
    buildSettings = { ... };
};
```

**3. Replace hardcoded values with variables:**

```
PRODUCT_BUNDLE_IDENTIFIER = "$(APP_BUNDLE_IDENTIFIER)";
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = "$(APP_BUNDLE_IDENTIFIER)";
```

#### Step 3: Update Entitlements

Use variable substitution in `.entitlements` files:

```xml
<key>com.apple.developer.icloud-container-identifiers</key>
<array>
    <string>$(CLOUDKIT_CONTAINER_IDENTIFIER)</string>
</array>
<key>com.apple.security.application-groups</key>
<array>
    <string>$(APP_GROUP_IDENTIFIER)</string>
</array>
```

#### Step 4: Bridge to Swift via Info.plist

Add keys to `Info.plist` that bridge xcconfig values to Swift:

```xml
<key>AppGroupIdentifier</key>
<string>$(APP_GROUP_IDENTIFIER)</string>
<key>CloudKitContainerIdentifier</key>
<string>$(CLOUDKIT_CONTAINER_IDENTIFIER)</string>
<key>AppClipDomain</key>
<string>$(APPCLIP_DOMAIN)</string>
```

#### Step 5: Create Swift Interface

**Why this is needed:** Swift code cannot read xcconfig files directly. The xcconfig values flow through Info.plist, and this Swift file provides a clean API to access them at runtime. Without this file, you'd have to call `Bundle.main.object(forInfoDictionaryKey:)` everywhere you need an identifier.

**When to use:** Any Swift code that needs App Group identifiers, CloudKit containers, custom domains, or other configuration values must use `AppIdentifiers.*` instead of hardcoding strings.

Create `Configuration/AppIdentifiers.swift`:

```swift
import Foundation

enum AppIdentifiers {
    // Read from Info.plist (values come from xcconfig)
    static let appGroupIdentifier: String = {
        Bundle.main.object(forInfoDictionaryKey: "AppGroupIdentifier") as? String
            ?? "group.com.yourcompany.AppName"
    }()
    
    static let cloudKitContainerIdentifier: String = {
        Bundle.main.object(forInfoDictionaryKey: "CloudKitContainerIdentifier") as? String
            ?? "iCloud.com.yourcompany.AppName"
    }()
    
    static let appClipDomain: String = {
        Bundle.main.object(forInfoDictionaryKey: "AppClipDomain") as? String
            ?? "yourapp.example.com"
    }()
    
    // Derived from bundle identifier
    static var bundleIdentifier: String {
        Bundle.main.bundleIdentifier ?? "com.yourcompany.AppName"
    }
    
    static var watchBundleIdentifier: String { "\(bundleIdentifier).watchkitapp" }
    static var appClipBundleIdentifier: String { "\(bundleIdentifier).Clip" }
    
    static func appClipURL(recordName: String) -> URL? {
        URL(string: "https://\(appClipDomain)/appclip?id=\(recordName)")
    }
}
```

### Data Flow

```
Base.xcconfig (source of truth)
    ↓
project.pbxproj (baseConfigurationReference)
    ↓
Build Settings → Bundle IDs, Team ID, etc.
    ↓
Info.plist (bridges values via $(VARIABLE))
    ↓
AppIdentifiers.swift (Swift reads from Bundle.main)
```

### Usage in Code

```swift
// Always use AppIdentifiers instead of hardcoding
FileManager.default.containerURL(
    forSecurityApplicationGroupIdentifier: AppIdentifiers.appGroupIdentifier
)

CKContainer(identifier: AppIdentifiers.cloudKitContainerIdentifier)
```

### Adding New Targets

When adding new targets (Widgets, Intents, App Clips, etc.), follow this pattern:

#### 1. Add Bundle ID Variable to Base.xcconfig

```
// In Base.xcconfig, add new derived identifier
WIDGET_BUNDLE_IDENTIFIER = $(APP_BUNDLE_IDENTIFIER).Widget
INTENT_BUNDLE_IDENTIFIER = $(APP_BUNDLE_IDENTIFIER).Intent
```

#### 2. Set Target to Use xcconfig

For the new target's Debug/Release configurations in `project.pbxproj`:

```
EA_NEW_TARGET_DEBUG /* Debug */ = {
    isa = XCBuildConfiguration;
    baseConfigurationReference = EACONFIG002 /* Debug.xcconfig */;
    buildSettings = {
        PRODUCT_BUNDLE_IDENTIFIER = "$(WIDGET_BUNDLE_IDENTIFIER)";
        DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
        // ... other settings
    };
};
```

#### 3. Configure Entitlements (if needed)

If the target needs App Groups or CloudKit access, create an entitlements file using variables:

```xml
<!-- WidgetExtension.entitlements -->
<key>com.apple.security.application-groups</key>
<array>
    <string>$(APP_GROUP_IDENTIFIER)</string>
</array>
```

#### 4. Share Code via App Groups

Extensions must use App Groups to share data with the main app:

```swift
// In extension code
let sharedDefaults = UserDefaults(suiteName: AppIdentifiers.appGroupIdentifier)
let containerURL = FileManager.default.containerURL(
    forSecurityApplicationGroupIdentifier: AppIdentifiers.appGroupIdentifier
)
```

#### 5. Update AppIdentifiers.swift (if needed)

Add new computed properties for target-specific identifiers:

```swift
static var widgetBundleIdentifier: String { "\(bundleIdentifier).Widget" }
static var intentBundleIdentifier: String { "\(bundleIdentifier).Intent" }
```

#### Common Target Types and Bundle ID Patterns

| Target Type | Bundle ID Variable | Example Value |
|-------------|-------------------|---------------|
| Widget Extension | `WIDGET_BUNDLE_IDENTIFIER` | `$(APP_BUNDLE_IDENTIFIER).Widget` |
| Intent Extension | `INTENT_BUNDLE_IDENTIFIER` | `$(APP_BUNDLE_IDENTIFIER).Intent` |
| App Clip | `APPCLIP_BUNDLE_IDENTIFIER` | `$(APP_BUNDLE_IDENTIFIER).Clip` |
| Watch App | `WATCH_BUNDLE_IDENTIFIER` | `$(APP_BUNDLE_IDENTIFIER).watchkitapp` |
| Notification Extension | `NOTIFICATION_BUNDLE_IDENTIFIER` | `$(APP_BUNDLE_IDENTIFIER).NotificationExtension` |
| Share Extension | `SHARE_BUNDLE_IDENTIFIER` | `$(APP_BUNDLE_IDENTIFIER).ShareExtension` |

#### Checklist for New Targets

- [ ] Add bundle ID variable to `Base.xcconfig`
- [ ] Set `baseConfigurationReference` to Debug/Release xcconfig
- [ ] Use `$(VARIABLE)` for `PRODUCT_BUNDLE_IDENTIFIER`
- [ ] Use `$(DEVELOPMENT_TEAM)` for team
- [ ] Create entitlements with `$(APP_GROUP_IDENTIFIER)` if sharing data
- [ ] Add to `AppIdentifiers.swift` if Swift code needs the identifier
- [ ] Register App ID in Apple Developer Portal (uses same App Group)

### Migration

To migrate to a new developer account, edit **one file** (`Base.xcconfig`):

```
COMPANY_IDENTIFIER = com.newcompany
DEVELOPMENT_TEAM = NEW_TEAM_ID
```

Then clean build (⇧⌘K) and rebuild. Everything updates automatically—including all extension targets.


## Dynamic Type Instructions

- Always support Dynamic Type for accessibility.
- Use `@ScaledMetric` to scale custom dimensions.
- Choose appropriate `relativeTo` text styles based on semantic purpose.
- For constrained UI elements, you may use fixed sizes but document the reason.
- Prefer system text styles: `.font(.body)`, `.font(.title)`, `.font(.caption)`.


## VoiceOver Accessibility Instructions

- All interactive elements must have meaningful `.accessibilityLabel()`.
- Use `.accessibilityValue()` for dynamic state.
- Use `.accessibilityHint()` to describe what happens on interaction.
- Use `.accessibilityAddTraits()` for element type.
- Hide decorative elements with `.accessibilityHidden(true)`.
- Group related elements to reduce navigation complexity.
- Post accessibility announcements for important events.


## Project Structure

- Use a consistent project structure organized by feature.
- Follow strict naming conventions for types, properties, and methods.
- **One public type per file**—break types into separate files.
- Write unit tests for core application logic.
- Only write UI tests if unit tests are not possible.
- Add code comments and documentation as needed.
- Never include secrets or API keys in the repository.


## Documentation Instructions

- **Keep `README.md` files up to date** when adding new functionality.
- In multi-project workspaces, update the relevant project's `README.md`.
- Document new features, settings, or mechanics in the appropriate README.
- Update documentation when modifying existing behavior.
- Include configuration options and special interactions.
- README updates should be part of the same commit as the feature.


## PR Instructions

- If installed, ensure SwiftLint returns no warnings or errors.
- Verify that documentation reflects any new functionality.
- Check for duplicate code before submitting.
- Ensure all new files follow the one-type-per-file rule.
