Reviewed the plan against the code it describes. Two design holes and five errors. Instance identity was the real one. The plan deleted the materialised instances table without saying what replaces the instance row id, which TasksRepositoryImpl.updateTask passes to updateInstance and which ListsScreen keys a lazy list by. Two occurrences of one series can appear in the same list, so taskId alone is not unique and a hash of (taskId, start) can collide - as a Compose key that is a visible bug. Task.id is dropped for occurrenceStart, updateInstance takes (taskId, occurrenceStart, form), and External mode maps back to a real instance row with one query. This is the single seam change, and the plan's "TasksDataSource unchanged" claim was wrong. Local lists had no account name. TaskList.accountName is non-null, ListsViewModel groups by it and ListsScreen renders it as a section header, so a null account_id must still report "Local". The unique index was wrong: overrides share their master's UID, so unique (list_id, uid) would reject the rows the recurrence design depends on. It needs recurrence_id in the key. Phase 0 broke background reminders. It dropped our authority from ProviderChangeReceiver's manifest filter while the provider was still the store, and renamed StorageMode.LOCAL to OWN four phases before OWN meant Room. Both moved to phase 5. Parity against the provider was overclaimed: the provider materialises one occurrence, so multi-occurrence expansion has nothing to compare against and is tested against RFC 5545 directly. The phases sum to 6.5-7 weeks, not the 6-6.5 stated, and the difference from STORAGE-DECISION.md's 4.5-6 is now explained rather than left as a contradiction. Gaps closed: WAL vs Auto Backup (checkpoint on ON_STOP, sidecars in the backup rules, tested in phase 6), cascade rules for master_id and parent_id, Instant type converters, a rollback path that re-runs the import from tasks.db.imported, the release note for dropping the authority and its permissions, and ICalendarWriter.uidFor's synthesis branch becoming External-only. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Agendula
A modern Material 3 Expressive task app for Android.
Keeps your tasks on your device, or on top of a tasks provider you already use.
Open standards, no account required.
Agendula is the task-list sibling to Calendula.
Where Calendula is a pure front-end over Android's CalendarContract, Agendula
speaks the dmfs TaskContract — the same shape DAVx5 (and SmoothSync,
DecSync, …) syncs your CalDAV VTODO tasks into.
The name rhymes with its sibling on purpose: Agendula is agenda — Latin for
“things to be done” — given Calendula's -ula ending. Calendula keeps your days;
Agendula keeps your to-dos. (A Calendula flower head is botanically a cluster of
many small florets — so the two apps are florets of one bloom.)
Where your tasks live — your choice
| Where | Sync | Needs | |
|---|---|---|---|
| On your device (default) | Agendula's own task store, bundled in the app | none yet — sync of our own is planned | nothing. No account, no permissions, no other app |
| In a provider you already use | OpenTasks or tasks.org | whatever syncs it for you — DAVx5 and friends | that app installed, and its read/write permission |
Agendula carries its own copy of the Apache-2.0 dmfs task provider, under its own name — so it coexists with OpenTasks rather than replacing it, and installing one never breaks the other. It is a fork of a proven schema, not a database written from scratch, which is why every CalDAV engine already understands it.
Your tasks are exportable as standard iCalendar .ics files at any time, because
data you can't take with you isn't really yours.
Status: backend complete, UI catching up. Storage, provider, reads and writes, smart-list filtering, a self-scheduled reminder engine, and export are built and unit-tested. The Material 3 Expressive screens are being built on top, one at a time — the storage-mode picker and export screen are not there yet. See
docs/ROADMAP.mdfor status,docs/ARCHITECTURE.mdfor how it's built, anddocs/STORAGE-AND-SYNC.mdfor why storage works the way it does.
Sync sources (by design)
In provider mode Agendula works with anything that writes to that provider — DAVx5 (CalDAV), SmoothSync, CalDAV-Sync, DecSync CC, or any Android sync adapter — because it builds on the provider, not on any one sync app. Google Tasks / Microsoft To Do are out of scope by design (proprietary; they would mean owning a sync stack). Open standards — CalDAV / iCalendar / DecSync — are the lane.
Translations
Agendula ships in English so far, and would like not to. Translations are managed on a self-hosted Weblate, and partial ones are fine — an untranslated string simply falls back to English.
No coding needed: register on the Weblate server, pick (or request) a language, and translate the strings in your browser. You can also reach this link in the app from the top of Settings → App language.
License
MIT — see LICENSE.