Publish /timebox schedules to Google Calendar#11
Merged
Conversation
…nfig - add calendar.events to OAuth SCOPES; tokens minted before need re-auth - extract get_google_service() in google_auth; drive_handler reuses it - add has_calendar_scope() to detect tokens missing calendar grant - add TIMEBOX_CALENDAR_ID + fixed-block anchors (day start/end, lunch, dinner, eat/commute durations) to config and .env.example - seed CONTEXT.md glossary and ADR-0001 (calendar idempotency)
generate_schedule now takes a DayConfig (day window, lunch, dinner, eat + commute durations) and a mode. The LLM owns placement and emits the fixed blocks as slots, overriding any when a user task states a conflicting time. Commute blocks are injected only in office mode.
mirrors drive_handler over a calendar v3 service. Bot events carry a private extendedProperties tag (source=timebox) so list/clear only ever touch our own events. write_schedule attempts every item and reports per-item ok/fail; slots crossing midnight roll the end into the next day. Mocked tests, no live API.
/timebox now: pick Office/WFH (inline keyboard) -> pin target date and check the Target Calendar -> if a schedule exists, confirm redo (keep vs overwrite) before collecting -> /done generates with mode + fixed blocks, clears prior bot events, writes each slot, and replies with per-event ✅/❌. Any failure keeps the buffer open so /done retries (clear-then-write stays idempotent). Falls back to a text-only reply when no calendar is configured, and asks for re-auth when the calendar scope is missing.
- webhook_server: add callback_query to allowed_updates so inline-button presses (/timebox Office/WFH, redo) reach the bot - Dockerfile: copy the whole src/ dir so new modules (scheduler, timebox, calendar_handler, …) ship in the image instead of crashing on import - docs: bring README/DEPLOY/DEVELOPMENT/.env.example in line with the current code — two run modes (polling + webhook), /timebox, calendar scope, OPENROUTER_API_KEY (required), TIMEBOX_* vars, correct DRIVE_FOLDER_NAME default, new module tree, deploy troubleshooting for the connection-refused and OAuth scope-change failures - fix run_local.sh / start_webhook.sh to use src/ paths - claude.md: drop the now-fixed helper-script gap Also includes the in-flight branch work: /status --local marker, fly.toml image bump to v1.0.6.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds Google Calendar publishing to the
/timeboxfeature, tailored to a personal-assistant use case.Flow
/timebox→ pick Office / WFH (inline keyboard) → pin target date + check the Target Calendar → if a schedule already exists for that day, confirm redo (overwrite vs keep) before collecting → collect tasks →/donegenerates the schedule and publishes it.Scheduling
TIMEBOX_DAY_START/END,TIMEBOX_LUNCH,TIMEBOX_DINNER,TIMEBOX_EAT_DURATION,TIMEBOX_COMMUTE_MORNING/EVENING,TIMEBOX_COMMUTE_DURATION).Calendar writes
TIMEBOX_CALENDAR_ID); never the primary.extendedProperties.private.source=timebox. Publishing is clear-then-write, so re-runs converge on one schedule and never touch manual events (seedocs/adr/0001)./donereplies with a per-event ✅/❌ and keeps the buffer open to retry failures.Config / setup
calendar.eventsOAuth scope → existing users must re-run/authenticate(the bot detects a missing scope and prompts).TIMEBOX_CALENDAR_ID→ schedule is replied as text only (no calendar write).Implementation
get_google_service()extracted intogoogle_auth.py;drive_handlerand the newcalendar_handlerboth reuse it.calendar_handler.pymirrorsdrive_handler(tag/list/clear/per-item write).scheduler.generate_schedulenow takes aDayConfig+ mode; stays pure/offline-testable.Tests
scheduler+ newcalendar_handler).