Skip to content

Recurrence ​

Recurrence Rules ​

OpenTask uses RFC 5545 RRULE strings (the iCalendar recurrence standard) to define repeating schedules.

Examples ​

PatternRRULE
Every dayFREQ=DAILY
Every weekdayFREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR
Every MondayFREQ=WEEKLY;BYDAY=MO
Every month on the 1stFREQ=MONTHLY;BYMONTHDAY=1
Every 2 weeksFREQ=WEEKLY;INTERVAL=2

Completion Behavior ​

Recurring tasks advance in place rather than being archived:

  1. You complete a daily 9 AM task
  2. The task stays active with done = 0
  3. The target (due_at) advances to the next scheduled occurrence (tomorrow at 9 AM)
  4. The completion is logged for history and stats

This means your recurring tasks always stay in your active list. You never need to recreate them.

A missed occurrence stays over target ​

A recurring task carries debt. If its target passes, it's over target from then until you complete it — through midnight and into the following days. It doesn't quietly reset when the next day starts.

When you complete it, the task moves to the next scheduled occurrence after the completion. For example, a task that repeats on Mondays and Thursdays, due Monday and completed on Tuesday, next comes due on Thursday. The schedule is kept, and the missed Monday isn't repeated.

A recurring task with no target is evaluated from its schedule instead.

Occurrence and target ​

A recurring task keeps its scheduled occurrence (occurrence_at) apart from its target (target_at). They start out the same. Snoozing or moving the task (including Today on an Upcoming row) changes only the target; the occurrence stays where the schedule put it. Completing or skipping advances from the occurrence and sets both to the next one. So a weekly Sunday task moved to Saturday and done on Saturday comes back the following Sunday, not the day after. The task editor shows a moved target with its occurrence underneath ("Occurrence Sun, Oct 18, 12:00 PM · target moved").

Deadlines on recurring tasks ​

A recurring task can have a deadline too. When you complete or skip an occurrence, the deadline moves with it: it stays the same number of days after the new occurrence, at the same local time of day, even across a daylight-saving change. It's measured from the scheduled occurrence, so snoozing an occurrence never shifts it. Like any deadline, it caps a snooze while it's still ahead. Recurring tasks never get an automatic target from their deadline (the occurrence is their target), and they never appear in the horizon task segments: the schedule already brings them round, with heads-ups in Upcoming.

In the task editor, a recurring task's time is labelled as its target ("Target Sundays at 12:00 PM"), and its deadline line says it repeats ("Sun Oct 18, 11:00 PM · moves with each week"). To give a weekly task a late-morning target and a deadline before bed that night, set the rule's time to late morning, then tap Deadline: the picker opens on the occurrence's day and time, so you only change the time. Recurring tasks have no Horizon row in the editor, since they never enter a task segment. Tap the recurrence line to open the recurrence editor.

Reminders roll forward

Reminders work differently. A recurring reminder has no debt: a missed one isn't shown again until its next occurrence, and it's never counted as over target.

Recurrence mode ​

The recurrence_mode field controls where the next occurrence is counted from:

ModeNext occurrenceExample
from_due (default)The next scheduled occurrence on the calendar"Every Monday at 9 AM" stays on Mondays no matter when you finish
from_completionThe interval counted from when you actually completed it, at the task's usual time of day"Every 3 months" filter change, counted from the last time it was done

Skipping an Occurrence ​

POST /api/tasks/{id}/skip-occurrence clears an item without recording a completion — for when you've decided not to do this occurrence, rather than snoozing it or marking it done.

  • Recurring task: advances to the next occurrence, the same way completing does, but doesn't count as a completion. skip_count increments.
  • One-off task: archived without being marked done.

It's refused for reminders (a missed reminder rolls forward on its own), trashed tasks, and one-off tasks that are already done. A skip is undoable and sends a task.skipped webhook, not task.completed.

bash
curl -X POST -H "Authorization: Bearer $TOKEN" \
  https://tasks.example.com/api/tasks/42/skip-occurrence

Skipping is currently available through the API only.

Changing the Schedule ​

Updating a task's rrule re-derives its schedule. Sending a date in the same request sets when the new schedule starts:

bash
curl -X PATCH -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"rrule": "FREQ=WEEKLY;BYDAY=MO", "due_at": "2026-03-16T14:00:00Z"}' \
  https://tasks.example.com/api/tasks/42

PATCH { rrule, due_at } keeps the date you send and uses it to set the task's time of day. A schedule change isn't a snooze: it sets the occurrence to what the new rule schedules and clears original_due_at. See Snooze tracking.

Timezone Handling ​

Recurring tasks preserve their intended local time across DST (Daylight Saving Time) transitions. A task due at 9 AM stays at 9 AM local time when clocks change.

Snooze Interaction ​

Snoozing a recurring task only moves this occurrence's target — the recurrence rule and the scheduled occurrence stay as they were. On completion, the task advances to the first scheduled occurrence after both its scheduled occurrence and the completion time.

A daily 9 AM task snoozed to noon and completed is next due at 9 AM tomorrow. But a snooze that goes past the next scheduled occurrence skips that occurrence (completing it then advances past the completion, with no catch-up); the app warns before a single-task snooze does this. See Snooze & Time.