# Calendar Calendars and contacts on your own machine, synced to your phone over CalDAV and CardDAV. - **Radicale, not a container.** A ~2MB Python package, spawned on loopback by this plugin's sidecar. It was a Docker service only because the old app store made everything one. - **Per user.** The sync door resolves an app password to one account and tells Radicale that account's id is the principal; `[rights] type = owner_only` does the rest. Every user gets their own calendars and their own contacts, in their own directory, invisible to everyone else. - **Phones work.** DAVx5, iOS and Thunderbird, including RFC 6764 autodiscovery from a bare domain. ## Two screens, one plugin `/calendar` and `/contacts`. They are two places you go rather than two sections of one page, which is why this is the first plugin to declare `screens` in its manifest — one sidecar, one permission, one install, two routes and two dock tiles. ## What it claims from the platform, and why Four paths outside `/api`, above the account gate: | Path | Why it cannot sit behind the session | | --- | --- | | `/dav/*` | DAVx5, iOS and Thunderbird send HTTP Basic on every request and have nowhere to put a JWT | | `/dav/provision/*.mobileconfig` | Safari is handed a URL by the phone app and has no credential; the one-shot token in the path IS the authentication | | `/.well-known/caldav` | RFC 6764 — probed with a bare domain before the client has any credential | | `/.well-known/carddav` | the same, for contacts | "Above the account gate" is not "open". The sync door demands a scoped DAV app password and resolves it to a user before anything reaches Radicale. Every one of those is in the platform's `RESERVED_ROOT`, claimable **only** by a first-party plugin. A third-party plugin is confined to `/p//` so it can never shadow a core route. ## Extracted from the platform on 2026-08-27 It was core from 2026-08-19. What moved: the sidecar, the four routers, the panel apps, the app-password table, and the settings form — which became a modal on the Calendar screen, because a plugin ships panels and cannot contribute a settings section. Two things deliberately did **not** change. The table is still `dav_app_passwords` rather than `caldav_app_passwords`: installs already hold real rows, and the platform's prefix convention is not worth a data migration on a live machine. And the panel names still resolve through the platform's translation catalogs, so the six locales they had as core screens survive.