Adding time tracking to OmniFocus using JXA

TL;DR - I am using JXA to add time tracking features to OmniFocus, generating reports based on how much time I spend on tasks. Link to the code at the bottom of the page.

The land of productivity applications seems to follow an unwritten law that apparently forbids developers from releasing good task managers with native, well-integrated, easy to use time-tracking features.

Todoist? Nope. Remember the Milk? Nada. Things? Nee. Dynalist? Nei. Workflowy? Net. OmniFocus? Não.

Even when graduating from task managers to project managers, time tracking is usually available solely through integrations with third-party trackers, often at significant additional costs. From Asana to JIRA, time tracking is never a given.

What the heck? How can this be? I understand that not everyone is interested in time tracking but there’s plenty of users and companies who definitely are, as evidenced by the proliferation of Toggl integrations.

Frustrated with the current state of things, I’ve decided to experiment with Mac OS’ automation features (which I’ve been meaning to look into for a while) to figure out whether I could add basic time tracking support to my workflow, which revolves around the wonderful OmniFocus.

I am happy to report that I’ve successfully managed to produce simple reports out of time spent entries in the notes section of my tasks on OmniFocus. These first attempts have resulted in the ofutils command-line utility, written in Node.js and available via its repository on GitHub.

Node.js? Indeed! While automation on Mac OS has traditionally been implemented using AppleScript, Apple has recently added support for JXA - JavaScript for Automation - as an additional scripting language in Mac OS. As a JavaScript developer focusing on Node.js and backend development, this is music to my ears.

JavaScript for Automation (JXA) is an OSA (Open Scripting Architecture) scripting language in macOS. Introduced in OS X Yosemite, JXA is a peer of the AppleScript language and as such has access to all macOS scriptable apps, frameworks, and native UNIX utilities.

However, a quick look on NPM brought me to the osa2 package, which gave me a clear idea of JXA’s main issue: all code must be passed to the OSA engine as a single, pure, serialized function which cannot reference anything outside of its own body (including npm packages). This makes writing well-structured OSA code significantly harder and resulted in some creative (if slightly convoluted) use of the evalfunction, which made me feel like a black magic wizard.

Another issue I’ve encountered is the lack of documentation on JXA, both
official and community-curated. I suspect that this is due to a relative lack of adoption motivated by the subpar development experience brought by having to work around the serialization issue mentioned above.

These two issues aside, I was pleasantly surprised at how quickly JXA allowed me to work around the lack of time tracking in OmniFocus. Reports might not be much to look at, for the time being, but they have already proven to be very useful in my day to day work. Ultimately, this is really a win for Mac OS and its OSA engine, alongside Omni’s support of scripting within their flagship application. Ultimately, as a user, these are the sort of APIs that truly ensure my being in control of my own data.

Check out the repository on GitHub!