Files
yattee/AGENTS.md
2026-02-08 18:33:56 +01:00

60 lines
3.1 KiB
Markdown

# Yattee Development Guide for AI Agents
## Deployment Targets
**iOS:** 18.0+ | **macOS:** 15.0+ | **tvOS:** 18.0+
This project targets the latest OS versions only - use newest APIs freely without availability checks.
## Build & Test Commands
**Build:** `xcodebuild -scheme Yattee -configuration Debug`
**Test (all):** `xcodebuild test -scheme Yattee -destination 'platform=macOS'`
**Test (single):** `xcodebuild test -scheme Yattee -destination 'platform=macOS' -only-testing:YatteeTests/TestSuiteName/testMethodName`
**Lint:** `periphery scan` (config: `.periphery.yml`)
## Code Style
**Language:** Swift 5.0+ with strict concurrency (Swift 6 mode enabled)
**UI:** SwiftUI with `@Observable` macro for view models (not `ObservableObject`)
**Concurrency:** Use `actor` for services, `@MainActor` for UI-related code, `async/await` everywhere
**Testing:** Swift Testing framework (`@Test`, `@Suite`, `#expect`) - NOT XCTest
## Imports & Organization
**Import order:** Foundation first, then SwiftUI, then @testable imports
**File headers:** Include `// FileName.swift`, `// Yattee`, and brief comment describing purpose
**MARK comments:** Use `// MARK: - Section Name` to organize code sections
**Sendable:** All models, errors, and actors must conform to `Sendable`
## Types & Naming
**Models:** Immutable structs with `Codable, Hashable, Sendable` conformance
**Services:** Use `actor` for thread-safe services, `final class` for `@Observable` view models
**Enums:** Use associated values for typed errors (see `APIError.swift`)
**Optionals:** Prefer guard-let unwrapping; use `if let` for simple cases
**Naming:** camelCase for variables/functions, PascalCase for types, clear descriptive names
## Error Handling
**Errors:** Define typed enum errors conforming to `Error, LocalizedError, Equatable, Sendable`
**Async throws:** All async network/IO operations should throw typed errors
**Logging:** Use `LoggingService.shared` for all logging (see `HTTPClient.swift` for patterns)
**User feedback:** Provide localized error descriptions via `errorDescription`
## Testing & Debugging
**Add logging/visual clues** (borders, backgrounds) when debugging issues - then ask user for results
**If first fix doesn't work:** Add debug code before second attempt to understand the issue better
## UI Testing (Ruby/RSpec with AXe CLI)
**Run UI tests:** `./bin/ui-test --skip-build --keep-simulator`
**Run single spec:** `SKIP_BUILD=1 KEEP_SIMULATOR=1 bundle exec rspec spec/ui/smoke/search_spec.rb`
**Accessibility labels vs identifiers:** On iOS 26+, `.accessibilityIdentifier()` doesn't work reliably on `Group`, `ScrollView`, and some container views (AXUniqueId comes back empty). Use `.accessibilityLabel()` instead, which maps to `AXLabel` and can be detected via AXe's `text_visible?()` method.
**iOS 26 TabView search:** The search field is integrated into the bottom tab bar with `Tab(role: .search)`. Typing `\n` doesn't submit - use hardware key press via `press_return` (AXe key 40).
**ScrollView children:** Video rows inside `LazyVStack`/`ScrollView` aren't exposed in the accessibility tree. Use coordinate-based tapping instead.