Guidelines for coding agents working on SwiftUI-Days.
SwiftUI-Days is a countdown/tracker app built with SwiftUI, SwiftData, and modern Swift concurrency.
For general project information, see README.md.
Use XcodeBuildMCP tools (preferred) or make test as fallback.
Use XcodeBuildMCP tools (preferred) or make build as fallback.
make formatRuns swiftformat and markdownlint. Always run before committing.
- Order: Foundation → Apple frameworks (SwiftUI, SwiftData, Observation) → third-party → local
- Separate groups with blank lines
- Use
@testable import SwiftUI_Daysin tests (note underscore)
import Foundation
import SwiftData
import SwiftUI
// Code here--ifdef no-indent- don't indent #if blocks--header strip- remove file headers--trailingCommas never- no trailing commas in multiline
- Use
@Observablefor shared state services - Use
@Modelfor SwiftData entities - Use
@State/@Bindingfor local view state - Prefer
final classfor reference types - Use
enumfor configuration options (e.g.,DisplayOption)
- Files: PascalCase matching the primary type (e.g.,
Item.swift,AppSettings.swift) - Screens:
*Screen.swiftsuffix (e.g.,RootScreen.swift,ItemScreen.swift) - Extensions:
Type+.swift(e.g.,View+.swift,Color+Hex.swift) - Services: Plain nouns (e.g.,
AppSettings,FeedbackSender) - Models: Plain nouns (e.g.,
Item,DisplayOption) - Environment keys:
*EnvironmentKey.swift
- Local state:
@State,@Binding - Shared services:
@Observable+@Environment(ServiceType.self) - SwiftData:
@Model,@Query,@Environment(\.modelContext) - Do NOT nest
@Observableobjects inside each other
- Use
do/try/catchwith.taskfor async operations - Use
try?for optional conversions where failure is expected - Fatal errors acceptable in app initialization failures
- Services go in
SwiftUI-Days/Services/ - Inject at app level via
.environment(serviceInstance) - Access via
@Environment(ServiceType.self)
import Foundation
import SwiftUI
@testable import SwiftUI_Days
import Testing
@Suite("Test suite name")
struct MyTests {
@Test func testName() throws {
let value = try #require(optionalValue)
#expect(value == expected)
}
@Test(arguments: [1, 2, 3])
func parameterizedTest(input: Int) {
#expect(input > 0)
}
}- Use
@Suitefor test struct with Russian description - Use
@Testfor test functions - Use
#expectfor assertions (notXCTAssert) - Use
try #requirefor unwrapping optionals - Use
@Test(arguments:)for parameterized tests
- NO file headers (stripped by swiftformat)
- Doc comments (
///) for public interfaces - Russian language acceptable in test descriptions
SwiftUI-Days/
├── SwiftUI_DaysApp.swift # App entry point, DI
├── EnvironmentKeys/ # Custom Environment keys
├── Extensions/ # Extensions and utilities
├── Models/ # Domain models, types
├── Preview Content/ # Preview data
├── Screens/ # Views and screens
│ ├── CommonViews/ # Reusable components
│ ├── Detail/ # Item detail screens
│ ├── Main/ # Main list screen
│ └── More/ # Settings, about
├── Services/ # Shared services
└── SupportingFiles/ # Assets, plist, localization
- Entry point + DI:
SwiftUI_DaysApp.swift - Main model:
Models/Item.swift - Settings service:
Services/AppSettings.swift - Sample tests:
SwiftUI-DaysTests/ItemTests.swift