# AGENTS.md Guidance for a coding agent working on **this plugin's own repository**. `CLAUDE.md` beside it only points here — the two harnesses discover different filenames and one set of instructions has to reach both. **This is not what the plugin is.** `README.md` answers that, for a person deciding whether to install it. This file answers "I have to change something in here — what will I break?" ## Where you are A plugin repository, cloned into `~/officer-dev/plugins/caldav`, its own git remote. It is **not** part of the platform's repository, and `platform/plugins/caldav` is a different thing — that is where this plugin gets INSTALLED, by the installer cloning it from gitea. Never edit there; the next install overwrites it. Verify the checkout is well-formed with `bun run plugins:check` from the platform repo. ## What this plugin is, in one paragraph Calendars and contacts over CalDAV and CardDAV, backed by Radicale spawned on loopback by its own sidecar. One sidecar, one permission, **two screens** — `/calendar` and `/contacts` — which makes it the only plugin using `screens` in its manifest. ## What must not change without knowing why - **`/dav`, `/.well-known/caldav`, `/.well-known/carddav`.** Claimed in `unauthenticatedRootPaths`, served ABOVE the account gate because phones send HTTP Basic and have nowhere to put a JWT. Reserved names, claimable only because this is a first-party plugin. - **`dav_app_passwords`** is not prefixed `caldav_` and the installer warns about it. Deliberate: installs hold real rows and a naming convention is not worth a data migration. - **The two screen segments.** They were core routes; bookmarks, dock tiles and persisted layouts all address them. - **The panel keys** (`calendar-nav`, `calendar-view`, `contacts-nav`, `contacts-view`). A stored layout names them. ## Traps that have already cost time - **`sidecar/radicale.ts` generates `radicale.conf` inside a template literal.** A backtick in a comment there terminates the string and the file stops parsing. No test imports it, so only `bunx tsgo` catches this. - **`createSidecarProxy` mounts a catch-all**, so in `api/router.ts` the plugin's own routes must be registered BEFORE it or they are forwarded to the sidecar and 404. - **Request bodies are not parsed** on this plugin's routes — the proxy registers the whole prefix with `registerProxiedPrefix`. Use `jsonBody()` in `api/app-passwords.ts`, not `ctx.get('body')`. - **`date -u -d` does not convert local time to UTC.** It parses AND prints as UTC. Every event lands an hour out and nothing errors. See the skill. ## Verifying From the platform repo, because that is where the toolchain is: ```bash bunx tsgo # a red typecheck is not done bun test # 1 known failure: ModelSelector, unrelated bun run plugins:check bunx prettier --write ``` Changing the sidecar needs `pm2 restart officer-caldav`; changing `api/` or `web/` needs `pm2 restart officer`. ## Related - `README.md` — what it is and what it claims, for someone installing it - `skills/calendar-and-contacts/SKILL.md` — how an agent USES the calendar, as opposed to changing it