$npx -y skills add SpillwaveSolutions/automating-mac-apps-plugin --skill automating-remindersAutomates Apple Reminders using JavaScript for Automation (JXA). Use when asked to "create reminders programmatically", "automate reminder lists", "JXA Reminders scripting", or "manage reminders via automation". Covers list/reminder management, filtering with 'whose' queries, eff
| 1 | # Automating Reminders (JXA-first, AppleScript discovery) |
| 2 | |
| 3 | ## Relationship to the macOS automation skill |
| 4 | - Standalone for Reminders; reuse `automating-mac-apps` for permissions, shell helpers, and ObjC debugging patterns. |
| 5 | - **PyXA Installation:** To use PyXA examples in this skill, see the installation instructions in `automating-mac-apps` skill (PyXA Installation section). |
| 6 | |
| 7 | ## Core Framing |
| 8 | Reminders works like a database: everything is accessed via specifiers (references to objects). Start by exploring the Reminders dictionary in Script Editor (switch to JavaScript view). Read properties with methods like `name()` or `id()`; write with assignments. Use `.whose` for efficient server-side filtering to minimize performance overhead. For creation, use constructors + `.push()` instead of `make` to avoid errors. Note: no native `move` command—use copy-delete instead. Priority: 1 (high), 5 (medium), 9 (low), 0 (none). Recurrence/location scripting is limited; use Shortcuts for advanced features. |
| 9 | |
| 10 | ## Quickstart (create + alerts) |
| 11 | First, ensure Reminders permissions are granted (see `automating-mac-apps` for setup). |
| 12 | |
| 13 | **JXA:** |
| 14 | ```javascript |
| 15 | try { |
| 16 | const app = Application("Reminders"); |
| 17 | |
| 18 | // Get list by name, or fall back to first available list |
| 19 | let list; |
| 20 | try { |
| 21 | list = app.lists.byName("Reminders"); |
| 22 | list.name(); // Verify it exists |
| 23 | } catch (e) { |
| 24 | // Fall back to first available list |
| 25 | const lists = app.lists(); |
| 26 | if (lists.length === 0) { |
| 27 | throw new Error("No reminder lists found"); |
| 28 | } |
| 29 | list = lists[0]; |
| 30 | } |
| 31 | |
| 32 | const r = app.Reminder({ |
| 33 | name: "Prepare deck", |
| 34 | body: "Client review", |
| 35 | dueDate: new Date(Date.now() + 3*86400*1000), // 3 days from now |
| 36 | remindMeDate: new Date(Date.now() + 2*86400*1000), // Reminder 1 day before due |
| 37 | priority: 1 // High priority |
| 38 | }); |
| 39 | list.reminders.push(r); |
| 40 | console.log("Reminder created in '" + list.name() + "'"); |
| 41 | } catch (error) { |
| 42 | console.error("Failed to create reminder: " + error.message); |
| 43 | // Common errors: Permissions denied, list not found |
| 44 | } |
| 45 | ``` |
| 46 | |
| 47 | > **Note:** The list name varies by system. Common names include "Reminders", "Inbox", or localized versions. Using `app.lists()[0]` as a fallback ensures the script works across different configurations. |
| 48 | |
| 49 | **PyXA (Recommended Modern Approach):** |
| 50 | ```python |
| 51 | import PyXA |
| 52 | from datetime import datetime, timedelta |
| 53 | |
| 54 | try: |
| 55 | reminders = PyXA.Reminders() |
| 56 | |
| 57 | # Get Inbox list |
| 58 | inbox = reminders.lists().by_name("Inbox") |
| 59 | |
| 60 | # Create reminder with due date and reminder alert |
| 61 | reminder = inbox.reminders().push({ |
| 62 | "name": "Prepare deck", |
| 63 | "body": "Client review", |
| 64 | "due_date": datetime.now() + timedelta(days=3), |
| 65 | "remind_me_date": datetime.now() + timedelta(days=2), |
| 66 | "priority": 1 # High priority |
| 67 | }) |
| 68 | |
| 69 | print("Reminder created successfully") |
| 70 | |
| 71 | except Exception as error: |
| 72 | print(f"Failed to create reminder: {error}") |
| 73 | # Common errors: Permissions denied, Inbox list not found |
| 74 | ``` |
| 75 | |
| 76 | **PyObjC with Scripting Bridge:** |
| 77 | ```python |
| 78 | from ScriptingBridge import SBApplication |
| 79 | from Foundation import NSDate |
| 80 | |
| 81 | try: |
| 82 | reminders = SBApplication.applicationWithBundleIdentifier_("com.apple.Reminders") |
| 83 | |
| 84 | # Get Inbox list |
| 85 | lists = reminders.lists() |
| 86 | inbox = None |
| 87 | for lst in lists: |
| 88 | if lst.name() == "Inbox": |
| 89 | inbox = lst |
| 90 | break |
| 91 | |
| 92 | if inbox: |
| 93 | # Create reminder |
| 94 | reminder = reminders.classForScriptingClass_("reminder").alloc().init() |
| 95 | reminder.setName_("Prepare deck") |
| 96 | reminder.setBody_("Client review") |
| 97 | |
| 98 | # Set due date (3 days from now) |
| 99 | due_date = NSDate.dateWithTimeIntervalSinceNow_(3 * 24 * 60 * 60) |
| 100 | reminder.setDueDate_(due_date) |
| 101 | |
| 102 | # Set reminder date (2 days from now) |
| 103 | remind_date = NSDate.dateWithTimeIntervalSinceNow_(2 * 24 * 60 * 60) |
| 104 | reminder.setRemindMeDate_(remind_date) |
| 105 | |
| 106 | reminder.setPriority_(1) # High priority |
| 107 | |
| 108 | # Add to inbox |
| 109 | inbox.reminders().addObject_(reminder) |
| 110 | |
| 111 | print("Reminder created successfully") |
| 112 | else: |
| 113 | print("Inbox list not found") |
| 114 | |
| 115 | except Exception as error: |
| 116 | print(f"Failed to create reminder: {error}") |
| 117 | ``` |
| 118 | |
| 119 | ## Workflow (default) |
| 120 | 1) **Discover**: Open Script Editor, view Reminders dictionary in JavaScript mode to learn available properties. |
| 121 | 2) **Target List**: Get your list by name (e.g., `app.lists.byName('Work')`) or ID. |
| 122 | 3) **Filter**: Use `.whose` for queries (e.g., `reminders.whose({name: {_contains: 'meeting'}})`). For dates, use `_le |