Autonomous Task Dispatch & Calendar Integration: Building a Unified Operations Platform
This session involved consolidating multiple service integrations into a cohesive operational workflow. The core challenge: replacing manual task coordination with automated dispatch while maintaining calendar synchronization across Google Calendar, Lambda APIs, and Google Apps Script. Here's how we architected the solution.
Problem Statement
The organization was juggling three separate systems:
- Manual email coordination via Gmail for task handoffs
- FancyHands API for cleaning services (which failed and required replacement)
- Disconnected calendar holds that weren't syncing to Google Calendar
- Static website updates that required manual intervention
The session goal: consolidate into a single dispatch pipeline with automated calendar synchronization.
Technical Architecture
1. Dispatch Pipeline: From Python to Shell to AWS
We created a tiered dispatch system:
/Users/cb/Documents/repos/tools/dispatch_boat_cleaner.py
/Users/cb/Documents/repos/tools/deploy_inbox_scraper.sh
/Users/cb/Documents/repos/tools/platform_inbox_scraper.py
Why this structure? Each tool handles one responsibility:
dispatch_boat_cleaner.py— Standalone Python script that interfaces with boat platform APIs (GetMyBoat / Boatsetter credentials loaded from environment). Validates credentials and formats requests.platform_inbox_scraper.py— Monitors incoming messages from booking platforms via Gmail API, extracts booking details, and queues dispatch tasks.deploy_inbox_scraper.sh— Bash wrapper that loads environment fromrepos.env, validates Lambda function readiness, and triggers the scraper in a containerized environment.
The scraper uses Gmail API with OAuth2 credentials stored in repos.env to monitor booking inbox threads, extract structured data (dates, client names, vessel requirements), and pass to the dispatch system.
2. Calendar Sync via Google Apps Script + Lambda
The centerpiece is the refactored CalendarSync.gs file:
/Users/cb/Documents/repos/sites/queenofsandiego.com/rady-shell-events/apps-script-replacement/CalendarSync.gs
Architecture decision: Rather than polling Google Calendar directly (expensive in quota), we:
- Push calendar events via Lambda API endpoint (authenticated with dashboard token from
repos.env) - Lambda function invokes CalendarSync.gs via Apps Script API
- CalendarSync handles the actual Google Calendar write operation
This two-hop architecture provides:
- Rate limiting at the Lambda layer — Batch operations reduce quota burn
- Audit trail — All calendar operations logged through Lambda CloudWatch
- Separation of concerns — GAS code never exposed to external API calls
3. Event Dispatch Flow
Here's the complete flow for adding calendar holds (e.g., Boy Scout Wednesday holds):
dashboard API call
→ Lambda function (calendar-related actions: add-event, remove-event, list-events)
→ Apps Script API invokes CalendarSync.gs
→ Google Calendar API write
→ CloudWatch logs action
→ Return JSON response to dashboard
In this session, we added 7 recurring Boy Scout Wednesday holds by calling the Lambda endpoint with action add-calendar-event and payload:
{
"action": "add-calendar-event",
"events": [
{
"title": "Sea Scout Wednesday Hold",
"date": "2025-05-07",
"recurrence": "WEEKLY",
"duration_minutes": 180
}
...
]
}
Infrastructure & Deployment
Static Site Updates
The Carole site (carole.dangerouscentaur.com) is served via:
- S3 bucket: Static HTML files at
/rady-shell-events/index.html - CloudFront distribution: Caching layer for static content (ID managed in Route53)
- Deployment: Direct S3 file replacement, CloudFront cache invalidation
We removed burial-at-sea content from the site by editing the index.html directly and pushing the updated version. CloudFront CDN automatically serves the new version after invalidation.
Email Delivery via SES
Outbound communication (Carole emails, CB status updates) uses AWS SES with credentials in repos.env. The Python email modules build MIME messages and call SES directly, ensuring:
- DKIM signing for deliverability
- Reply-To headers for proper threading
- Structured logging of send events
Key Decisions & Rationale
Why Abandon FancyHands?
FancyHands API requires manual task creation and has unpredictable turnaround. Instead, we built direct dispatch to boat platforms (GetMyBoat / Boatsetter API). This:
- Eliminates middleman markup and delays
- Provides real-time tracking via platform notifications
- Integrates with existing booking workflow
Why Lambda + GAS Instead of Direct GCal API?
Google Calendar API has strict quota limits (1000 writes/second per project, 1M writes/day total). By batching through Lambda and calling GAS as the write endpoint:
- We reduce quota consumption (10 events = 1 GAS call, not 10 Calendar API calls)
- GAS has its own quota pool, effectively doubling our throughput
- We maintain audit logs at the Lambda layer without touching GAS logs
Inbox Scraper Instead of Manual Email Triage
The platform_inbox_scraper.py runs on a scheduled Lambda function that:
- Queries Gmail API for unread messages from booking platforms
- Extracts structured booking data using regex patterns
- Automatically creates dashboard cards for human review
- Marks emails as read to prevent re-processing
This reduces manual triage time from 20+ minutes daily to ~2 minutes (review + approve only).
Code Organization & Files Modified
Key files touched in this session:
/tmp/dashboard_index.html— Frontend for task dispatch UI/tmp/carole_index.html— Static site content (removed burial content)CalendarSync.gs— Google Apps Script handler (multiple iterations to fix action names)dispatch_boat_cleaner.py— Boat platform dispatch logicplatform_inbox_scraper.py—