Fabian Schober63 downloadsTwo-way sync of TaskNotes tasks with a CalDAV task list (VTODO). Requires TaskNotes.
Keep your TaskNotes tasks in sync with CalDAV task lists — Nextcloud Tasks, Apple Reminders, Radicale, Baikal, anything that stores VTODOs. Create a task in Obsidian and it shows up on your phone a couple of seconds later. Tick it off on the phone and the note updates on the next sync. Tags and projects decide which list a task lands in: #work to your Work list, everything in your House project to Home, everything else to a default list.
This is a companion plugin: it does nothing on its own and needs TaskNotes installed and enabled. Your tasks stay ordinary Markdown notes; the plugin only adds a few caldav_* keys to their frontmatter.
The sync started life as a pull request to TaskNotes itself (#2280). TaskNotes has since grown an official runtime API for companion plugins, so the same mechanism now lives here and talks to TaskNotes only through that API. It works with stock TaskNotes and doesn't have to wait on a merge.
The plugin is not in the community plugin directory (yet). Two ways to install it:
schobernoise/tasknotes-caldav in BRAT.main.js, manifest.json and styles.css from the latest release into <vault>/.obsidian/plugins/tasknotes-caldav/, then enable TaskNotes CalDAV under Settings → Community plugins.https://cloud.example.com/remote.php/davhttps://caldav.icloud.com with an app-specific passwordhttps:// (plain http:// is allowed for localhost).Two commands are available from the command palette: Sync tasks with CalDAV now and Unlink all tasks from CalDAV.
| TaskNotes | CalDAV (VTODO) |
|---|---|
| Title | SUMMARY |
| Due / scheduled date | DUE / DTSTART |
| Status | STATUS |
| Priority | PRIORITY |
| Completed date | COMPLETED |
| Tags | CATEGORIES |
| Recurrence | RRULE |
| Projects (parent tasks) | RELATED-TO;RELTYPE=PARENT |
| Blocked by | RELATED-TO with the dependency type (RFC 9253) |
| Reminders | VALARM |
The note body is not synced. Anything the plugin doesn't model — a description written on the phone, attachments, custom X- properties — is left exactly as it was on the server.
Statuses. TaskNotes lets you define your own, CalDAV has a fixed set. A status marked completed becomes COMPLETED, one marked skipped becomes CANCELLED, everything else NEEDS-ACTION. Coming back, NEEDS-ACTION maps to your first open status by order.
Priorities. CalDAV has 1–9 plus 0 for not set, and task apps show them in three bands: 1–4 high, 5 medium, 6–9 low. By default your lowest-weight priority is sent as 9, the next as 5, and the rest are shared across 1–4, highest weight first; a priority with weight 0 is not set. With TaskNotes' own low/normal/high that is 9/5/1, what Apple Reminders uses. Under Priorities in the settings you can pick the number for each one. A number coming back that matches none of yours goes to the nearest priority in the same band, so a medium set on the phone never turns into a high one. Clearing the priority on the phone sets the note to your weight-0 priority.
The task tag. TaskNotes recognises task notes by a tag (#task by default). Every synced task would carry it, so it's left off the server unless you turn on Sync the task tag. Your notes always keep it, even when a phone app edits or drops a task's categories.
Subtasks. A subtask is a task whose Projects field links to another task, and it arrives on the server as a real subtask. A link is only sent once both tasks exist on the server; projects that are plain notes rather than tasks are left out.
An account is one server login; it can sync any number of its lists. Each list gets tags, projects, or both, and the rows are tried top to bottom:
work also matches work/client) or whose projects it belongs to, otherwise to the Everything else list, otherwise nowhere.#work and it is deleted from Home and created in Work, with the same UID and anything a phone app added (a description, say) carried over. A task stays put as long as it still has one of its list's tags, so a Work task that also gets #home stays in Work. Losing its list's tag sends it to Everything else; with nowhere to go, it stays where it is.#work and gains #home. It is not mistaken for a deletion. Project lists work the same way: moved out, the task loses its link to that list's project; moved in, it gets a link to the list's first project, unless it already belongs to one of them. Links to other projects stay.work, so it's hidden like the task tag, and a phone app editing categories can't remove it from the note.caldav_* keys are removed from the note. Nothing else in the note changes. The server copy has to go, because a copy nothing links to would come back as a new note on the next poll.Upgrading from 0.4: Only tasks in folder becomes a one-entry folder list, and lists route by no project until you add one. If the default priority numbers changed for you, the first sync after the upgrade sends every affected task once more with its new number. Nothing in your notes changes.
Upgrading from 0.3: an account's list becomes its only list. An include tag filter becomes that list's tags; otherwise the list takes Everything else, and an exclude filter becomes Never sync. Nothing in your notes changes.
caldav_* keys and deletes nothing on either side. The link is also what stops a task being uploaded twice, so syncing the same list again afterwards gives you a second copy of every task.:, are dropped from titles pulled in from the server. The server keeps its version; the plugin doesn't push the shortened title back.IN-PROCESS status from the server can't be told apart from "not started" unless your statuses make it obvious. The plugin picks your second open status.Your password lives in Obsidian's secret storage and is never written to data.json. Task UIDs are random, so vault paths are never visible to anyone else who can see the list. The plugin talks to the servers you configure and nothing else.
npm install
npm run dev # esbuild watch, writes main.js
npm run build # typecheck + production bundle
npm test # unit tests for the pure CalDAV modules (Jest, jsdom)
src/main.ts lifecycle: connect to TaskNotes, wire events and commands
src/tasknotes.ts the slice of the TaskNotes runtime API used, plus the version/capability check
src/CalDavSyncService.ts push, pull, conflicts, relations, retry queue
src/SettingsTab.ts account settings UI
src/settings.ts settings types and defaults
src/caldav/ pure modules: CalDAV client, XML, ICS dates, VTODO mapping, tag and project routing, reconciliation
tests/caldav/ unit tests for src/caldav/
The pure modules in src/caldav/ hold every sync decision (what a VTODO looks like, which list a task belongs to, who wins a conflict, what to upload) and do no I/O, which is why they're the part with unit tests. CalDavSyncService carries out those decisions: vault writes, timers, network.
npm version patch # or minor / major: runs tests + build, bumps manifest.json and versions.json, commits, tags
npm run release # pushes main and the tag to origin, Codeberg and GitHub
Pushing the tag triggers CI on GitHub and Codeberg, which builds the plugin and attaches main.js, manifest.json and styles.css to a release. Tags carry no v prefix, because Obsidian looks releases up by the exact version in manifest.json.
Built on TaskNotes by Callum Alpass and its runtime API. MIT licensed, see LICENSE.