Personal AI executive assistant — inbox monitoring, classification, and Slack alerts
- SAM template with DynamoDB, two Lambdas (fetch-classify, daily-digest), ECS/Fargate for Socket Mode listener, EventBridge Scheduler - Gmail API integration with OAuth refresh and History API sync - Bedrock Haiku classification (HIGH/NORMAL/LOW) - Slack DM delivery with Block Kit formatting and threading - Socket Mode listener for two-way conversation (placeholder) - Setup script for Gmail OAuth token exchange - Slack app manifest for app creation |
||
|---|---|---|
| listener | ||
| scripts | ||
| src | ||
| .gitignore | ||
| PLAN.md | ||
| README.md | ||
| samconfig.toml.example | ||
| slack-app-manifest.yaml | ||
| template.yaml | ||
Exec Aide
Personal AI agent that monitors Adam Moussa's Gmail inbox, classifies emails by urgency using Claude Haiku (Bedrock), and delivers Slack alerts and daily digests.
Architecture
EventBridge (15 min) → fetch-classify Lambda → Gmail API → Bedrock Haiku → DynamoDB + Slack DM
EventBridge Scheduler (5 PM ET M-F) → daily-digest Lambda → DynamoDB + Gmail API → Slack DM
- exec-aide-fetch-classify: Polls Gmail via History API, classifies each new message, sends immediate Slack DM for HIGH priority items, tracks thread state for unanswered detection.
- exec-aide-daily-digest: Summarizes the day's high-priority items, bypassed work orders (emails not CC'ing work-orders@), and unanswered threads older than 24h.
- DynamoDB table
exec-aide: Single-table design with message records, thread tracking, and sync metadata. 90-day TTL.
Classification Rules
| Category | Trigger |
|---|---|
| HIGH | VIP sender, urgency keywords, escalation language, financial/legal matters |
| NORMAL | Standard business correspondence |
| LOW | Newsletters, automated notifications, marketing |
| Bypassed WO | Email to Adam without work-orders@ in TO/CC |
| Unanswered | Thread where Adam hasn't replied in 24h+ |
Prerequisites
- AWS CLI + SAM CLI
- Python 3.12
- Gmail API enabled in Google Cloud Console
- Slack app with
chat:write+im:writescopes
One-Time Setup
1. Gmail OAuth
# Install the setup dependency (not needed in Lambda)
pip install google-auth-oauthlib
# Download OAuth client JSON from Google Cloud Console, then:
python scripts/get_gmail_token.py --client-secrets-file path/to/client_secret.json
# Authorize as adam@seahavenind.com in the browser
# Copy the output into Secrets Manager
2. Secrets Manager
# Gmail OAuth (output from step 1)
aws secretsmanager create-secret --name exec-aide/gmail-oauth --secret-string '...'
# Slack bot token
aws secretsmanager create-secret --name exec-aide/slack-bot-token --secret-string 'xoxb-...'
3. SSM Parameters
aws ssm put-parameter --name /exec-aide/adam-email --value adam@seahavenind.com --type String
aws ssm put-parameter --name /exec-aide/adam-slack-user-id --value U01XXXXXXXX --type String
aws ssm put-parameter --name /exec-aide/vip-senders --value '["ceo@example.com"]' --type String
aws ssm put-parameter --name /exec-aide/vip-domains --value '["example.com"]' --type String
aws ssm put-parameter --name /exec-aide/work-order-addresses --value '["work-orders@seahavenind.com","work-orders@seahaven.com"]' --type String
aws ssm put-parameter --name /exec-aide/unanswered-threshold-hours --value 24 --type String
Deploy
cp samconfig.toml.example samconfig.toml # edit if needed
sam build
sam deploy
Manual Testing
# Trigger a poll
aws lambda invoke --function-name exec-aide-fetch-classify /dev/stdout
# Trigger the daily digest
aws lambda invoke --function-name exec-aide-daily-digest /dev/stdout
Updating VIP List or Keywords
Edit the SSM parameters directly — changes take effect on the next Lambda cold start (or within ~15 minutes):
aws ssm put-parameter --name /exec-aide/vip-senders --value '["new@example.com"]' --type String --overwrite