Contributing¶
Before you start¶
Read Architecture for the component boundaries and Building for the toolchain. arch.txt in the repository root is the hand-maintained architecture record — if you make an architectural change, update it in the same change, as noted in CLAUDE.md.
Project layout¶
GrotTrack/ Main app source
├── Models/ SwiftData @Model classes
├── ViewModels/ @Observable view models
├── Services/ Core services (tracking, screenshots, native messaging, ...)
├── Views/ SwiftUI views, grouped by feature area
└── Utilities/ Extensions, shared constants, the Chrome host installer
GrotTrackNativeHost/ Native messaging host CLI entry point
GrotTrackTests/ Unit tests (XCTest, run against the app as test host)
grot-track-extension/ Chrome extension (WXT / TypeScript)
project.yml XcodeGen project definition — regenerate after editing
arch.txt Hand-maintained architecture document
Conventions¶
- Swift 6 strict concurrency.
SWIFT_STRICT_CONCURRENCYiscomplete. Types that cross isolation boundaries need to beSendable; UI-facing state (AppState,AppCoordinator) is@MainActor. - MVVM with
@Observable. New UI state goes in an@Observableview model, not directly on a View.AppCoordinatoris the single composition root — services are constructed and wired there, not scattered across views. - SwiftLint governs style; run
swiftlint lintbefore submitting (see Building). CI runs it as a non-blocking annotation pass, so a lint issue will not fail your PR's required check, but fix it anyway. - Regenerate the Xcode project with
xcodegen generateafter adding, removing or moving source files, or after editingproject.yml, and commit the resulting project file changes if any are tracked. - Commit messages follow Conventional Commits (
feat:,fix:,chore:,docs:,refactor:,perf:,test:) — release-please parses these to generate the changelog and decide the next version. See Releasing.
Tests¶
Add or update tests under GrotTrackTests/ for behavioral changes — see Building for how to run the full suite or a single test class. The test-gate job in the release workflow runs the full suite before any release build, and build.yml's build-swift job runs it on every push and pull request.
Chrome extension changes¶
Extension changes should type-check (npx tsc --noEmit) and build (npx wxt build) cleanly — see Building. If you touch the native messaging message shape or the host manifest, update both sides together: grot-track-extension/entrypoints/background.ts and GrotTrack/Services/NativeMessageHost.swift share an implicit contract that nothing currently enforces at compile time (see Native Messaging).
Submitting changes¶
Open a pull request against main. CI (build.yml) builds and tests both the Swift app and the extension; the ci-success job is the single required status check. Once merged, release-please picks up your Conventional Commit on the next run and includes it in the pending release PR.