# Google Calendar

Live Google Calendar for one account: read the user's real events, and create,
update, cancel, respond to and check availability against them. Twelve tools,
admin agent only.

There is deliberately no Gmail surface here. Mail runs on the `email` plugin's
IMAP/SMTP path, and Gmail's read/modify scopes are *restricted*, which would
force Google's annual third-party security assessment. Calendar is only a
*sensitive* scope, so it needs the lighter brand verification.

## Connecting an account

`google-account-register` resolves which of two routes applies to this install
and returns one `instruction` field plus a `readback` directive. Relay the
`instruction` to the user verbatim. Do not narrate both routes or decide between
them yourself; the tool already chose.

The two routes behind that resolution:

**Auto-opened** (`path: "auto-open"`), when the install's own browser is
reachable. Register opens the Google sign-in in it, so no link is handed over.
The user signs in and approves there and the connection completes by itself. A
backup link comes back in `consentUrl` for the rare case the page did not open
in front of them.

**Paste** (`path: "paste"`), when no on-host browser is reachable, such as a
browserless brand or a phone. Register returns a consent URL to relay. The user
opens it, signs in, and approves; the loopback page then fails to load, which is
expected, because the vendor app is a Desktop client that redirects to a
loopback address the device cannot reach. The address bar still carries the
code, so they copy the whole URL from it and pass it to
`google-account-register-submit`. The tool pulls the code out of a whole URL, a
bare code, a `code=...` fragment, or a value containing `%2F`.

Either way, read the outcome back with `google-account-register-poll`, per the
result's `readback` field: `registered` names the connected email, `pending`
means it has not completed, `expired` means the code timed out and register
should be re-run. Do not tell the user they are connected before poll returns
`registered`.

The register tool does not block and does not wait. A second register while one
is already live is refused rather than overwriting it; that refusal names how
long the live one has been pending.

One account can connect several Google accounts. Every operational tool takes an
optional `account` (the email address). Omit it when there is one; with two or
more, omitting it returns a refusal listing them.

## Reading and controlling

- `google-calendar-list` — events in the next `rangeDays` days (default 7).
  Recurring series are expanded into instances, so this returns what the user
  actually sees in their calendar.
- `google-calendar-event` — one event by id.
- `google-calendar-create` — times are RFC3339 (`2026-07-20T09:00:00Z`) unless
  `allDay` is true, in which case they are plain dates (`2026-07-20`).
- `google-calendar-update` — changes only the fields you name. Omitted fields
  are left alone, so an update never blanks something by accident.
- `google-calendar-cancel` — deletes the event and notifies attendees.
- `google-calendar-respond` — accept, decline or tentatively accept an
  invitation. Every other attendee's response is preserved.
- `google-calendar-freebusy` — busy blocks between two times. Free time is the
  complement, which you work out.

## Checking health

`google-account-list` answers "is anything connected?" from local stores with no
network call. Read each entry's `status` — a count alone is not "connected", and
an unreadable store still counts. `google-account-info` gives one account's auth
state, including whether its access token is near expiry and which scopes were
granted.

## When something is wrong

**"GOOGLE_CLIENT_ID is not configured"**, or the same for
`GOOGLE_CLIENT_SECRET` — this brand has no Google vendor app yet. Nothing the
operator does on the device fixes it, and no file placed on the device fixes it
either: the id and secret ship in the brand's `brand.json` and reach the device
through an installer publish. The brand needs its own Google Cloud Desktop OAuth
client. See `platform/plugins/google/references/auth.md`.

**A 403 naming insufficient scope** — the connected account approved something
narrower than the full calendar scope. Re-run `google-account-register` so they
re-consent.

**The user re-consents every week** — the brand's Google app is still in
Testing, where Google caps refresh tokens at seven days and limits the app to
100 named test users. Completing brand verification removes both. This is a
property of the vendor app, not a fault in the connection.

**A registration never completes** — the consent URL was opened but not
approved, or the code was never copied back to
`google-account-register-submit`. `google-account-register-poll` reports
`expired` once the pending entry outlives Google's code lifetime.
