caldav leaves the platform

calendar and contacts are a plugin now — plugins/caldav, its own repository like
every other one. a fresh machine runs five processes instead of seven and gets a
calendar by installing one plugin, which is the whole point: the platform stops
carrying a python calendar server for people who may not want one.

what left: the radicale sidecar, four routers, the panel apps, the
dav_app_passwords table, the two screens, the two dock tiles, the permission
registry entry, the settings section, and radicale from every package list.

three platform things had to change first, each committed on its own:
6b5c87da a plugin can be more than one screen; e0df28ff a first-party plugin can
claim a reserved root path. this commit adds the third, `personal` on a plugin
permission — a member granted READ must still mint and revoke their own app
password, because that password is how their own phone reaches their own
calendar. those rows are theirs and nobody else's.

two fixes the work surfaced rather than caused. the dock pinned mountPrefix, so
a multi-screen plugin pinned a tile pointing at /caldav — a route no plugin
serves. and the OPTIONS carve-out was a literal list of four DAV paths; it asks
the claim registry now, so it follows whoever owns the route.

/calendar stays in DEFAULT_DOCK_PATHS. it is installed by default and a fresh
dock that silently dropped it would read as a downgrade.

docs:check earned its keep twice here: it caught spotlight still offering
/settings/integrations/dav-app-passwords after the section was deleted, and the
permission count going 22 -> 21. neither is greppable and both were already wrong
when it ran.

verified against alpha, which is still on the pre-extraction code: /.well-known/
caldav 301s, /dav/ answers 401 with the same WWW-Authenticate realm byte for
byte, /api/caldav/passwords 401s, and OPTIONS reaches the DAV router rather than
being answered as a CORS preflight. installed here end to end — schema applied,
sidecar started, two tiles with their own artwork behind one permission.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
2026-08-27 04:54:42 +00:00
co-authored by Claude Opus 5
parent e0df28ff5d
commit 52f209c69f
45 changed files with 108 additions and 2277 deletions
+3 -9
View File
@@ -109,29 +109,23 @@ pkgs_core() {
echo curl ca-certificates gnupg git jq unzip \
apt-transport-https lsb-release software-properties-common \
wget zip brotli build-essential python3 btop tree tmux ripgrep fd-find net-tools eza \
inotify-tools poppler-utils radicale fail2ban unattended-upgrades
inotify-tools poppler-utils fail2ban unattended-upgrades
;;
pacman)
echo curl ca-certificates gnupg git jq unzip \
wget zip brotli base-devel python btop tree tmux ripgrep fd net-tools eza \
inotify-tools poppler radicale fail2ban
inotify-tools poppler fail2ban
;;
dnf)
echo curl ca-certificates gnupg2 git jq unzip \
wget zip brotli python3 btop tree tmux ripgrep fd-find net-tools eza \
inotify-tools poppler-utils radicale fail2ban
inotify-tools poppler-utils fail2ban
;;
brew)
# curl, unzip and the TLS roots ship with macOS; the compilers come from
# the Xcode command line tools, which is not a formula — see xcode_clt_*.
# brotli is here because macOS ships the library but not the CLI.
#
# radicale has no Homebrew formula — confirmed live ("No available formula with the
# name radicale"), it is a pure-Python package normally installed via pip/pipx, not
# brew. Left out of a dev install rather than reached for pip here: officer-caldav
# (services.sh CORE_PROCESSES) is skipped to match on macOS, so nothing on this
# machine expects it to be present. The Linux lists above are untouched — a real
# package there, unaffected.
echo gnupg git jq wget brotli btop tree ripgrep fd eza poppler
;;
esac
+4 -14
View File
@@ -55,20 +55,10 @@ CORE_PROCESSES=(
"officer-notify|bun|run src/servers/sidecar/notify/index.ts"
)
# Calendar and contacts, CORE since 2026-08-19 rather than an app-store entry.
#
# It was a Docker service because the app store made everything one, not because Radicale needs a
# container — it is a ~2MB Python package, and this sidecar spawns it directly on loopback. A personal
# server having a calendar is not an integration with something you already run; it is the baseline.
# Radicale needs `python3` and the `radicale` package, both installed by machine-setup.
#
# EXCEPT on macOS: radicale has no Homebrew formula (pkgs_core in machine-setup/lib/packages.sh
# leaves it out of the brew list for the same reason), so a dev install has nowhere for this sidecar
# to find it — `resolveRadicale()` failing is exactly the "took a whole sidecar down on a fresh
# install" case its own test guards against. Left out of a macOS install's process list entirely
# rather than crash-looped; Calendar/Contacts are the one core feature not available on a Mac dev
# install. The Linux path — and the feature itself — is untouched.
[[ "$(uname -s)" == "Darwin" ]] || CORE_PROCESSES+=("officer-caldav|bun|run src/servers/sidecar/caldav/index.ts")
# Calendar and contacts are NOT here. They were core from 2026-08-19 until 2026-08-27, when caldav became
# a plugin: it declares its own sidecar, its own `radicale` dependency and its own two screens, and the
# generated ecosystem file gains an `officer-caldav` entry when it is installed. A fresh machine runs five
# processes instead of seven, and gets a calendar by installing one plugin.
write_ecosystem() {
local dest entry name script args