Writing OmniFocus scripts using TypeScript

OmniFocus 4 is coming soon! In my years of managing my to-do list, I have tried almost all the to-do software on the market, such as Todoist, TickTick, Things, Sorted, and so on. But in the end, OmniFocus has become my ultimate choice. When it comes to the power of OmniFocus, we cannot ignore its powerful automation capability - Omni Automation.

Omni Automation is actually based on JS scripts, and the process of writing pure JS scripts... is hard to describe in a few words. Although Omni Automation officially provides TypeScript definition files, on the one hand, it is difficult to perform type checking well, and on the other hand, its comprehensiveness still needs improvement (long-term lack of updates, extensive use of 'any', etc.). In addition, due to the lack of packaging tools, code logic reuse is also quite difficult (I even relied on a bug in the Mac version of OmniFocus for a long time to achieve logic reuse).

To celebrate the release of OmniFocus 4, I decided to organize and open source the solution I personally developed and used, including packaging scripts and type definitions, as well as some utility functions and scripts I used, hoping to allow more people to write OmniFocus Scripts happily.


  1. Create a repository using this template: Use this template
  2. Clone the repository you created
  3. Run pnpm install to install dependencies
  4. Run pnpm build to build the script

The script source code is located in the src directory, and the compiled result (usable by OmniFocus Scripts) is located in the dist directory.

Writing Scripts#

Any TypeScript file in the src directory that does not start with _ will be treated as an OmniFocus script and compiled (_-prefixed script files are reserved for utility functions).

Any script must follow the following pattern:

export const action = new PlugIn.Action(function (selection) {
  // do anything you want

action.validate = function (selection) {
  // do anything you want

export const meta: Meta = {
  label: "...",
  description: "...",
  identifier: "...",
  author: "...",
  version: "0.1",


  1. action and meta are required, action.validate is optional
  2. meta must be the last part of the script. There should be no content after it.

Building and Using#

Run pnpm build, and the built script (ending with .omnifocusjs) will be placed in the dist directory.

You can directly copy the scripts in the dist directory to OmniFocus's script directory, or use the script for synchronization.

If you use iCloud to save OmniFocus scripts, you can use pnpm sync to automatically sync the built scripts to the OmniFocus script directory in iCloud. If you don't use iCloud and use a custom path instead, you can modify the file to change the target path.


I have personally used this solution for over a year, but on the one hand, the open source version may have some errors, and on the other hand, there may be more customization needs.

Feel free to submit issues and PRs on the repository page!

Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.