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.
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.
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-error; their values indicate how OmniFocus should continue the current automation workflow.
Here are the supported URL actions:
- /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 (
- parallel=bool - whether children are parallel (
true) or sequential (
- 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:
- repeat-rule=rule - an ICS repeat rule (see RFC2445), e.g.
- 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 (
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`).
- /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
- /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
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 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
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 (
@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:
@repeat-rule(rule) - an ICS repeat rule (see RFC2445), e.g.
@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!