# Calendar Module Specification

**Version**: v1.2.3 | **Status**: Active | **Last Updated**: March 2026

## 1. Overview

The `calendar` module is designed to provide agents with a consistent interface to manage user calendars. It abstracts away the intricacies of different calendar providers (Google Calendar, Outlook, Apple Calendar) behind a unified, statically typed interface.

## 2. API Semantics

### 2.1 `CalendarEvent`

The `CalendarEvent` is a Pydantic `BaseModel` that serves as the universal language for events across all providers.

**Attributes:**

- `id` (Optional[str]): The unique identifier of the event. Typically generated by the provider upon creation.
- `summary` (str): The title or primary summary of the event.
- `description` (Optional[str]): Additional details or description of the event.
- `start_time` (datetime): The start time. Must be aware (have timezone info).
- `end_time` (datetime): The end time. Must be aware.
- `location` (Optional[str]): The physical or virtual location of the event.
- `attendees` (List[str]): A list of email addresses of attendees. Default is an empty list.
- `html_link` (Optional[str]): A fully-qualified URL to view the event in a browser.

### 2.2 `CalendarProvider` Protocol

The `CalendarProvider` is an `abc.ABC` defining the contract that all specific provider implementations must fulfill.

**Methods:**

- `list_events(time_min: datetime, time_max: datetime) -> List[CalendarEvent]`: Retrieves all events that overlap with the specified time range.
- `create_event(event: CalendarEvent) -> CalendarEvent`: Creates an event. The returned event contains the populated `id` and `html_link`.
- `get_event(event_id: str) -> CalendarEvent`: Retrieves a specific event. Raises `EventNotFoundError` if it does not exist.
- `update_event(event_id: str, event: CalendarEvent) -> CalendarEvent`: Partially or fully updates the event.
- `delete_event(event_id: str) -> None`: Deletes the specified event.

### 2.3 Exceptions

- `CalendarError`: Generic base exception for the module.
- `CalendarAuthError`: Represents failures during authentication or authorization.
- `CalendarAPIError`: Represents upstream provider failures (e.g., HTTP 5xx).
- `EventNotFoundError`: Raised during get/update/delete operations if the event is inaccessible or does not exist.
- `InvalidEventError`: Raised when mapping from the provider's native format to `CalendarEvent` fails, or if the provided input is missing mandatory constraints.

### 2.4 MCP Tools Integration (`mcp_tools.py`)

The calendar module exposes operations directly to compatible agents via the Model Context Protocol (MCP) using the `@mcp_tool` decorator.

Available tools:

- `calendar_list_events(days_ahead: int)`: Lists events occurring within the next specified number of days.
- `calendar_create_event(...)`: Creates a new event. Automatically injects `FristonBlanket@gmail.com` (or `CODOMYRMEX_CALENDAR_ATTENDEE` env var) into the `attendees` array to guarantee bidirectional synchronization between PAI/agents and the primary calendar.
- `calendar_get_event(event_id: str)`: Retrieves specific event details.
- `calendar_update_event(...)`: Updates an existing event. Enforces the same attendee injection rule.
- `calendar_delete_event(event_id: str)`: Deletes a calendar event.

These tools inherently require a valid `.codomyrmex/gcal_token.json` payload generated by the PAI dashboard, alongside `.env` credentials (`GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`).

## 3. Google Calendar (`gcal/provider.py`) Implementation Details

- **Dependency:** Relies on `google-api-python-client`.
- **Initialization:** Requires a valid `google.oauth2.credentials.Credentials` object or an authenticated `Resource` object.
- **Timezone Handling:** Converts all datetime inputs to ISO-8601 strings, appending 'Z' explicitly if the datetime is naive (though naive datetimes are discouraged).
- **Graceful Parsing:** Defaults to `(No title)` for missing summaries, handling both date ('date') and datetime ('dateTime') boundaries to accommodate all-day events. All parsed datetimes are converted to aware `datetime` objects in UTC.

## Navigation

- **Self**: `SPEC.md`
- **Parent**: [../README.md](../README.md)
- **Readme**: [README.md](README.md)
- **Agents**: [AGENTS.md](AGENTS.md)
- **Repository Root**: [README.md](../../../README.md)
