# Calendar Import — pulling the last 30 days into the Golden Section

A reusable procedure for seeding Step ① from Google Calendar. Works for the owner or a client (anyone whose calendar is connected). Default window is **the last 30 days**; pass a different `--days` if asked.

## Why a script
Fetching and classifying calendar data by hand is slow and inconsistent. `scripts/calendar_to_tasks.py` does the deterministic part — dedupe, exclude noise, bucket, sum hours, pre-classify — so every run is identical. You only supply judgement on the two lenses a calendar can't know (energy, telos).

## Procedure

1. **Fetch the window.** Load the Calendar tools (`tool_search` "calendar events" if not already loaded) and call `Google Calendar:list_events`:
   - `startTime` = today − 30 days, `endTime` = now (ISO 8601 with the user's offset)
   - `orderBy: "startTime"`, `pageSize: 100`, `timeZone` = the user's IANA zone
   - If the response has a `nextPageToken`, page until exhausted and concatenate the `events` arrays.
   Save the **full response** (it includes `summary` = the owner's email, used to detect external attendees) to a file, e.g. `/tmp/events.json`.

2. **Run the importer.**
   ```bash
   python scripts/calendar_to_tasks.py /tmp/events.json --days 30
   # options: --days N  |  --owner-email me@co.com  |  --no-offcal  |  --max-samples N
   ```
   It returns JSON: `tasks` (ready for `SEED_TASKS`), plus `dedup_removed`, `excluded`, and `owner_domain` for your summary.

3. **What it does automatically**
   - **Dedupe:** collapses the `FROM_GMAIL` auto-copy of each Calendly/Zoom invite and the `no-reply@circle.so` copy of community events — same start/end instant → one task. Reports the count removed.
   - **Exclude:** drops `OFF`/PTO blocks, personal/health/family events (gym, golf, meals, etc.), and all-day items (hotel stays, multi-day OFF). Reports excluded hours so you can mention them.
   - **Bucket + sum** the rest into: Focus/deep-work, Sales/consult/onboarding, 1:1 client coaching, Group/community calls, Internal/team meetings, Other meetings, Travel. A 1:1 with one external attendee is read as a client/coaching call.
   - **Pre-classify** tier / function / decide / act per bucket, and append three `[Off-calendar]` placeholder rows at 0h (suppress with `--no-offcal`).

4. **Inject + confirm.** Drop `tasks` into the dashboard's `SEED_TASKS` (replace the `/* INJECT_TASKS */ let SEED_TASKS = [];` line), set `OWNER_NAME`, save to `/mnt/user-data/outputs/`, present it. Then say plainly:
   - **Energy and Telos are guesses** — the calendar can't see them. Ask the user to confirm/adjust those columns live.
   - **Calendar only sees booked time** — their real Golden Section (reading, IP/build, content, strategy) is the `[Off-calendar]` rows at 0h; have them fill in real hours.
   - If a **Travel** row is present and the window was atypical (a trip), tell them to delete it for a clean view.

## Caveats to always surface
- A 30-day window can catch travel, OFF days, and launches — it may not be a *typical* month. For a representative read, a normal **7-day** week (`--days 7`) is often cleaner; offer it.
- Heuristics are good, not perfect. The buckets are starting points — the user edits anything that's miscategorised in the dashboard.

## Schema (what `tasks` items look like)
`{ task, hours, energy, prof, tier, fn, decide, act, owner, note }` — identical to the dashboard's `SEED_TASKS` schema in SKILL.md, so injection is a straight paste.
