---
name: google-calendar-stdlib
description: Access Google Calendar API via Python stdlib only (no pip, no google-api-python-client). For headless servers like ZimaOS with stored OAuth refresh tokens.
triggers:
  - User wants Google Calendar read/write without pip/google packages
  - ZimaOS / headless Linux needs Calendar access
  - "google-api-python-client not installed"
  - "no pip available"
  - Accessing Google Calendar via urllib / raw HTTP
  - Need to read/write Google Calendar events on a server
---

# Google Calendar via Python Stdlib

When `pip`, `google-api-python-client`, and `requests` are unavailable (e.g. ZimaOS), use a pure-Python-stdlib wrapper that speaks directly to the Google Calendar API v3 over HTTPS.

## Prerequisites

- A valid **OAuth refresh token** (and client ID + secret). Usually already present in the Hermes env or a `.secrets/google_oauth.env` file.
- System Python 3 (no extra packages required).

## The Wrapper

Use the included template: `templates/kiwitime.py`.
- Install to `~/.bin/kiwitime` (or `.bin/kiwitime` under `$HERMES_HOME`) and `chmod +x`.
- The script handles automatic access-token refresh via `urllib`.
- Supports `list`, `create`, `delete` operations.

## Built-In Commands

| Command | Example |
|---------|---------|
| List events | `python3 kiwitime.py list "Arbeit" 14` |
| Create event | `python3 kiwitime.py create "Ahmed und Talla" "Date" "2026-05-10T19:00:00+02:00" "2026-05-10T21:00:00+02:00" "Dinner"` |
| Delete event | `python3 kiwitime.py delete "Arbeit" EVENT_ID` |

## CRITICAL Pitfalls

1. **Hardcoded `time_min` in list command**  
## CRITICAL Pitfalls

1. **Friendly names vs raw IDs**  
   The wrapper internally maps short friendly names (e.g. `"Arbeit"`, `"Uni"`, `"Ahmed und Talla"`) to the long Google Calendar hash IDs.  
   **Always pass the friendly name or the exact primary calendar email** (`ahmed.aytac@gmail.com`).  
   Passing the raw hash ID like `a2ac7dd2…@group.calendar.google.com` will return *"Kalender nicht gefunden"* and produce a false-empty result.

2. **ISO-8601 with explicit offset**  
   Google requires timezone offsets in event payloads. Use `"2026-05-10T19:00:00+02:00"`, not naive strings.

3. **Token expiry**  
   Access tokens expire after ~1 hour; the script auto-refreshes via the token endpoint. If refresh fails, check the `GOOGLE_REFRESH_TOKEN` validity.

4. **Hardcoded `timeMin` in old binary**  
   If `kiwitime` returns events from May 2026 regardless of current date, the binary still uses the old hardcoded `timeMin="2026-05-08T00:00:00+02:00"`. Reinstall the current template to `~/.bin/kiwitime`.

## Binary vs Template

The runtime binary lives at `~/.bin/kiwitime` (or `$HERMES_HOME/.bin/kiwitime`).  
The skill template at `templates/kiwitime.py` is the source of truth.  
When the template is patched (e.g. to fix the dynamic-date bug), copy it to the binary path:

```bash
cp /DATA/AppData/hermes/skills/productivity/google-calendar-stdlib/templates/kiwitime.py /DATA/AppData/hermes/.bin/kiwitime
chmod +x /DATA/AppData/hermes/.bin/kiwitime
```

**Verification after update:**
```bash
kiwitime list "Ahmed und Talla" 1
# Should show today's events, not events from May 2026
```

If the agent no longer has `terminal` access, the user must run the copy command above manually.

## Reference

See `references/calendar-ids.md` for the user's specific calendar friendly-name-to-ID mapping.
