Entry point for coding agents working on TaskMenu. Keep this file short and repo-wide; put folder-specific implementation notes in the nearest README.md.
- Native macOS menu bar app for Google Tasks.
- Swift 6, AppKit UI, macOS 14.4+,
@Observable, strict concurrency. - XcodeGen build graph targeting Xcode 26.4 project settings: edit
project.yml, then regenerateTaskMenu.xcodeproj. - Targets:
TaskMenuandTaskMenuTests. - Configurations:
Debug,Release(direct-download DMG), andAppStore. OnlyAppStoredefinesAPP_STORE_BUILD, which compiles out the GitHub update checker and the donation link for App Review guidelines 2.4.5(vii) and 3.1.1. Changes near either feature must keep both variants building; seedocs/RELEASING.md. - App shape: no Dock icon and no main app window; UI is presented from an AppKit status item popover.
- External surface area: Google OAuth 2.0 with PKCE, Google Tasks REST API, Keychain token storage, UserNotifications for due-date reminders, GitHub release update checks, MetricKit payload persistence.
TaskMenu/README.md- app-target map, lifecycle, and state flow.TaskMenu/Models/README.md- app state, Google models, ordering, search, and mutation rules.TaskMenu/Services/README.md- OAuth, Google Tasks API, keychain, notification, MetricKit, update checks, and service-injection guidance.TaskMenu/Views/README.md- popover UI ownership, task-list interactions, settings, and view-testable helpers.TaskMenu/Utilities/README.md- constants, OAuth config values, and date formatting expectations.TaskMenu/Resources/README.md- Info.plist, entitlements, URL schemes, app icons, and generated asset notes.TaskMenuTests/README.md- unit-test map, test doubles, and focused test selection.AppStorePreviews/README.md- generated marketing/App Store preview assets.
- Use Swift concurrency APIs that compile with
SWIFT_STRICT_CONCURRENCY: complete. - Keep
AppStateon the main actor and make view-facing mutations flow through it unless a folder README names a narrower owner. - Keep network and token operations in services; views should call
AppStatemethods, not Google APIs directly. - Keep models
CodableandSendable. - Prefer Apple frameworks and SF Symbols. Do not add package dependencies without a strong reason.
- Avoid force unwraps on network, OAuth, keychain, notification, or plist-derived data.
- Put temporary agent artifacts such as handoff specs, investigation notes, scratch scripts, and build logs under
scratch/; it is gitignored and must not contain files intended to ship. - If you add, remove, rename, or retarget source files, update
project.ymland runxcodegen generate. - When files are added or deleted, update the corresponding folder-local
README.mdin the same change so its file map and ownership notes stay current. - Keep
TaskMenu.xcodeprojgenerated; do not hand-edit it. - Do not commit
Config.xcconfig; it contains local OAuth and signing values.BuildConfig.xcconfigis the committed entry point that includes it, plus the generatedBuildMetadata.xcconfiggit-commit stamp. - Preserve the menu-bar-only behavior for app launches.
- Update
CHANGELOG.mdbefore committing feature or bug-fix work, under## Unreleasedwhen present.
- Default to the current branch. When explicitly asked to commit/push, commit a focused logical change and push directly to
main. - Do not create a feature branch or pull request unless the user asks.
xcodegen generate
xcodebuild build -project TaskMenu.xcodeproj -scheme TaskMenu \
-configuration Debug \
-destination "platform=macOS"
xcodebuild test -project TaskMenu.xcodeproj -scheme TaskMenu \
-configuration Debug \
-destination "platform=macOS" \
-only-testing:TaskMenuTests/AppStateTests
xcodebuild build -project TaskMenu.xcodeproj -scheme "TaskMenu (App Store)" \
-configuration AppStore \
-destination "platform=macOS"- When verifying a fix or new feature, run only the minimal relevant
-only-testing:slice. - OAuth-enabled app launches require a local
Config.xcconfigcopied fromConfig.xcconfig.examplewithGOOGLE_CLIENT_IDandGOOGLE_REDIRECT_SCHEME.
To see and verify UI changes without credentials, launch the app with --testing-window argument.
Remember to always run the full UI verification loop first before working on any changes to discover
any issues early (e.g., macOS permission issues).
- The task UI opens in a regular window (signed-in state, seeded fake tasks) instead of the menu bar popover.
- Seeded data covers four lists: "Seeded Tasks" (subtasks, completed section, delete target), "Due Dates" (overdue/today/tomorrow/future due dates on parents and subtasks, plus standalone due-today and undated roots so "Sort by" → "Due date" visibly reorders it), "Long Subtasks" (a parent with 12 subtasks for scroll behavior), and "Empty List" (empty state). Switch lists with the picker at the top.
- Adding
--signed-outstarts on the sign-in screen instead of a seeded signed-in state, which is how to reach the "Explore the Demo" button and exercise demo mode. - Adding
--demoopens directly in demo mode on the realistic sample lists (Today/Work/Personal). This is the state the App Store preview sources are captured from. - Adding
--side-by-sidestarts with the two-pane layout on;--secondary-list <id>picks the right pane's seeded list. - Adding
--list <id>(e.g.--list seeded-due-dates) switches to that seeded list after the first load, and--sort-due-datestarts with the list sorted by due date, so sort screenshots need no clicking. - Everything is in memory: no Keychain access, no Google credentials, no network, no notifications, no update checks, no persisted defaults. Task mutations (add, add subtask, edit, complete, delete) and creating a list from the picker's "New List…" item work against the fake API and reset on relaunch.
- Take screenshots with
screencaptureto inspect rendering, then kill the process when done. - Fakes live at the bottom of
TaskMenu/TaskMenuApp.swift(TestingWindowTasksAPIand friends); extend the seeded data there if a UI state you need is missing.
- OAuth refresh/access tokens belong in Keychain only.
- Keep sandbox and hardened-runtime settings intact.
- Network access should stay limited to explicit product features: Google OAuth, Google Tasks, token revocation, and GitHub release update checks.
- MetricKit payloads are currently persisted locally; do not add upload behavior without explicit opt-in and a reviewed privacy path.