OmniFocus: “The Big Picture”
OmniFocus is an organizational tool for managing your time and efforts. It provides personalized access and customizable views into its central database that stores and organizes your data using the containers and descriptors: projects, folders, tasks, and tags.
Using its integrated Omni Automation support, you can streamline and automate OmniFocus procedures, and transfer and receive data to and from other applications like the project management application OmniPlan.
This page is designed to provide you a quick overview of the structure of the built-in Omni Automation support in OmniFocus.
“Action” or “Task”
When interacting with the OmniFocus application’s user-interface (UI for short), you will encounter the term “Action” which refers to a new to-do item for a project. However, in the OmniPlan application, such a time-related element is called a “Task.”
The Omni Automation support in OmniFocus considers the terms “action” and “task” to be functionally synonymous, and refers to the scriptable element representing an “action” as a “task.”
In other words: a “task” is a something that needs doing, and “action” is the element in the OmniFocus interface that represents that need or to-do item. Scripts reference tasks, and the graphical user-interface of OmniFocus references actions. In the following documentation, consider tasks to be equivalent to actions.
The Big Picture
Here is a visual overview of the scripting relationships in OmniFocus. Note that certain intermediate database classes used in the scripting application interface (API) do not appear in this illustration, but instead are described in detail in the OmniFocus Omni Automation documentation.
From a scripting point-of-view, here are some concepts to keep in mind:
- Tags, Folders, and Tasks (Actions) can all contain children of their own type.
- Folders can contain Folders and Projects
- Projects can contain only Tasks (Actions)
- Tasks (Actions) can contain other Tasks (Actions), in which case they become a Task Group (Action Group).
- Tags can contain other Tags, in which case they become a Tag Group.
- inbox is a property of the Database. The value of the inbox property is an array of references to the Tasks currently in the Inbox perspective.
- library is also a property of the Database. The value of the library property is an array of references to the top-level Projects and Folders in the database. Two other database properties: folders and projects can be used to return references to those top-level database items.
- tags is also a property of the Database. The value of the tags property is an array of references to the top-level Tags in the database.
Application
The heart of OmniFocus is its database. Most of your scripts will target the database and the objects and data it contains. The Application class is generally only addressed by scripts in order to determine the operating system environment, pressed modifier keys, and for opening archived documents.
In Omni Automation script statements, the Application object is represented by the abbreviation: app
Determine the Current Platform
app.platformName
//--> macOS or iOS
Open Document and Iterate Projects
app.openDocument(
document,
fileURL,
function(doc,wasOpen){
doc.windows[0].perspective = Perspective.BuiltIn.Projects
db = doc.windows[0].selection.database
db.projects.forEach((project)=>{
// processing goes here
})
}
)
Documents
Although documents are a top-level element of the OmniFocus application, the database, not the document, is the repository of the data. Typically, scripts reference the Document class to manage the data view and selection. In scripts, the current document is not referenced by appending the Application object, but is referenced instead as a top-level object, using the term: document
Get Document Name
document.name
//--> "OmniFocus"
For the sake of security, documents are not allowed to be accessed by scripts run in the consoles of other documents, so the application object will not return references to other documents.
Reference Other Documents
//--> these are not supported
app.documents.length
app.documents[0]
Document Windows
In the OmniFocus scripting implementation, the Window class is an element of the Document class, and so references to windows include their parent document object:
Document Windows
document.windows.length
And the current window is always the first item in the list (array) of open windows:
Current Window
document.windows[0]
Perspective
A Perspective is a view into your OmniFocus database that appears in the perspective list (left-side of OmniFocus window) and whose contents are detailed in the outline (on the right-side of the window).
OmniFocus comes with these built-in perspectives: Flagged, Forecast, Inbox, Nearby, Projects, Review, and Tags; and two transient reference perspectives: Completed and Changed. Custom perspectives can be created in OmniFocus Pro.
Perspective
// Get the name of the current perspective
document.windows[0].perspective.name
//--> "Projects"
// Change window view to show Inbox perspective
document.windows[0].perspective = Perspective.BuiltIn.Inbox
//--> [object Perspective.BuiltIn: Inbox]
// Change window view to show custom perspective
document.windows[0].perspective = Perspective.Custom.byName("Fairfield")
//--> [object Perspective.Custom: Fairfield]
Document Selection
A document’s selection is a property of the Window class, which in turn, belongs to the parent implied document. The Selection class includes properties whose values are arrays of references to the specified object types selected in the window: projects, folders, tags, tasks and others listed in the script example below.
Properties of the Selection Object
document.windows[0].selection.database
//--> [object Database]
document.windows[0].selection.folders
//--> [array of folder references]
document.windows[0].selection.projects
//--> [array of project references]
document.windows[0].selection.tags
//--> [array of tag references]
document.windows[0].selection.tasks
//--> [array of task references]
document.windows[0].selection.window
//--> [object DocumentWindow]
document.windows[0].selection.allObjects
//--> [array of instances of all objects in the selection, if any]
document.windows[0].selection.databaseObjects
//--> [array of all DatabaseObject objects in the selection, if any.]
document.windows[0].selection.document
//--> [object DatabaseDocument]
For example, here’s a simple script for getting the titles of the selected tasks:
Titles of Selected Tasks
var selectedTasks = document.windows[0].selection.tasks
taskTitles = selectedTasks.map(task => {return task.name})
Database
At the core of OmniFocus is a database that is used for the display and management of time-related data and schedules. To accomplish such data organization, OmniFocus relies on a variety of container components to segment the data and information, and to enable the creation of relationships between the various elements.
Folders, Projects, Tasks, and Tags are some of the scriptable database objects used as container for storing data and information. To provide scripting access to these database objects, the Omni Automation API (Application Programming Interface) for the central database includes the following properties whose values are references to the current set of related container types.
- library • The value of the library property is an array of object references to the top-level Projects and Folders in the database.
- projects • The value of the projects property is an array of object references to the top-level Projects in the database.
- folders • The value of the folders property is an array of object references to the top-level Folders in the database.
- inbox • The value of the inbox property is an array of object references to the top-level Tasks in the database (those in the the InBox Perspective).
- tags • The value of the tags property is an array of object references to the top-level Tags in the database.
- settings • The value of the settings property is an object reference to the Settings object that represents the database synchronized configuration values.
When using these properties in a script, remember that the Database is the topmost implied scripting object, which may be represented by the “this” enumeration. Therefore, database properties can be called simply entering them in a script statement without any preceding hierarchy.
For example, here is a script for iterating the current set of top-level Tasks in the InBox Perpective, represented by the database property: inbox
Iterate Top-Level Tasks
inbox.forEach((task)=>{
if (task.taskStatus === Task.Status.Available){
// processing statements go here
}
})
To iterate all tasks in the Inbox hierarchy — even those tasks within other tasks — use the apply(…) function:
Iterate All Tasks in Inbox Heiratchy
inbox.apply((task)=>{
if (task.taskStatus === Task.Status.Available){
// processing statements go here
}
})
NOTE: the apply(…) method can be called on the properties of the Database class whose value is a hierarchical collection: library, projects, folders, inbox, tags
Get Names of All Tags
var tagNames = new Array()
tags.apply((tag)=>{
if(!tagNames.includes(tag.name)){tagNames.push(tag.name)}
})
console.log(tagNames)
For more information regarding the use of the apply(…) function, see the section on Finding Items.
For your convenience, “flattened” versions of object hierarchies are available for easily parsing and processing database elements: flattenedTags, flattenedTasks, flattenedFolders, flattenedProjects, flattenedSections
The “flattened” properties return object hierarchies “flattened” into array of specific object type references, sorted by their order in the database. Use these database when it is necessary to process all of the existing instances of a particular class, such as Tasks:
Every Task Whose Title Begins with “Red”
//--> reference every task whose name begins with the word "Red"
var str = "Red "
var result = flattenedTasks.filter(task => task.name.startsWith(str))
Locating Database Items by Name
To make it possible to locate a specific top-level database element, such as a folder, project, task, or tag, identified by name, the Database class offers the following functions:
folderNamed(name:String) → (Folder or null) • Returns the first top-level folder with the given name, or null.
projectNamed(name:String) → (Project or null) • Returns the first top-level project with the given name, or null.
tagNamed(name:String) → (Tag or null) • Returns the first top-level tag with the given name, or null.
taskNamed(name:String) → (Task or null) • Returns the first top-level task in the inbox with the given name, or null.
Here is a script example that returns a reference to a top-level tag specified by name. If the tag does not already exist, it is created.
Reference to Tag Specified by Name
tag = tagNamed("Kitchen") || new Tag("Kitchen")
This technique can be used with any of the top-level database elements: folders, projects, tags, and tasks.
TIP: To scan the entire hierarchy of a class for the first item matching by name, execute the byName() function on the corresponding “flattened” property, such as in this example script that will return a reference to the first task whose name matches the provided value, creating a new task if required:
Reference to Task Specified by Name
task = flattenedTasks.byName("Build Shed") || new Task("Build Shed")
By default, database elements created using the new item constructor are inserted at the end of the list of elements. Here’s a variation of the previous script that uses a positional indicator to insert a new top-level element (if it doesn’t already exist) at the beginning of the container of elements. The result is a reference to the either the existing element or the newly created element:
Insert Task at Beginning of Inbox
taskName = "Clear Footings"
task = taskNamed(taskName) || new Task(taskName, inbox.beginning)
Built-In Search Functions
The Database class provides three generalized search functions for locating folders, projects, and tags that “smart match” the indicated string.
projectsMatching(search: String) → (Array of Project) • Returns each existing projects that Smart Matches the given search. The result will be in the same order and have the same projects as would be found when searching this string in the Quick Open window.
foldersMatching(search: String) → (Array of Folder) • Returns each existing folders that Smart Matches the given search. The result will be in the same order and have the same folders as would be found when searching this string in the Quick Open window.
tagsMatching(search: String) → (Array of Tag) • Returns each existing tags that Smart Matches the search. The result will be in the same order and have the same tags as would be found when searching this string in the Quick Open window.
Find Matching Tags
tagsMatching("Auto-")
//--> [[object Tag: Auto-Open], [object Tag: Auto-Close], [object Tag: Auto-Update]]
Other Database Functions
In OmniFocus, many of the functions that are normally applied to documents, such as performing a save, are instead done by the database, along with other commands for organizing, moving, duplicating, and deleting database elements.
For example, here is a script that uses positional properties of the Inbox Array class to add new Task instances to the beginning and end of the InBox, and saving the current state of the database.
Create Tasks and Save
new Task("New First Task", inbox.beginning)
new Task("New Last Task", inbox.ending)
this.save()
Here’s a script that uses the deleteObject() method remove all items from the InBox:
Clear InBox
inbox.forEach(tsk => deleteObject(tsk))
Other OmniFocus Items
Specific descriptions and examples for the database container objects and other OmniFocus scripting topics can be accessed in the navigation list at the top left side of this page.