Implementation Details for OmniFocus 2.14 Automation


#1

Automation in OmniFocus 2.14

OmniFocus 2.14 improves automation by adding support for two-way communication with other iOS apps.

In iOS, the primary way that apps talk to each other is through URLs. These are much like the URLs you enter into a web browser (in fact, you can enter these exact URLs into a web browser if you wish) and provide a mechanism for an app to transmit information to another app.

OmniFocus included support for automation through URLs on the day the App Store first launched, back in 2008. Back then, URLs were considered one-way mechanisms: one app could send something to another app, but that was it: the original iPhone would only run one app at a time, so the starting app was gone and would never hear anything back. But even that much was quite useful: for example, you could add a Safari bookmark which would send the current web page to OmniFocus. And many apps have taken advantage of this primitive mechanism from 2008 to send a new task to OmniFocus or to ask OmniFocus to show a particular item or perspective.

Well, how time flies! Fast forward eight years. Since 2008, the device hardware and the iOS operating system have both evolved significantly, and on most devices it’s now possible to have multiple apps running at the same time (one in the background)—and on some devices, you can even have two apps simultaneously running side-by-side.

And over those eight years, the app ecosystem has evolved as well. Many apps—like Workflow, Editorial, Drafts, 1Writer, and Ulysses—now support two-way communication by through the use of “callback” URLs, as proposed at x-callback-url.com. Using those apps you can build automation workflows that no longer stop the moment you transfer control to another app: when that app finishes its work, it uses a different URL to “call back” to the next step in the workflow.

With OmniFocus 2.14, I’m very pleased to be able to say that OmniFocus now includes best-of-class support for callback URLs. At its simplest, this means that you can create a workflow that adds more than one item to OmniFocus. But we didn’t just add support for two-way communication between OmniFocus and other apps, we added support for doing for automating a whole lot more of the powerful capabilities of OmniFocus.

This means, for example, that you can now create a text file outlining an entire project, with placeholders for specific names, defer dates, due dates, and so on. You can then run a workflow that processes those placeholders and builds a new project (such as “Run a marathon on June 30”) from that project template, and these project templates and their processing workflows can be shared with others.

But that’s just one possible workflow which is enabled by automation. You can also use the time estimates and dates already entered into OmniFocus to schedule tasks on a calendar. Or you could build a workflow which publishes the status of all the tasks in a project. We’ve just barely begun to explore the possibilities!

So that’s what this release is about.


Implementation Details

What follows is a description of the app-to-app interface that can now be used by other apps when talking to OmniFocus. The target audience for this is app developers, who need to see exactly what to do to get their app talking to OmniFocus.

URL Actions

OmniFocus URLs take the form omnifocus:///action?parameter=value&…. Parameter values should be URL-escaped. For two-way communication between apps, OmniFocus uses the protocol described by x-callback-url.com. The quick summary is that each command accepts optional query parameters x-success, x-cancel, and x-error; their values indicate how OmniFocus should continue the current automation workflow.

Here are the supported URL actions:

Data Entry

  • /add?name=name&… - creates a single task

    • name=string - the name of the new task
    • note=string - its note
    • estimate=time span - time estimate, e.g. 2h for 2 hours or 3w for 3 weeks.
    • flag=bool - whether the item is flagged (true or false)
    • parallel=bool - whether children are parallel (true) or sequential (false)
    • autocomplete=bool - whether the item automatically completes itself when its children are complete
    • defer=date - defer until date, e.g. 2016-04-19 5pm or next Thursday -3d
    • due=date - due on date
    • completed=date - completed on date
    • repeat-method=method - the repeat method: fixed, start-after-completion, or due-after-completion
    • repeat-rule=rule - an ICS repeat rule (see RFC2445), e.g. FREQ=WEEKLY;INTERVAL=1
    • project=string - the project to assign
    • context=string - the context to assign
    • attachment-name=string - attachment file name, repeated as necessary for multiple attachments
    • attachment=attachment-data - base-64 encoded file content, repeated as necessary
    • reveal-new-item=bool - whether to navigate to the newly created item (true or false)

    Callback: on success, the result query parameter will contain a URL that can be used to navigate to that task (e.g. omnifocus:///task/abc123), while the parent query parameter will contain the URL for the assigned parent project (if any).

  • /paste - pastes a hierarchy of items into the Inbox or project list

    • target=target - use inbox to create new inbox items, or projects to create top-level projects
    • index=number - where the new item should appear in the list: 1 (top) to n or -1 (bottom) to -n
    • content=TaskPaper string - the content to paste, in TaskPaper format (if unspecified, will read text from the pasteboard)

    Callback: on success, the result query parameter will contain a URL that can be used to navigate to that task (e.g. omnifocus:///task/abc123).

Navigation

  • /home - navigates to the top level of the app
  • /inbox - navigates to Inbox
  • /projects - navigates to Projects
  • /contexts - navigates to Contexts
  • /nearby - navigates to Nearby
  • /forecast - navigates to Forecast
  • /flagged - navigates to Flagged
  • /review - navigates to Review
  • /search?q=string - opens the search view
  • /context/context-id - navigates to a context
  • /folder/folder-id - navigates to a folder
  • /perspective/perspective-id - navigates to a custom perspective
  • /task/task-id - navigates to a project or action

General

  • /app-info - returns information about the current OmniFocus version
  • /parse-date?input=string - parses a date (e.g. next thu 5pm, or 7/1 -90d) based on current locale settings

Sharing

While viewing a task or project, you can use the Share button to send that task to another app.

Several representations of the task are included on the pasteboard:

  • TaskPaper text - TaskPaper text is the most human-readable representation of a task, suitable for copying into any text editor. See below for details.

  • Navigation URL - A simple navigation URL will be placed on the pasteboard.

  • Reference URL - A long navigation URL with a fully populated set of parameters (just like the /add URL action). This URL does not include attachments at the moment; if those attachments would be useful to you, please let us know!

TaskPaper Format

TaskPaper text is a simple but flexible format for representing tasks as text. It can be edited with any text editor. Quoting from the TaskPaper Users Guide:

TaskPaper’s file format is fairly simple. Here’s how TaskPaper reads a file:

  • Files are expected to use the UTF-8 encoding and use ‘\n’ to separate lines.

  • A task is a line that begins with a hyphen followed by a space (’- ') which can optionally be prefixed (i.e indented) with tabs or spaces. A task can have zero or more tags anywhere on the line (not just trailing at the end).

  • A project is a line that isn’t a task and ends with a colon (’:’), or a colon (’:\n’) followed by a newline. Tags can exist after the colon, but if any non-tag text is present, then it won’t be recognized as a project.

  • A note is any line that doesn’t match the task or project rules.

  • Indentation level (with tabs, not spaces) defines ownership. For instance, if you indent one task under another task, then it is considered a subtask. Tasks and notes own all objects that are indented underneath them. Empty lines are ignored when calculating ownership.

  • A tag has the form “@tag”, i.e. it starts with an “at” character ("@"), followed by a run of non-whitespace characters. A tag can optionally have a value assigned to it. The value syntax immediately follows the tag word (no whitespace between) and is enclosed by parentheses: ‘(’ and ‘)’. The value text inside can have whitespace, but no newlines. Here is an example of a tag with a value: @tag(tag’s value)

As you can see, one issue with this format is that TaskPaper doesn’t have any mechanism for escaping arbitrary content, so this representation can be lossy. For example, a task name that includes the text @flagged will see that text disappear from its name and the task will end up being flagged. And you can’t begin a note with a -. (To prevent mishap, on export we substitute any leading - characters in notes with en-dash characters.)

In general, OmniFocus tries to use the same names for tags that it uses for parameters in the /add URL action, with a few modifications (like @done) to match the way other apps interpret TaskPaper content.

OmniFocus currently supports the following tags:

  • @estimate(time span) - time estimate, e.g. 2h for 2 hours or 3w for 3 weeks.
  • @flagged - present when an item is flagged
  • @parallel(bool) - whether children are parallel (true) or sequential (false)
  • @autodone(bool) - whether the item automatically completes itself when its children are complete (named to match @done)
  • @defer(date) - defer until date, e.g. 2016-04-19 5pm or next Thursday -3d
  • @due(date) - due on date
  • @done(date) - completed on date
  • @repeat-method(method) - the repeat method: fixed, start-after-completion, or due-after-completion
  • @repeat-rule(rule) - an ICS repeat rule (see RFC2445), e.g. FREQ=WEEKLY;INTERVAL=1
  • @context(string) - the context to assign

If you’ve read this far, I hope you’ve gained a clearer understanding of how all of this works. If anything was confusing or left you with unanswered questions, please don’t hesitate to contact us!


Export and import projects from OF
Are location-based contexts actually useful?
Automation in OmniFocus 2.14 (released 2016-04-26)
Current status of OmniFocus automation in one place?
Is there a Web flavor or API available?
Taskpaper Sync to OmniFocus from Windows OS
Repeated Use of Workflow Taskpaper into Omnifocus creates duplicate project names
Thank you for the copy-pasting of plain text lists
Automation in OmniFocus 2.14 (released 2016-04-26)
X-callback-url to create Inbox item without item details screen
What kind of text format I can use to Import my list of projects and their actions to Omnifocus
Automation in OmniFocus 2.14 (released 2016-04-26)
#2

Very useful, thanks!

How about importing project templates to a folder within OmniFocus like so:

- New Project @folder(Personal)
    - Task 01
    - Task 02
    - etc.

#3

The missing piece ! Thanks for that.

Why 2 words for the same function (if I understand well) :

  • autocomplete
  • autodone ?

Regarding this functionality, I could not find a way to mark a project or group action to autocomplete directly within the app. Is it only available through the url scheme ?


#4

The plan for the future is that the /paste URL action will accept folder names as targets, not just the “inbox” and “projects” options it currently accepts.

I’m not wholly convinced that I made the right choice here, but since TaskPaper documents call completed items “@done”, for internal consistency (within the format) I went with “@autodone” to match it. (So in TaskPaper we have “@done” and “@autodone”, while in the URL action we have “complete” and “autocomplete”.)

The autocomplete setting has always been available on Mac, but this is the first time you’ve been able to choose that setting on iOS.


#5

Ah, excellent.


#6

I remember that there were some bugs (format misapprehensions) in an earlier OmniFocus translator for the TaskPaper format, and I notice that you are using a very old reference document there. Probably worth checking with current documentation:

http://guide.taskpaper.com/getting_started.html

In particular, do be clear that the following is not a project followed by its tasks:

Project:
- task 1
- task 2
- task 3

It is a project followed by three top-level miscellaneous tasks which are its peers and not its children – nesting (parent child relations) in TaskPaper is only by tabs – this allows for notes and miscellaneous items which are not in a project. To test this, experiment with folding and filtering operations in a https://www.taskpaper.com/ outline.

A Project containing three tasks would look like this, where the whitespace indent is a tab:

Project:
    - child task 1
    - child task 2
    - child task 3

( I think one of your recent template examples also seemed to be referring to a parent task as a ‘project’ )

Remember also that TaskPaper projects nest – There is no restriction on the depth of sub-projects – and can therefore be mapped onto folder nests as well as onto projects, tasks and sub-tasks.


#7

This sidesteps the problem of specifying folders in the Taskpaper format when trying to add tasks, but as I understand it the problem remains for copying OmniFocus structures as Taskpaper lists. Currently this is not possible for folders - they currently do not even have a share option from which to copy (only status, move, and delete).

If Taskpaper is indeed to become the cannonical Pasteboard format of choice, this would be great to have in some way.


#8

3 posts were split to a new topic: Mapping OmniFocus structures to TaskPaper


Mapping OmniFocus structures to TaskPaper
#9

That will be very helpful. Along similar lines, are there plans to allow a specific project to be specified as a target?

The new “Paste” option is very useful for adding groups of tasks, but sometimes I just want to add several items to a single action list, or a sub-project to an existing project. Current TaskPaper parsing doesn’t seem to provide any way to accomplish this, unless I’m missing something…


#10

Yes, the plan is to let you specify either. (Perhaps even a task within a project, if you know its reference URL.)


#11

This is fantastic to have (I’m using editorial).

The only things I am missing, in order of decreasing importance:

  1. The ability to make a project in a folder.
  2. My taskpaper syncs via dropbox… something on OSX that can use these templates in the same way that the editorial workflow can in iOS.
  3. Conditional tasks (I want to say ‘if variable = x then delete this task’ - this lets me set a variable when running a task that gives very different lists (trivial - if a packing list for a trip is ‘abroad’ include the ‘passport’ item, otherwise delete it).
  4. Variable options (select from a list of options, rather than typing in the item).

#12

This is fantastic!

Just wondering what the taskpaper syntax is for assigning a nested context:

Tried these but none worked

- «JiraNo» @parallel(false)
    - Task 1 @context(Work:Coding)
    - Task 2 @context(Work/Coding)
    - Task 3 @context(Work Coding)

Any ideas?


#14

Try @context(Work : Coding). (You can also use Coding if that’s the first Coding context in your context hierarchy.)

One way to figure this sort of thing out using the app itself is to create a project or task laid out the way you want it to be in OmniFocus (e.g., create a task and assign it to Work : Coding), then use the Share button to copy to to your pasteboard.


#15

Great - thanks, the spaces either side of the colon did the trick!


#16

I think I’ve found a bug…

I have been making taskpaper tasks with things like this - but when I enter a date like ‘next monday’ the due date ends up before the defer - and when I use a date like 1/1/2017 it puts both dates as 31/12/2016

 - Pack for «Trip Name»  @defer(«dateoftrip»-8d 9am) @due(«dateoftrip»-1d 9am) @autodone(true) @parallel(true)
	- Pack Hand Luggage for «Trip Name» Trip @autodone(true)
		- Plane specific items for «Trip Name» @autodone(true)
			- Thing 1 for «Trip Name» trip
			- Thing 2 «Trip Name»
			- Thing 3 «Trip Name»
		- Pack Documents for «Trip Name» @autodone(true)
			- Airport Car Park Info for «Trip Name»
			- Plane info for «Trip Name»

#17

I have the fix, I need to enter dates as yyyy-mm-dd - not the end of the world, but dd/mm/yyyy would be nice (though you’d have to play nice with mm/dd/yyyy - probably take from user preference)


#18

Interestingly, “1/1/2017” on its own works just fine—it’s just going awry somewhere when it tries to perform the relative manipulation of that date (“1/1/2017 -8d 9am”). Which is strange, since (as you note) the ISO form doesn’t have this issue.

We look at the current locale’s date format to determine the preferred date order, but no matter what locale you’re using we generate and accept dates in the ISO “2017-01-01” format (since otherwise we can end up in situations where the user’s preferred format doesn’t actually include information we need, e.g. “1/1” without a year).


#19

I’ll leave that one in your inbox, then :)

In the meantime, I’ve renamed my variable as «travel yyyy-mm-dd» to give me a reminder when I need it.


#20

I think the new TaskPaper parser has a regex bug.

In TaskPaper I often put the due date first in order to prioritize/sort when viewing a list of tasks due dates:

  • @due(2016-05-01) thing 1
  • @due(2016-06-01) thing 2
    Etc.

When I try to use “omnifocus:///paste” or the Editorial workflow to capture and convert these, the OF task name includes the “@due” part and the due date is not parsed into the OF task.

Perhaps this isn’t blackletter TaskPaper syntax, but I feel that OF should handle this and I imagine that it would be easy to fix.


#21

“something on OSX that can use these templates in the same way that the editorial workflow can in iOS”

interestingly calling an omnifocus:// url on the mac does open OmniFocus , but none of the other actions do anything. Given how robust the AppleScript support in OF for Mac is, it wouldn’t be too hard to write a URL handler that takes an OF URL and executes the actions via AppleScript. Except for callbacks. It wouldn’t surprise me if this came in an update to OF for Mac eventually.