Repeating Tasks

Omni Automation in OmniFocus provides the ability to set the repetition rules for a task. The repetitionRule property of the Task class is used to access and set any repeating parameters.

The Task.RepetitionRule Class

A Task.RepetitionRule describes a pattern of dates using a ICS formatted recurrence string (iCalendar.org) and a Task.RepetitionMethod to describe how those dates are applied to a Task.

The properties of the Task.RepetitionRule class:

The instance functions of the Task.RepetitionRule class:

Date/Time of the Next Task Repetition


var task = document.windows[0].selection.tasks[0] if(task && task.repetitionRule){ console.log(task.name, task.repetitionRule.firstDateAfterDate(new Date())) }

The Task.RepetitionMethod Class

Task.RepetitionRule Constructor

Task.RepetitionRule Constructor


new Task.RepetitionRule( ruleString: String or null, method: Task.RepetitionMethod or null, scheduleType: Task.RepetitionScheduleType or null, anchorDateKey: Task.AnchorDateKey or null, catchUpAutomatically: Boolean or null )

Returns a new Task.RepetitionRule with the specified ICS rule string and scheduling information. If the rule string is not valid, an error will be thrown. The system defaults will be used for ruleString, scheduleType, anchorDateKey, and catchUpAutomatically if not provided.

IMPORTANT: The method parameter is deprecated, but remains for backwards compatibility with existing scripts and scheduleType should be used instead. If deprecated method is provided along with updated scheduleType and anchorDateKey, an error will be thrown.

Properties of Task.RepetitionScheduleType Class

Schedule Type


var scheduleType = Task.RepetitionScheduleType.Regularly

Properties of Task.AnchorDateKey Class

Anchor Date Key


var anchorDateKey = Task.AnchorDateKey.DueDate

Create Repeating Task

Creating a new repeating task:

omnifocus://localhost/omnijs-run?script=try%7Bvar%20task%20%3D%20new%20Task%28%22My%20Weekly%20Task%22%29%0Avar%20ruleString%20%3D%20%22FREQ%3DWEEKLY%22%0Atask%2ErepetitionRule%20%3D%20new%20Task%2ERepetitionRule%28ruleString%2C%20Task%2ERepetitionMethod%2EDueDate%29%0Avar%20taskID%20%3D%20task%2Eid%2EprimaryKey%0AURL%2EfromString%28%22omnifocus%3A%2F%2F%2Ftask%2F%22%20%2B%20taskID%29%2Eopen%28%29%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
New Repeating Task
 

task = new Task("My Weekly Task") ruleString = "FREQ=WEEKLY" repetitionMethod = Task.RepetitionMethod.DueDate task.repetitionRule = new Task.RepetitionRule(ruleString, repetitionMethod) task.url.open()

Using OmniFocus v4.7+ parameters. NOTE: The method parameter is included with a value of null

omnifocus://localhost/omnijs-run?script=task%20%3D%20new%20Task%28%22My%20Weekly%20Task%22%29%0Dtask%2ErepetitionRule%20%3D%20new%20Task%2ERepetitionRule%28%0D%09%22FREQ%3DWEEKLY%22%2C%0D%09null%2C%0D%09Task%2ERepetitionScheduleType%2ERegularly%2C%0D%09Task%2EAnchorDateKey%2EDueDate%2C%0D%09true%0D%29%0Dtask%2Eurl%2Eopen%28%29
New Repeating Task (v4.7+)
 

task = new Task("My Weekly Task") task.repetitionRule = new Task.RepetitionRule( "FREQ=WEEKLY", null, Task.RepetitionScheduleType.Regularly, Task.AnchorDateKey.DueDate, true ) task.url.open()

And to disable repetition, set the property value to null:

Stop Repetition


var task = taskNamed("My Weekly Task") task.repetitionRule = null

The Rule Info Plug-In

Aside from using the free RRULE Tool at iCalendar.org, perhaps the simplest way to derive an ICS rule string is to set up an example repeating task in OmniFocus using the standard application interface, and then use Omni Automation to retrieve the corresponding ISC rule string from the selected task. You can then use the extracted ICS rule string in your scripts to define the specified repetition parameters.

The plug-in provided below will both display the ICS string and log it to the console for you.

rule-info-sheet
Rule Info for Selected Task
  

/*{ "type": "action", "targets": ["omnifocus"], "author": "Otto Automator", "identifier": "com.omni-automation.of.task-rule-info", "version": "1.1", "description": "This action will display an alert showing the ICS rule string and repetition method of the selected task or project.", "label": "Rule Info for Selected Item", "shortLabel": "Rule Info", "paletteLabel": "Rule Info", "image": "info.square.fill" }*/ (() => { const action = new PlugIn.Action(async function(selection, sender){ if (selection.projects.length === 1){ var item = selection.projects[0] var alertTitle = "Project: " + item.name } else { var item = selection.tasks[0] var alertTitle = "Task: " + item.name } rule = item.repetitionRule ruleString = item.repetitionRule.ruleString repetitionMethod = item.repetitionRule.method msg = "" var methodName switch(repetitionMethod) { case Task.RepetitionMethod.DueDate: methodName = "Due Date" break; case Task.RepetitionMethod.Fixed: methodName = "Fixed" break; case Task.RepetitionMethod.DeferUntilDate: methodName = "Defer Until Date" break; default: methodName = "None" } msg = "ICS Rule String: " + ruleString + "\n" + "Repetition Method: " + methodName console.log(msg) new Alert(alertTitle, msg).show() }); action.validate = function(selection, sender){ return ( selection.projects.length === 1 && selection.projects[0].repetitionRule != null || selection.tasks.length === 1 && selection.tasks[0].repetitionRule != null ) }; return action; })();
rule-info-in-console

Repeating Project with Sequential Tasks

This example demonstrates repetition through the tasks required to create and present a kindergarten class every week. Each task has a morning notification and evening due date. Once the project’s sequential tasks are completed, the project is marked completed and a new blank project is generated as its replacement.

formatter = Formatter.Date.withStyle(Formatter.Date.Style.Short) folder = folderNamed("Personal") || new Folder("Personal") projectName = "Kinder Class" project = folder.projectNamed(projectName) if(project){deleteObject(project)} project = Object.assign( new Project(projectName, folder), { sequential : true, note : "My weekly kindergarten class" } ) tag = flattenedTags.byName("Instruction") || new Tag("Instruction") project.addTag(tag) ruleString = "FREQ=WEEKLY" repetitionMethod = Task.RepetitionMethod.DueDate project.repetitionRule = new Task.RepetitionRule(ruleString, repetitionMethod) project.completedByChildren = true task = Object.assign( new Task("(Wed) Select Topic for Kinder Class", project), { note : "Determine a topic for this week’s class", dueDate: formatter.dateFromString('wednesday @ 7:00PM') } ) dateObj = formatter.dateFromString('wednesday @ 9:00AM') task.addNotification(dateObj) task.clearTags() task = Object.assign( new Task("(Thu) Create Materials for Kinder Class", project), { note : "Create materials for this week’s class", dueDate: formatter.dateFromString('thursday @ 7:00PM') } ) dateObj = formatter.dateFromString('thursday @ 9:00AM') task.addNotification(dateObj) task.clearTags() task = Object.assign( new Task("(Sat) Kinder Class Rehearsal", project), { note : "Rehearse Kinder Class presentation", dueDate: formatter.dateFromString('saturday @ 7:00PM') } ) dateObj = formatter.dateFromString('saturday @ 9:00AM') task.addNotification(dateObj) task.clearTags() task = Object.assign( new Task("(Sun) Kinder Class", project), { note : "Kinder Class", dueDate : formatter.dateFromString('sunday @ 11:30AM') } ) task.addNotification(-3600) dateObj = formatter.dateFromString('sunday @ 9:00AM') task.addNotification(dateObj) task.clearTags()
omnifocus://localhost/omnijs-run?script=formatter%20%3D%20Formatter%2EDate%2EwithStyle%28Formatter%2EDate%2EStyle%2EShort%29%0A%0Afolder%20%3D%20folderNamed%28%22Personal%22%29%20%7C%7C%20new%20Folder%28%22Personal%22%29%0A%0AprojectName%20%3D%20%22Kinder%20Class%22%0Aproject%20%3D%20folder%2EprojectNamed%28projectName%29%0Aif%28project%29%7BdeleteObject%28project%29%7D%0Aproject%20%3D%20Object%2Eassign%28%0A%09new%20Project%28projectName%2C%20folder%29%2C%0A%09%7B%0A%09%09sequential%20%3A%20true%2C%0A%09%09note%20%3A%20%22My%20weekly%20kindergarten%20class%22%0A%09%7D%0A%29%0Atag%20%3D%20flattenedTags%2EbyName%28%22Instruction%22%29%20%7C%7C%20new%20Tag%28%22Instruction%22%29%0Aproject%2EaddTag%28tag%29%0AruleString%20%3D%20%22FREQ%3DWEEKLY%22%0ArepetitionMethod%20%3D%20Task%2ERepetitionMethod%2EDueDate%0Aproject%2ErepetitionRule%20%3D%20new%20Task%2ERepetitionRule%28ruleString%2C%20repetitionMethod%29%0Aproject%2EcompletedByChildren%20%3D%20true%0A%0Atask%20%3D%20Object%2Eassign%28%0A%09new%20Task%28%22%28Wed%29%20Select%20Topic%20for%20Kinder%20Class%22%2C%20project%29%2C%0A%09%7B%0A%09%09note%20%3A%20%22Determine%20a%20topic%20for%20this%20week%E2%80%99s%20class%22%2C%0A%09%09dueDate%3A%20formatter%2EdateFromString%28%27wednesday%20%40%207%3A00PM%27%29%0A%09%7D%0A%29%0AdateObj%20%3D%20formatter%2EdateFromString%28%27wednesday%20%40%209%3A00AM%27%29%0Atask%2EaddNotification%28dateObj%29%0Atask%2EclearTags%28%29%0A%0Atask%20%3D%20Object%2Eassign%28%0A%09new%20Task%28%22%28Thu%29%20Create%20Materials%20for%20Kinder%20Class%22%2C%20project%29%2C%0A%09%7B%0A%09%09note%20%3A%20%22Create%20materials%20for%20this%20week%E2%80%99s%20class%22%2C%0A%09%09dueDate%3A%20formatter%2EdateFromString%28%27thursday%20%40%207%3A00PM%27%29%0A%09%7D%0A%29%0AdateObj%20%3D%20formatter%2EdateFromString%28%27thursday%20%40%209%3A00AM%27%29%0Atask%2EaddNotification%28dateObj%29%0Atask%2EclearTags%28%29%0A%0Atask%20%3D%20Object%2Eassign%28%0A%09new%20Task%28%22%28Sat%29%20Kinder%20Class%20Rehearsal%22%2C%20project%29%2C%0A%09%7B%0A%09%09note%20%3A%20%22Rehearse%20Kinder%20Class%20presentation%22%2C%0A%09%09dueDate%3A%20formatter%2EdateFromString%28%27saturday%20%40%207%3A00PM%27%29%0A%09%7D%0A%29%0AdateObj%20%3D%20formatter%2EdateFromString%28%27saturday%20%40%209%3A00AM%27%29%0Atask%2EaddNotification%28dateObj%29%0Atask%2EclearTags%28%29%0A%0Atask%20%3D%20Object%2Eassign%28%0A%09new%20Task%28%22%28Sun%29%20Kinder%20Class%22%2C%20project%29%2C%0A%09%7B%0A%09%09note%20%3A%20%22Kinder%20Class%22%2C%0A%09%09dueDate%20%3A%20formatter%2EdateFromString%28%27sunday%20%40%2011%3A30AM%27%29%0A%09%7D%0A%29%0Atask%2EaddNotification%28%2D3600%29%0AdateObj%20%3D%20formatter%2EdateFromString%28%27sunday%20%40%209%3A00AM%27%29%0Atask%2EaddNotification%28dateObj%29%0Atask%2EclearTags%28%29
Kinder Class
 

formatter = Formatter.Date.withStyle(Formatter.Date.Style.Short) folder = folderNamed("Personal") || new Folder("Personal") projectName = "Kinder Class" project = folder.projectNamed(projectName) if(project){deleteObject(project)} project = Object.assign( new Project(projectName, folder), { sequential : true, note : "My weekly kindergarten class" } ) tag = flattenedTags.byName("Instruction") || new Tag("Instruction") project.addTag(tag) ruleString = "FREQ=WEEKLY" repetitionMethod = Task.RepetitionMethod.DueDate project.repetitionRule = new Task.RepetitionRule(ruleString, repetitionMethod) project.completedByChildren = true task = Object.assign( new Task("(Wed) Select Topic for Kinder Class", project), { note : "Determine a topic for this week’s class", dueDate: formatter.dateFromString('wednesday @ 7:00PM') } ) dateObj = formatter.dateFromString('wednesday @ 9:00AM') task.addNotification(dateObj) task.clearTags() task = Object.assign( new Task("(Thu) Create Materials for Kinder Class", project), { note : "Create materials for this week’s class", dueDate: formatter.dateFromString('thursday @ 7:00PM') } ) dateObj = formatter.dateFromString('thursday @ 9:00AM') task.addNotification(dateObj) task.clearTags() task = Object.assign( new Task("(Sat) Kinder Class Rehearsal", project), { note : "Rehearse Kinder Class presentation", dueDate: formatter.dateFromString('saturday @ 7:00PM') } ) dateObj = formatter.dateFromString('saturday @ 9:00AM') task.addNotification(dateObj) task.clearTags() task = Object.assign( new Task("(Sun) Kinder Class", project), { note : "Kinder Class", dueDate : formatter.dateFromString('sunday @ 11:30AM') } ) task.addNotification(-3600) dateObj = formatter.dateFromString('sunday @ 9:00AM') task.addNotification(dateObj) task.clearTags()
Repeating project with sequential tasks