Skip to content

feat: Apple Reminders two-way sync with calendarItemIdentifier storage#6161

Closed
mdmohsin7 wants to merge 14 commits intomainfrom
feat/apple-reminders-two-way-sync
Closed

feat: Apple Reminders two-way sync with calendarItemIdentifier storage#6161
mdmohsin7 wants to merge 14 commits intomainfrom
feat/apple-reminders-two-way-sync

Conversation

@mdmohsin7
Copy link
Copy Markdown
Member

Summary

  • Store calendarItemIdentifier — Every Apple Reminder we create now returns its stable EventKit UUID, which is stored on the backend alongside the action item. This enables lookup, update, delete, and completion detection.
  • Client-pull sync on foreground resume — New AppleRemindersSyncService runs on every app foreground (30s debounce). Fetches unexported items from backend, creates reminders locally, stores identifiers back. No longer solely dependent on FCM silent push (which iOS throttles to ~2-3/hour).
  • Two-way completion sync — Detects when reminders are completed in Apple Reminders app and marks corresponding Omi action items as complete. Also syncs Omi completions back to Apple Reminders.
  • Fix iCloud calendar sourceaddReminder now uses defaultCalendarForNewReminders() instead of preferring .local source, so reminders sync across devices via iCloud.
  • Remove 100-item dedup cap — Old UserDefaults dedup mechanism replaced by backend identifier mapping.

Changes

Backend (2 files)

  • apple_reminder_id field on UpdateActionItemRequest and ActionItemResponse
  • New GET /v1/action-items/pending-sync?platform=apple_reminders endpoint
  • New Firestore query functions for unexported and synced items

iOS Native (2 files)

  • addReminder returns calendarItemIdentifier string instead of true/false
  • syncBatchFromJSON returns [{actionItemId, calendarItemIdentifier}] mappings
  • 3 new methods: getRemindersStatus, updateReminder, deleteReminder
  • Fixed calendar source, removed UserDefaults dedup

Dart (6 files modified, 1 new)

  • appleReminderId field on ActionItemWithMetadata
  • Updated AppleRemindersService with new return types and methods
  • New AppleRemindersSyncService orchestrator (outbound + inbound sync)
  • Lifecycle hook on AppLifecycleState.resumed in HomePage

Test plan

  • Set Apple Reminders as default task integration
  • Create action items in Omi → verify reminders appear in Apple Reminders after backgrounding/foregrounding
  • Complete a reminder in Apple Reminders → switch back to Omi → verify action item is marked complete
  • Delete a reminder in Apple Reminders → switch back to Omi → verify action item remains but loses export badge
  • Kill app, create action items via another device, reopen → verify reminders are created on foreground
  • Manually export via tile icon → verify calendarItemIdentifier is stored
  • Test with iCloud Reminders enabled → verify reminders sync across devices

🤖 Generated with Claude Code

Add apple_reminder_id to UpdateActionItemRequest and ActionItemResponse
models for storing EventKit calendarItemIdentifier. Add new GET
/v1/action-items/pending-sync endpoint that returns items needing
outbound sync (unexported) and inbound sync (have apple_reminder_id).
Add get_unexported_action_items() for finding items needing outbound
sync and get_action_items_with_reminder_id() for finding items needing
inbound completion sync.
- addReminder now returns calendarItemIdentifier instead of bool
- syncBatchFromJSON returns [{actionItemId, calendarItemIdentifier}]
- Fix calendar source to use defaultCalendarForNewReminders (iCloud)
- Remove UserDefaults 100-item dedup cap
- Add getRemindersStatus for batch identifier lookup
- Add updateReminder for updating by identifier
- Add deleteReminder for deleting by identifier
Update handleAppleRemindersSync to send calendarItemIdentifier
mappings instead of plain action item IDs via markExportedBatch.
Store the EventKit calendarItemIdentifier on the action item model
for two-way Apple Reminders sync.
Add appleReminderId parameter to updateActionItem for storing the
EventKit identifier. Add getPendingSyncItems() for fetching items
that need outbound or inbound Apple Reminders sync.
- addReminder returns calendarItemIdentifier string instead of bool
- Update FCM/background sync handlers for new mapping format
- Add getRemindersStatus for batch identifier lookup
- Add updateReminderById and deleteReminderById methods
Update _handleAppleRemindersExport to capture and store the
calendarItemIdentifier when manually exporting to Apple Reminders.
New orchestrator that runs on foreground resume with 30s debounce:
- Outbound: creates reminders for unexported items, stores identifiers
- Inbound: detects completion changes in Apple Reminders, syncs back
Add lifecycle hook in HomePage to run AppleRemindersSyncService
on app resume, then refresh action items UI after sync completes.
Expand getRemindersStatus to return notes and dueDate fields from
EventKit reminders, enabling full bidirectional field sync.
Filter pending_export by the integration's created_at timestamp so
enabling Apple Reminders doesn't dump all existing action items.
Also add due_at to synced_items response for bidirectional due date sync.
Check TaskIntegrationProvider.selectedApp before triggering sync on
foreground resume to avoid unnecessary network and EventKit calls.
Sync title, due date, and completion in both directions:
- Omi changed since last sync → push all fields to reminder
- Otherwise → pull all reminder fields to Omi
- Completion is always merged (if either side completed, both complete)
@Rahulsharma0810
Copy link
Copy Markdown

Merge this please

@mdmohsin7
Copy link
Copy Markdown
Member Author

Closing in favor of a clean reimplementation. The accumulated fixes made this PR hard to review.

@mdmohsin7 mdmohsin7 closed this Apr 3, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 3, 2026

Hey @mdmohsin7 👋

Thank you so much for taking the time to contribute to Omi! We truly appreciate you putting in the effort to submit this pull request.

After careful review, we've decided not to merge this particular PR. Please don't take this personally — we genuinely try to merge as many contributions as possible, but sometimes we have to make tough calls based on:

  • Project standards — Ensuring consistency across the codebase
  • User needs — Making sure changes align with what our users need
  • Code best practices — Maintaining code quality and maintainability
  • Project direction — Keeping aligned with our roadmap and vision

Your contribution is still valuable to us, and we'd love to see you contribute again in the future! If you'd like feedback on how to improve this PR or want to discuss alternative approaches, please don't hesitate to reach out.

Thank you for being part of the Omi community! 💜

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants