Go API

Use go-eventkit for programmatic access to macOS Reminders — the same library that powers rem and cal.

Overview

For programmatic Go access to macOS Reminders, use go-eventkit directly — the same library that powers rem and cal.

go get github.com/BRO3886/go-eventkit

Quick example

package main

import (
    "fmt"
    "time"

    "github.com/BRO3886/go-eventkit/reminders"
)

func main() {
    client, err := reminders.New()
    if err != nil {
        panic(err)
    }

    // Create a reminder
    due := time.Now().Add(24 * time.Hour)
    r, err := client.CreateReminder(reminders.CreateReminderInput{
        Title:    "Deploy to production",
        ListName: "Work",
        DueDate:  &due,
        Priority: reminders.PriorityHigh,
    })
    if err != nil {
        panic(err)
    }
    fmt.Println("Created:", r.ID)

    // List incomplete reminders
    items, err := client.Reminders(
        reminders.WithList("Work"),
        reminders.WithCompleted(false),
    )
    if err != nil {
        panic(err)
    }
    for _, item := range items {
        fmt.Printf("%s  %s  (due: %v)\n", item.ID[:8], item.Title, item.DueDate)
    }

    // Mark as done
    client.CompleteReminder(r.ID)
}

Client

All operations start with creating a client:

client, err := reminders.New()
if err != nil {
    log.Fatal(err)
}

New() requests TCC (Transparency, Consent, and Control) access to Reminders. Returns an error if access is denied or the platform is unsupported.

Creating reminders

due := time.Now().Add(48 * time.Hour)
r, err := client.CreateReminder(reminders.CreateReminderInput{
    Title:    "Buy groceries",
    ListName: "Personal",          // optional, uses default list
    DueDate:  &due,
    Priority: reminders.PriorityMedium,
    Notes:    "Milk, eggs, bread",
    URL:      "https://example.com",
})

All fields except Title are optional.

Priority values

ConstantValueMeaning
reminders.PriorityNone0No priority
reminders.PriorityHigh1High priority (1-4)
reminders.PriorityMedium5Medium priority
reminders.PriorityLow9Low priority (6-9)

Reading reminders

Get a single reminder

r, err := client.Reminder("6ECEA745")  // full ID, UUID, or prefix

Supports full IDs, UUIDs, and prefix matching (case-insensitive).

List with filters

items, err := client.Reminders(
    reminders.WithList("Work"),
    reminders.WithCompleted(false),
    reminders.WithDueBefore(deadline),
    reminders.WithSearch("deploy"),
)

All filter options are optional. Call with no options to get all reminders.

OptionDescription
WithList(name)Filter by list name
WithListID(id)Filter by list ID
WithCompleted(bool)Filter by completion status
WithDueBefore(time)Due before date
WithDueAfter(time)Due after date
WithSearch(query)Full-text search

Updating reminders

newTitle := "Updated title"
newPriority := reminders.PriorityMedium
r, err := client.UpdateReminder(id, reminders.UpdateReminderInput{
    Title:    &newTitle,       // nil = don't change
    Priority: &newPriority,   // nil = don't change
    ClearDueDate: true,       // explicitly clear due date
})

Only non-nil pointer fields are modified.

Status operations

r, err := client.CompleteReminder(id)
r, err := client.UncompleteReminder(id)
err := client.DeleteReminder(id)

List management

// Get all lists
lists, err := client.Lists()
for _, l := range lists {
    fmt.Printf("%s (%d reminders, source: %s)\n", l.Title, l.Count, l.Source)
}

// Create a list
list, err := client.CreateList(reminders.CreateListInput{
    Title:  "Shopping",
    Source: "iCloud",    // required — use Lists() to discover sources
    Color:  "#FF6961",   // optional
})

// Rename a list
newTitle := "Groceries"
list, err = client.UpdateList(list.ID, reminders.UpdateListInput{
    Title: &newTitle,
})

// Delete a list
err = client.DeleteList(list.ID)

Immutable system lists (e.g., Siri suggestions) return reminders.ErrImmutable on update/delete.

Reminder model

The Reminder struct returned by read operations:

type Reminder struct {
    ID             string
    Title          string
    Notes          string
    List           string      // list display name
    ListID         string
    DueDate        *time.Time
    RemindMeDate   *time.Time
    CompletionDate *time.Time
    CreatedAt      *time.Time
    ModifiedAt     *time.Time
    Priority       Priority
    Completed      bool
    Flagged        bool        // always false (EventKit limitation)
    URL            string      // native URL field
    Recurring      bool
    HasAlarms      bool
}

Error handling

All methods return standard Go errors. Use errors.Is for sentinel errors:

if errors.Is(err, reminders.ErrAccessDenied) {
    // macOS TCC hasn't granted Reminders access
}
if errors.Is(err, reminders.ErrNotFound) {
    // reminder ID doesn't match any reminder
}
if errors.Is(err, reminders.ErrUnsupported) {
    // running on non-macOS
}
if errors.Is(err, reminders.ErrImmutable) {
    // list is immutable (system list)
}

Learn more

See the go-eventkit README for the full API reference, including calendar/events support.