Motivation

OmniFocus1 is a wonderful task management application. It runs on the Mac, iPad and iPhone, and I simply wouldn't be without it.

However, somewhat inexplicably, it's hard to import a list of tasks generated elsewhere into OmniFocus. Happily, the Mac application has a rich AppleScript API, so in principle one could use this to solve the task. In practice though I know very little AppleScript, and when I've tried to write command line scripts with it before, it's always been a pain.

So, I'd rather use a mainstream language with AppleScript bindings. Sadly the Perl interface seems a bit flakey and unloved, perhaps because the cool guys seem to use Ruby's rb_appscript2 for this sort of thing. I've not written much Ruby, but how hard can it be ?

Discussion

Happily there are a number of OmniFocus AppleScript examples floating around the web. Andy Schott's examples3 were helpful, as was browsing the OmniFocus dictionary with the AppleScript Editor application (File | Open Dictionary). The dictionary is particularly handy for details about the properties supported by each task.

The program tries to do as little work as possible. It takes data from a YAML4 file, treats them as simple task properties, and calls the relevant API. In most cases it's just a case of passing strings around, but there are three exceptions:

There's one other twist. Incoming fields beginning with an underscore aren't passed to the AppleScript API, rather they're understood as being 'internal' to the import process. Some of these are interpreted by the program:

Finally you can ask the program to dump a list of all the tasks it actually added.

Sample data

You'll probably generate the YAML with another program, but here's the sort of thing you should get:

---
- context: Administriva
  due date: 2010-12-24
  name: Blossom 2
  note: Cherry 2
  project: Auto
- context: Administriva
  due date: 2010-12-26
  name: Blossom 3
  note: Cherry 3
  project: Auto
  _no_dupes: 1

Practical Matters

You can download the program,5 but you'll then need to copy it to somewhere on your PATH.

To run it, you probably want something like this:

% of-import-yaml --help
...
% of-import-yaml tasks.yml
...
% of-import-yaml --output YAML tasks.yml

Internals

Internally the code is pretty simple. Simplified slightly in the interests of clarity, the basic core is shown below. Feel free to steal it for your own applications.

...

of = app('OmniFocus')
dd = of.default_document

...

add_task(dd, task)

...

def add_task(dd, props)

  proj_name = props["project"]
  proj      = dd.flattened_tasks[proj_name]

  ctx_name  = props["context"]
  ctx       = dd.flattened_contexts[ctx_name]

  tprops = props.inject({}) do |h, (k, v)|
    h[:"#{k}"] = v
    h
  end

  tprops.delete(:project)
  tprops[:context] = ctx

  t = dd.make(:new => :inbox_task, :with_properties => tprops)
  t.assigned_container.set(proj)

  return true
end

Disclaimer

I've used this program myself and it appears to work, but you should be aware that I know very little Ruby and even less AppleScript.

Ultimately, the program sends OmniFocus a series of commands asking it to modify your task lists, so it's perfectly possible that things will get trashed!

You should probably backup your OmniFocus data before playing with this.