speze8862 downloadsBidirectionally synchronize markdown tasks tagged with #caldav to/from a CalDAV server.
An Obsidian plugin that bidirectionally synchronizes markdown tasks to/from a CalDAV server (e.g. mailcow/SOGo).
#caldav, #work, or #privateBefore sync (you write this):
- [ ] Buy groceries #private
After sync (UID written back automatically):
- [ ] Buy groceries #private <!-- caldav-uid:550e8400-e29b-41d4-a716-446655440000 -->
The UID comment is invisible in Obsidian's reading/preview mode.
main.js and manifest.json<vault>/.obsidian/plugins/obsidian-caldav-sync/
main.js and manifest.json into that foldergit clone https://github.com/your-username/obsidian-caldav-sync
cd obsidian-caldav-sync
npm install
npm run build
Then copy main.js and manifest.json to your vault's plugin folder as above.
Go to Settings → CalDAV Task Sync and add one or more calendar mappings:
| Field | Description | Example |
|---|---|---|
| Calendar name | Optional label shown in settings | Private |
| Server URL | Full CalDAV calendar URL with trailing slash | https://mail.example.com/SOGo/dav/[email protected]/Calendar/personal/ |
| Username | Username for this calendar (usually your full email for mailcow) | [email protected] |
| Password | Password for this calendar | |
| Tag | Tag that routes a task into this calendar | #private |
Use Add calendar to create additional mappings. Each calendar stores its own URL and credentials, so different servers or accounts can be used side by side.
Example mappings:
| Tag | Calendar |
|---|---|
#private |
Personal CalDAV calendar |
#work |
Work CalDAV calendar |
Example task routing:
- [ ] Pay rent #private
- [ ] Prepare Q2 review #work
Each task is synced to the calendar whose configured tag appears on the same task line.
Your calendar URL typically follows this pattern:
https://<mail-server>/SOGo/dav/<email>/Calendar/<calendar-name>/
You can verify it with curl:
curl -u [email protected]:password \
https://mail.example.com/SOGo/dav/[email protected]/Calendar/personal/ \
-X PROPFIND -H "Depth: 0"
A 207 Multi-Status response confirms the URL and credentials are correct.
Sync is triggered every time you save a markdown file.
| Scenario | Result |
|---|---|
Local [x], remote incomplete |
Local wins — pushes STATUS:COMPLETED |
Local [ ], remote completed |
Remote wins — marks task [x] in your note |
| Local title differs from remote SUMMARY | Remote wins — updates the title in your note |
| Remote VTODO not found (404) | Warning logged, local task unchanged |
| ETag conflict (412) | Re-fetches ETag and retries the PUT once |
When the plugin writes UIDs or pulled changes back to a file, it uses an internal guard to prevent that write from triggering another sync loop.
MIT