# Google Workspace: Standalone HTTP Workaround

Session: May 8, 2026 — Kiwi (Hermes Agent) setting up Google Calendar access for user Ahmed on ZimaOS.

## Problem
ZimaOS does not have `pip` available in the system Python. The venv at `/DATA/AppData/hermes/venv/bin/` also lacks `pip`. The Google Workspace skill's `setup.py` and `google_api.py` scripts require `google-api-python-client` which cannot be installed.

## Prerequisites: bootstrap pip first
Before falling back to urllib, try bootstrapping pip via `ensurepip` (bundled with Python 3.12 on ZimaOS):

```bash
export PYTHONUSERBASE=/DATA/AppData/hermes/.local
python3 -m ensurepip --upgrade --user
export PATH="$PYTHONUSERBASE/bin:$PATH"
```

If this succeeds, install the Google packages normally:
```bash
pip install --user google-api-python-client google-auth-oauthlib google-auth-httplib2
```

Only proceed to the urllib workaround below if `ensurepip` is also unavailable.

## Solution: Pure Standard-Library HTTP Client
When the environment lacks pip and the skill's scripts cannot run, fall back to a lightweight urllib-based client that speaks the Google REST APIs directly.

### Step 1: Read existing OAuth credentials
The user's `.env` or `.secrets/google_oauth.env` often already contains:
- `GOOGLE_CLIENT_ID`
- `GOOGLE_CLIENT_SECRET`
- `GOOGLE_REFRESH_TOKEN`

```python
import urllib.request, urllib.parse, json

CLIENT_ID = "..."
CLIENT_SECRET = "..."
REFRESH_TOKEN = "..."
TOKEN_URI = "https://oauth2.googleapis.com/token"

# Refresh access token
data = urllib.parse.urlencode({
    "refresh_token": REFRESH_TOKEN,
    "client_id": CLIENT_ID,
    "client_secret": CLIENT_SECRET,
    "grant_type": "refresh_token",
}).encode()
req = urllib.request.Request(TOKEN_URI, data=data, headers={"Content-Type": "application/x-www-form-urlencoded"})
with urllib.request.urlopen(req) as resp:
    tokens = json.loads(resp.read())
    access_token = tokens["access_token"]
```

### Step 2: Call Calendar API directly

**List calendars:**
```python
req = urllib.request.Request(
    "https://www.googleapis.com/calendar/v3/users/me/calendarList",
    headers={"Authorization": f"Bearer {access_token}"},
)
with urllib.request.urlopen(req) as resp:
    result = json.loads(resp.read())
    calendars = result["items"]
```

**List events:**
```python
from datetime import datetime, timedelta, timezone

now = datetime.now(timezone.utc).isoformat()
max_time = (datetime.now(timezone.utc) + timedelta(days=7)).isoformat()

params = {
    "timeMin": now,
    "timeMax": max_time,
    "orderBy": "startTime",
    "singleEvents": "true",
}
url = f"https://www.googleapis.com/calendar/v3/calendars/{CALENDAR_ID}/events?{urllib.parse.urlencode(params)}"
req = urllib.request.Request(url, headers={"Authorization": f"Bearer {access_token}"})
```

**Create event:**
```python
body = {
    "summary": "Meeting",
    "description": "Details",
    "start": {"dateTime": "2026-05-10T10:00:00+02:00", "timeZone": "Europe/Vienna"},
    "end": {"dateTime": "2026-05-10T11:00:00+02:00", "timeZone": "Europe/Vienna"},
}
data = json.dumps(body).encode()
req = urllib.request.Request(
    f"https://www.googleapis.com/calendar/v3/calendars/{CALENDAR_ID}/events",
    data=data, headers={"Authorization": f"Bearer {access_token}", "Content-Type": "application/json"},
    method="POST"
)
```

### Step 3: Wrap as reusable CLI tool
Save the above as a standalone Python script (no external deps) and place it in `/DATA/AppData/hermes/.bin/` with `chmod +x`.

## When to use this workaround
- `pip` is missing from the system Python
- `python3 -m ensurepip` fails due to permissions
- The standard `google_api.py` script throws `ModuleNotFoundError`
- User needs Calendar/Gmail/Drive access ASAP without waiting for pip

## When NOT to use this
- If `pip` IS available: prefer `pip install google-auth google-auth-oauthlib google-auth-httplib2 google-api-python-client` and use the skill's built-in scripts.
- If the user needs Sheets/Contacts/Docs: expand the urllib wrapper or install the proper libraries.

## Pitfalls
- `urllib` handles pagination differently than the Python SDK. For Drive with thousands of files, you must manually follow `nextPageToken`.
- Error handling is manual (catch `urllib.error.HTTPError`).
- OAuth refresh must be handled manually when the access token expires.
- URL-encode calendar IDs that contain `@` or special characters.
