reminderrelay

module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 18, 2026 License: MIT

README

ReminderRelay

Bidirectional sync daemon that keeps Apple Reminders and Home Assistant todo lists in sync — automatically, in the background, on macOS.

Apple Reminders  ←──────────────────→  Home Assistant
   (EventKit)          ReminderRelay      (REST + WebSocket)

Features

  • Bidirectional sync — changes made in either app appear in the other within seconds.
  • Last-write-wins conflict resolution — the side that changed most recently wins; no silent data loss.
  • Real-time HA updates — WebSocket subscription for instant propagation from HA → Reminders.
  • Polling for Reminders changes — configurable 10 s – 5 m interval (default 30 s).
  • Priority mapping — Apple Reminders priorities are encoded as [High], [Medium], [Low] prefixes in HA descriptions.
  • First-run bootstrap — interactive wizard that matches existing items between both sides by title and prompts before writing anything.
  • Persistent state database — SQLite tracks sync metadata so resuming after a restart is safe.

Prerequisites

Requirement Version
macOS 13 Ventura or later
Apple ID / iCloud Signed in with Reminders enabled
Home Assistant ≥ 2023.11 (Todo integration required)
HA long-lived access token Profile → Security → Long-Lived Access Tokens

Quick Start

1. Install devbox (once)
curl -fsSL https://get.jetify.com/devbox | bash
2. Clone and enter the dev shell
git clone https://github.com/njoerd114/reminderrelay.git
cd reminderrelay
devbox shell
3. Create your config
mkdir -p ~/.config/reminderrelay
cp config.example.yaml ~/.config/reminderrelay/config.yaml
$EDITOR ~/.config/reminderrelay/config.yaml

Key fields:

ha_url: "http://homeassistant.local:8123"
ha_token: "your-long-lived-access-token-here"
poll_interval: 30s
list_mappings:
  "Shopping": "todo.shopping"
  "Work":     "todo.work_tasks"
4. Test connectivity (dry run)
just sync-once

This does one full sync cycle and exits.
On first run you will be prompted to review and confirm bootstrap matches — nothing is written until you type y.

5. Install as a background daemon
just install

That's it. ReminderRelay is now running and will restart automatically when you log in.

Configuration Reference

Key Type Default Description
ha_url string Home Assistant base URL (http://… or https://…)
ha_token string Long-lived access token
poll_interval duration 30s How often Reminders are polled (10 s – 5 m)
list_mappings map "Reminders list name": "todo.entity_id"

Discovering Your HA Entity IDs

  1. Open Home Assistant → Settings → Devices & services → Entities.
  2. Filter by domain todo.
  3. Copy the entity IDs (e.g. todo.shopping) into list_mappings.

Or run:

just sync-once -- --verbose 2>&1 | grep "entity"

Priority Encoding

Apple Reminders supports four priority levels.
Home Assistant todo has no native priority field, so ReminderRelay encodes priority as a prefix in the task description:

Reminders priority Description prefix
High [High]
Medium [Medium]
Low [Low]
None (no prefix)

Justfile Recipes

just build        # compile binary
just test         # run all tests
just lint         # run golangci-lint
just run          # run daemon in foreground (Ctrl-C to stop)
just sync-once    # run one sync cycle and exit
just install      # build + install + load launchd agent
just uninstall    # unload + remove binary and plist

Logs

Location Contents
~/Library/Logs/reminderrelay/output.log Info and debug output
~/Library/Logs/reminderrelay/errors.log Errors and warnings

Tail logs live:

tail -f ~/Library/Logs/reminderrelay/errors.log

Uninstall

just uninstall                             # remove daemon + binary
bash deployment/uninstall.sh --purge       # also remove config + DB + logs

Troubleshooting

Reminders access denied (TCC)

macOS requires explicit permission for apps to access Reminders.
On first run a system dialog appears — click OK.
If you previously denied access:

  1. Open System Settings → Privacy & Security → Reminders.
  2. Enable access for Terminal (or your shell app).
HA connection refused
  • Confirm ha_url is reachable: curl -s <ha_url>/api/ -H "Authorization: Bearer <token>"
  • Ensure the token has not expired or been revoked.
Items duplicated after restart

This usually means the state database was deleted while items still existed in both systems. Remove the DB and re-run the bootstrap:

rm ~/.local/share/reminderrelay/state.db
just sync-once
Sync is slow

Decrease poll_interval (minimum 10s). Real-time HA → Reminders flow is already push-based via WebSocket; the interval only affects Reminders → HA propagation.

Architecture

cmd/reminderrelay/        Entry point, signal handling, wiring
internal/config/          YAML config loader + validation
internal/state/           SQLite repository (WAL mode)
internal/model/           Shared Item type, priority encoding, content hash
internal/reminders/       Apple Reminders adapter (EventKit via cgo)
internal/homeassistant/   HA REST + WebSocket adapter, retry logic
internal/sync/            Reconciler, bootstrap wizard, daemon engine
deployment/               launchd plist, install/uninstall scripts

License

MIT — see LICENSE.

Directories

Path Synopsis
cmd
reminderrelay command
ReminderRelay is a macOS daemon that syncs Apple Reminders ↔ Home Assistant todo lists bidirectionally using last-write-wins conflict resolution.
ReminderRelay is a macOS daemon that syncs Apple Reminders ↔ Home Assistant todo lists bidirectionally using last-write-wins conflict resolution.
internal
config
Package config loads and validates the ReminderRelay YAML configuration.
Package config loads and validates the ReminderRelay YAML configuration.
homeassistant
Package homeassistant wraps the go-ha-client REST and WebSocket APIs for todo-list operations.
Package homeassistant wraps the go-ha-client REST and WebSocket APIs for todo-list operations.
model
Package model defines shared types used across the sync engine and adapters.
Package model defines shared types used across the sync engine and adapters.
reminders
Package reminders wraps the go-eventkit reminders library and converts between native EventKit types and the shared model.Item representation.
Package reminders wraps the go-eventkit reminders library and converts between native EventKit types and the shared model.Item representation.
state
Package state manages the SQLite database that tracks sync metadata between Apple Reminders and Home Assistant todo lists.
Package state manages the SQLite database that tracks sync metadata between Apple Reminders and Home Assistant todo lists.
sync
Package sync implements the bidirectional reconciliation engine for ReminderRelay.
Package sync implements the bidirectional reconciliation engine for ReminderRelay.
telemetry
Package telemetry initialises optional OpenTelemetry trace, metric, and log providers backed by an OTLP gRPC collector.
Package telemetry initialises optional OpenTelemetry trace, metric, and log providers backed by an OTLP gRPC collector.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL