Weekly Review in Things with AppleScript and Keyboard Maestro

#1

Introduction
I love Things as task manager. I have used many many different task managers in the past (Omnifocus, Taskpaper, Todoist, Rememberthemilk, Evernote), but it seems that Things sticks with me. I’m using it for more than a year now and that is longer than any other task manager before.

I’m also a GTD practitioner. It is a system that works for me. The only aspect that was always difficult for me to implement is the weekly review. But I think I found the problem and hopefully a solution.

The problem is that I have more to-dos in my system that I can handle during a weekly review. I would like to be able to pause the review process when necessary. In the ideal world, I can work on a review for say 10 minutes, pause it and resume later. Furthermore, I discovered that not all to-dos need a weekly review. Some I need to see next week, others in 4 weeks and maybe some in 3 months.

This means I need some kind of support from my task manager to manage the weekly review. I came up with the following process that consists of three stages: 1) start the weekly review, 2) do the weekly review, and 3) stop the weekly review. During stage 1, all to-dos that need a review get flagged (with the ‘ToReview’ tag). In stage 2 I will review every task with the ‘ToReview’ tag and give it a date for the next review and during stage 3 the ‘ToReview’ tag is removed from every to-do.

Inspired by Automators, I was wondering if I could build this functionality myself with a combination of Keyboard Maestro and AppleScript. Turns out, I can. So here is what I did.

Implementation

The 3 stages are 3 separate AppleScripts.

AppleScript for Stage 2 - Update Next Review Date

tell application "Keyboard Maestro Engine"
	set aantalWeken to getvariable "NextReview"
end tell

set nextReviewDate to current date
set nextReviewDate to nextReviewDate + (aantalWeken * weeks)
tell application "Things3"
	set reviewString to (year of nextReviewDate) * 10000 + (month of nextReviewDate) * 100 + (day of nextReviewDate) as text
	set reviewString to "-NR" & text 3 thru 8 of reviewString
	set listOfToDos to selected to dos
	repeat with selectedToDo in listOfToDos
		set noteText to selectedToDo's notes as text
		if noteText contains "-NR" then
			set start to offset of "-NR" in noteText
			set oudeReview to text start thru (start + 8) of noteText
			set the noteText to my replace_chars(noteText, oudeReview, "")
		end if
		set noteText to noteText & reviewString
		set selectedToDo's notes to noteText
		set tagNames to tag names of selectedToDo
		set tagNames to my replace_chars(tagNames, "ToReview", "")
		set tag names of selectedToDo to tagNames
	end repeat
end tell

on replace_chars(this_text, search_string, replacement_string)
	set AppleScript's text item delimiters to the search_string
	set the item_list to every text item of this_text
	set AppleScript's text item delimiters to the replacement_string
	set this_text to the item_list as string
	set AppleScript's text item delimiters to ""
	return this_text
end replace_chars

I’ll start with the script for stage 2 (doing the review). It’s the most complex one. I’ve created a keyboard maestro macro that asks for the number of weeks for the next review (for the selected tasks). It stores this number in a variable and starts the AppleScript.


The script then reads this variable and uses it to determine the next review date by taking the current date and adding the number of weeks to it. Then it switches to the Things application. It converts the next review date to a string with the following format: -NRYYMMDD (I use -NR prefix to make it easier to recognize it between all other information in the notes field). In the next step the script stores the selected to-dos in a list and loops through this list. For every selected to do, it checks if the note of the to-do already contains a string that starts with -NR and if so it replaces this string with the new review date. If there is no -NR string than the new review date is added at the end of the to-do’s note. Finally the script deletes the ‘ToReview’ tag from the to-do. By using the selected to-dos it is possible to give a whole bunch of tasks the same next review date with a single keystroke.

AppleScript for Stage 1 - Start Review

display dialog "When is the next review" default answer "yymmdd"
set nextReview to text returned of result

tell application "Things3"
	repeat with toDo in to dos
		if toDo's status is not equal to "completed" then
			set notesText to (the toDo's notes as text)
			if notesText contains "-NR" then
				set start to offset of "-NR" in notesText
				set reviewDate to text (start + 3) through (start + 8) of notesText
				if reviewDate ≤ nextReview then
					set tagNames to tag names of toDo
					set tagNames to tagNames & ",ToReview"
					set tag names of toDo to tagNames
				end if
			else
				set tagNames to tag names of toDo
				set tagNames to tagNames & ",ToReview"
				set tag names of toDo to tagNames
			end if
		end if
	end repeat
end tell

The AppleScript for stage 1 starts the review process. It first displays a dialog and asks the user for a date for the next review. Then it checks for every open to-do in Things if it has a review date and if it is before the next review. If so it will flag the the to-do with the ‘ToReview’ tag. If a to-do has no next review date (meaning it has never been reviewed before) it will get the ‘ToReview’ tag by default.

When this script has run I can search in Things for all tasks with the tag ‘ToReview’ and Things will give me a nice list that contains all the tasks that need reviewing.

AppleScript for Stage 3 - Stop Review

tell application "Things3"
	set aTag to tag "ToReview"
	delete aTag
end tell

The last AppleScript for stage 3 (stopping the review) is very simple. It just deletes the tag ‘ToReview’. By deleting the tag itself, it is automatically deleted from all tasks.

If I want to resume my review I just restart the script for stage 1 and it will immediately give me a list of tasks that need reviewing.

Final Thoughts
Some final thougths. I’ve used two different methods to get input from the user 1) via a dialog triggered by Keyboard Maestro, and 2) via a dialog triggered by AppleScript itself. There is no special reason for this, I was just experimenting.

You do not need Keyboard Maestro to get this to work. You can also bind the different AppleScripts to short-cuts via the system preferences.

This was my very first experiment with AppleScript. Love to see in the comments how the script could be improved. Hope it will give some inspiration for your own experiments.

9 Likes
#2

This should be helpful for those people who prefer to use Things but want something like the Review feature of OmniFocus. Very nice work!

One issue I see is that one could have a single URL as the note of a to do. In that case, your script could wreck the URL by tacking the -NR directly to the end of it. You could probably solve this a few different ways but I would probably just insert a linefeed or two (to insert returns) before writing the ‘-NR…’ string the first time:

set noteText to selectedToDo's notes as text
if noteText contains "-NR" then
	set start to offset of "-NR" in noteText
	set oudeReview to text start thru (start + 8) of noteText
	set the noteText to my replace_chars(noteText, oudeReview, "")
else
	set noteText to noteText & linefeed
end if
set noteText to noteText & reviewString

You could be clever and only write the linefeeds if the note’s not empty, but I might be inclined to leave the space there in case I come along to add a note later.

1 Like
#4

Excellent Idea that I’m going to implement! Thanks.

1 Like
#5

I like the approach; I think the ability of OmniFocus to have a structured review process is one of its strength and certainly one of Things’ weaknesses. Here are some random thoughts:

  1. Wouldn’t it be easier to use tags for reviews? So instead of poking at the note of the task add a tag called NRYYMMDD? I guess it depends on how your things are structured. If you plan your reviews very detailed, there might be an overwhelming number of tags.

  2. In step 1, you can ask the system to open the URL things:///show?query=ToReview and get right into the correct view. Just adding open location "things:///show?query=ToReview" as the last line of the script should do the trick

  3. I personally would probably want to pick a specific day to do such reviews, for example, do reviews on Fridays. So when I say: Review in three weeks, but it is Monday, the script would automatically select the next/previous (depending on preference) Friday as the review date.

  4. Another change I could see for me is changing the date format to YYYYMMDD which triggers my brain to register as a date better. I don’t think that’s important for the functionality as the date is for the computer only anyway.

Thanks again for sharing and exploring the possibilities!

#6

What is “aantalWeken”?

#7

Dutch for number of weeks…

#8

Okay, thanks! Bing Translate failed me.