Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Quick start: CLI

This walks through a first sync from one CalDAV calendar to another. For Calendar.app calendars, see the desktop app quick start or Calendar.app to Nextcloud.

1. Create a config

capycal --generate-config

This writes a commented starter config to the default location and refuses to overwrite an existing file:

OSConfigState
Linux~/.config/capycal/capycal.toml~/.local/state/capycal/
macOS~/Library/Application Support/capycal/capycal.toml~/Library/Application Support/capycal/state/

Use -c <path> with any command for a different config file.

2. Find your calendars

capycal --discover https://caldav.example.com

Capycal asks for username and password, looks up the CalDAV root (RFC 6764, /.well-known/caldav) and prints an [accounts.<name>] snippet for the server and one [calendars.<name>] snippet per calendar:

[accounts.work]
url = "https://caldav.example.com/"
username = "alice"
password = { env = "CAPYCAL_WORK_PASSWORD" }

[calendars.work]
account = "work"
url = "https://caldav.example.com/calendars/alice/work/"

On macOS, capycal --discover-eventkit does the same for Calendar.app.

3. Wire a sync

Copy the source calendar and the calendar that should receive the blockers into the config, then edit the sync:

[daemon]
log_level = "info"

[accounts.work]
url = "https://caldav.example.com/"
username = "alice"
password = { env = "CAPYCAL_WORK_PASSWORD" }

[accounts.nextcloud]
url = "https://cloud.example.org/remote.php/dav/"
username = "alice"
password = { env = "CAPYCAL_HOME_PASSWORD" }

[calendars.work]
account = "work"
url = "https://caldav.example.com/calendars/alice/work/"

[calendars.blockers]
account = "nextcloud"
url = "https://cloud.example.org/remote.php/dav/calendars/alice/work-blockers/"

[syncs.work-to-blockers]
source = "work"
target = "blockers"
interval = "5m"

transforms = [
  { field = "SUMMARY", action = "set_field", value = "Busy ({{source_name}})" },
]

Use a dedicated, empty calendar as the target. Capycal only touches events it created, but a separate calendar is easier to hide, share or clean up.

4. Check and run once

export CAPYCAL_WORK_PASSWORD=... CAPYCAL_HOME_PASSWORD=...
capycal --validate
capycal --once -v

--validate parses the config and checks references, transforms and placeholders without contacting a server. --once runs every sync one time and exits with a non-zero code if any sync failed; -v adds debug output.

5. Run as a daemon

capycal

Without --once, Capycal keeps running and syncs every interval until it receives SIGINT or SIGTERM. For a permanent setup, see Running on a server.

Next: Config file and the Cookbook.