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
just checkbefore committing or submitting (see Building) — it covers formatting, linting, extension typecheck, generated-asset drift and tests. CI treats a lint failure as a failed required build. - Regenerate the Xcode project with
just xcodeprojafter adding, removing or moving source files, or after editingproject.yml.GrotTrack.xcodeprojis generated and gitignored; never commit it. - 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 pass just typecheck and just build-extension — 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.