Cleaning out old Reminders

As I read my RSS feed during lunch today, I came across this post by Dan Moren at Six Colors, in which he complains, rightly, that Apple’s Reminders apps—Mac and iOS—have no automated or manual way to clean out old completed tasks.

It would be great if… Apple provided an option to have those completed tasks automatically deleted after a certain amount of time—30 days would work great for me—and even better if it allowed you to choose the interval.

Given that Reminders has a fairly decent AppleScript dictionary, I figured it’d be easy to write a script that would do what Dan wanted. And it was.

First, though, I should mention that there’s been very little testing of this script. I made up a bunch of fake reminders in different lists, and wrote the script initially to delete all completed tasks that were more than 5 minutes old. That worked, so I think the 30-day revision should also work. But you may want to think about backups before implementing this.

Also, are you sure you want to delete all your old completed reminders? Maybe some of them would be good to have around to prove—to yourself, at least—what you did and when you did it.

End of caveats. Let’s look at the script, which I’ve named “Purge Old Reminders.”

 1:  set monthago to (current date) - (30 * days)
 3:  tell application "Reminders"
 4:    set myLists to name of every list
 5:    repeat with thisList in myLists
 6:      tell list thisList
 7:        delete (every reminder whose completion date is less than monthago)
 8:      end tell
 9:    end repeat
10:  end tell

Line 1 determines the date 30 days ago and saves it in the variable monthago. Line 4 gets the names of all your Reminders lists and puts them in the variable myLists. Lines 5–9 then loop through all your lists, deleting all the reminders with a completion date that falls before monthago. That’s it.

If you want to change how old a completed reminder has to be before it gets purged, change the (30 * days) part in Line 1 to whatever you prefer. If you don’t want all your lists purged, change Line 4 to something like

set myLists to {"Groceries", "Hardware", "Packing"}

where the braces enclose a comma-separated list of the names of the lists you want to purge with the names in double quotes.

You can, of course, just run this script by hand whenever you get the hankering to purge your old completed reminders, but the cool thing is to set up a system to run it periodically.

The standard way to run scripts periodically in macOS is to use the launchd system. If you want to go that way, I’d suggest you get a copy of LaunchControl, a $10 app that makes the creation and scheduling of launchd services relatively painless. Or you can read Nathan Grigg’s excellent launchd tutorial, which you should probably do even if you do buy LaunchControl. Either way, you’ll end up with a plist file that looks something like this:

 1:  <?xml version="1.0" encoding="UTF-8"?>
 2:  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "">
 3:  <plist version="1.0">
 4:  <dict>
 5:    <key>Label</key>
 6:    <string>com.leancrew.purge</string>
 7:    <key>ProgramArguments</key>
 8:    <array>
 9:      <string>/usr/bin/osascript</string>
10:      <string>/Users/drdrang/Dropbox/bin/Purge Old Reminders.scpt</string>
11:    </array>
12:    <key>StartCalendarInterval</key>
13:    <array>
14:      <dict>
15:        <key>Hour</key>
16:        <integer>6</integer>
17:        <key>Minute</key>
18:        <integer>6</integer>
19:      </dict>
20:    </array>
21:  </dict>
22:  </plist>

Lines 8–11 run the AppleScript via the osascript command. You’ll need to change the path in Line 10 to wherever you have Purge Old Reminders stored. Lines 14–19 set the script to run every morning at 6:06. Change lines 16 and 18 to set the hour and minute you prefer. Save it to your ~/Library/LaunchAgents folder and follow Nathan’s instructions to use launchctl to load it.

If you own Keyboard Maestro, you can avoid launchd by creating a macro with a timed trigger to run the script.

Purge Old Reminders macro

I’m not sure how Keyboard Maestro handles macros that got triggered when it wasn’t on, so you may want to change it to a time that you’re likely to be at your computer. Frankly, it’s no big deal if the script doesn’t run for a few days.

There used to be a simple way to run scripts periodically using Calendar, but Apple has either deleted that function or hidden it well. I suspect there are other methods using other third-party apps, but I don’t want to recommend anything I haven’t used myself.

Update 04/25/2017 10:59 AM
I have Reminders open all the time, so I didn’t think about the script possibly needing to quit the app after it’s done. But Vítor Galvão did, so here’s an update with his changes. This version checks to see if Reminders is already running in Line 1; if it isn’t, it quits in Line 11 after deleting the old completed reminders.

 1:  set remindersOpen to application "Reminders" is running
 2:  set monthAgo to (current date) - (30 * days)
 4:  tell application "Reminders"
 5:    set myLists to name of every list
 6:    repeat with thisList in myLists
 7:      tell list thisList
 8:        delete (every reminder whose completion date is less than monthago)
 9:      end tell
10:    end repeat
11:    if not remindersOpen then quit
12:  end tell

Thanks, Vítor!