How to Create OmniFocus Projects with TaskPaper and JavaScript for Automation

A Little Automation Goes a Long Way

by Colter Reed
2:07 read (647 words)
In automation, simplicity is key.
by Colter Reed
2:07 read (647 words)
In automation, simplicity is key.

TaskPaper is a great format for copying and pasting tasks and projects between OmniFocus and other apps. You can also use it with Shortcuts to create dynamic projects on iOS.

I’ve been scripting OmniFocus for years now. It lets me add my own features to OmniFocus. But I’ve fallen into the same trap into which every automator eventually tumbles:

Overengineering.

The first rule of automation is to keep it simple. Start with the simplest thing that could possibly work. The more complicated a script is, the harder it is to debug and the harder it is to extend.

Take, for example, a project to pay the rent:

Pay Rent
 - Write out check
 - Drop off rent check

I’ve scripted this with AppleScript. It’s overkill, but I had a hammer and so it looked like a nail.

(In my defense, I think I did that before OmniFocus supported TaskPaper. And once you have an automation in place, the second rule of automation kicks in: if it ain’t broke, don’t fix it.)

You can create most projects with a little TaskPaper:

Pay Rent @due(next month) @tag(Home) @parallel(false)
 - Write out rent check
 - Drop off rent check

Paste that into OmniFocus and it will create your Pay Rent project.

If you want to have it created for you automatically, here’s a JavaScript for Automation (JXA) script that will create the project for you.

var TaskPaperText = "\n\
Pay Rent @due(next month) @tag(Home) @parallel(false)\n\
 - Write out rent check\n\
 - Drop off rent check\n\
"
var TaskPaperURL = "omnifocus:///paste?target=projects&content=" + encodeURIComponent(TaskPaperText)

var app = Application.currentApplication()
app.includeStandardAdditions = true
app.openLocation(TaskPaperURL)

The script only sends the TaskPaper to OmniFocus; that part isn’t likely to change. If you need to edit the project itself, you can easily make changes to the TaskPaper content without worrying about breaking the entire script.

That will get you pretty far. You could stop right now and have a perfectly valid script to create a Pay Rent project.

This is the point where I should stop more often than I do.

But there’s a limit to what TaskPaper can express for due dates and defer dates. I don’t want this project due at midnight on the first of the month. I want it due at 5pm on the last day of this month. And I don’t want to worry about it until the last week of the month.

So let’s add a touch of scripting to tweak the TaskPaper.

//
// Calculate the date strings we need
//
var date = new Date()              // Start with today
date.setDate(1)                    // Go to the first…
date.setMonth(date.getMonth() + 1) // …of next month
var month_name = Intl.DateTimeFormat('en-us', { month: 'long' }).format(date)

date.setDate(0)                    // Go to the first of the previous (this) month
var due_date = Intl.DateTimeFormat().format(date) + " 5pm"
date.setDate(date.getDate() - 6)   // Go back 6 more days (1 week)
var defer_date = Intl.DateTimeFormat().format(date) + " 6am"


//
// Create the TaskPaper text
//
var TaskPaperText = "\n\
Pay MONTH_NAME Rent @defer(DEFER_DATE) @due(DUE_DATE) @parallel(false)\n\
 - Write out rent check\n\
 - Drop off rent check\n\
"
TaskPaperText = TaskPaperText.replace("MONTH_NAME", month_name)
TaskPaperText = TaskPaperText.replace("DEFER_DATE", defer_date)
TaskPaperText = TaskPaperText.replace("DUE_DATE", due_date)


//
// Send the text to OmniFocus
//
var TaskPaperURL = "omnifocus:///paste?target=projects&content=" + encodeURIComponent(TaskPaperText)

var app = Application.currentApplication()
app.includeStandardAdditions = true
app.openLocation(TaskPaperURL)

This script is still using mostly TaskPaper to create the project. Only the dates are calculated. This is still going to be easy to adjust.

Programmatically, you can do just about anything. But there’s a lot you can do that doesn’t involve writing a line of code. You could copy and paste the same TaskPaper project every month. Or you could set up bill pay and have the rent check delivered automatically.

When you do decide it’s time to introduce scripting to an automation, do so gradually. Only script what needs to be scripted. Look for the simplest solution that could possibly work. Simple automations are easy to debug, update, and reuse to solve new and evolving problems. Complex automations may create more problems than they solve.

Question: What is one automation you over-engineered? Share your thoughts in the comments, on Twitter, LinkedIn, or Facebook.