Add recurring reminders (--repeat) and hasRecurrence/nextDueDate JSON fields - #4
Merged
Merged
Conversation
Implements EKRecurrenceRule-backed recurrence: - `reminders add <list> <reminder> --repeat daily|weekly|monthly|yearly` - `--repeat-interval N` to repeat every N units instead of every 1 (default 1), e.g. `--repeat-interval 2 --repeat weekly` for fortnightly. - `--repeat-until <date>` to set a recurrence end date; omitting it repeats forever, matching Reminders.app's own default. - `reminders edit <list> <index> --repeat ...` replaces an existing repeat rule; `--clear-repeat` removes it entirely. - JSON output (`--format json`) now includes `recurrence`, `recurrenceInterval`, and `recurrenceEnd` fields when a reminder has a recurrence rule. `hourly` is intentionally rejected with a clear validation error rather than silently degrading to a daily rule: EventKit's `EKRecurrenceFrequency` has no hourly case (Reminders.app's own UI doesn't expose hourly repeat either), so there's no faithful way to represent it via `EKRecurrenceRule`. Ported from keith/reminders-cli#109, authored by Ramesh Baskaran.
Adds `edit --repeat-until <date>` and `--clear-repeat-end` so a reminder's recurrence end condition can be changed on its own, without needing to also respecify the frequency. An end-only edit copies the existing EventKit recurrence rule and only changes its end, preserving interval and any complex selectors instead of rebuilding a plain rule from scratch. Also validates that a repeating reminder always has a due date, and that the recurrence end can't be earlier than it. Ported from keith/reminders-cli#110, authored by Aleksei Morozov.
The previous end-only edit path rebuilt the recurrence rule via the public EKRecurrenceRule initializer, which drops provider-specific metadata such as calendarIdentifier and firstDayOfTheWeek. Copy the existing rule instead and only mutate its recurrenceEnd, so an end-only edit is fully transparent to everything else about the rule. Ported from keith/reminders-cli#110, authored by Aleksei Morozov.
EventKit doesn't advance dueDateComponents on a repeating EKReminder as occurrences pass, so a recurring reminder's due date can end up arbitrarily overdue rather than reflecting the next actionable occurrence (observed directly against Reminders.app; documented in the README since Apple doesn't cover this behavior). hasRecurrence is now always encoded as a boolean so scripts don't have to check for a missing or null field. nextDueDate steps the recurrence rule's frequency/interval forward from its due date, honoring --repeat-until/occurrence-count ends, and is only populated for the plain daily/weekly/monthly/yearly rules this CLI itself creates and edits. Extends the recurrence support ported from keith/reminders-cli#109 and #110. Co-authored-by: Ramesh Baskaran <ramesh.baskaran@gmail.com> Co-authored-by: Aleksei Morozov <246998741+morozovpersonal@users.noreply.github.com>
udondan
added a commit
that referenced
this pull request
Sep 13, 2026
Add recurring reminders (--repeat) and hasRecurrence/nextDueDate JSON fields
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Ports recurring-reminder support from two still-open upstream PRs on
keith/reminders-cli, and adds two additional fields to make the JSON output easier to consume from scripts.main, then adds two more commits making end-date edits safe). Original authorship is preserved viagit cherry-pick; commit messages were reworded to this repo's conventional-commits style.add/edit:--repeat daily|weekly|monthly|yearly,--repeat-interval N,--repeat-until <date>,--clear-repeat-end,--clear-repeat.recurrence,recurrenceInterval,recurrenceEnd/recurrenceCountin JSON and plain output forshow/show-all(verified end-to-end; no extra wiring was needed since both already go through the shared formatting/encoding used byadd/edit).hasRecurrence: true|false— always present as a boolean in JSON, so scripts don't need to check for a missing/nullfield.nextDueDate— EventKit doesn't advance a repeatingEKReminder'sdueDateComponentsas occurrences pass (confirmed against real Reminders.app data; not otherwise documented by Apple), so the due date can end up arbitrarily overdue.nextDueDatecomputes the next actionable occurrence by stepping the rule's frequency/interval forward, honoring--repeat-until/occurrence-count ends. Only populated for the plain daily/weekly/monthly/yearly rules this CLI itself creates/edits; omitted for rules with EventKit-native complex selectors it doesn't construct.hasRecurrenceandnextOccurrence/nextDueDate(stepping, interval > 1,recurrenceEnddate/count bounds,nilfor complex selectors).Test plan
swift build -Xswiftc -warnings-as-errors— cleanswift test -Xswiftc -warnings-as-errors— 52/52 passingadd --repeat weekly,show/show-allin plain and JSON, confirmedhasRecurrence/nextDueDate/recurrence/recurrenceIntervalappear correctly for a recurring reminder andhasRecurrence: falsewith nonextDueDatefor a plain one; scratch reminders deleted afterward