Personal AI executive assistant — inbox monitoring, classification, and Slack alerts
This repository has been archived on 2026-08-04. You can view files and clone it, but cannot push or open issues or pull requests.
Find a file
Adam Moussa 460cf200c7 Migrate from SAM to CDK per Sea Haven conventions
SAM is for simple serverless stacks; this project has ECS, VPC, and
multi-service composition which requires CDK. Migration brings
ContainerImage.fromAsset() for automatic Docker builds on deploy,
matching the seahaven-slack-bot pattern.

Also fixes: Bedrock model ID (add version suffix), Gmail history API
parameter (labelId not labelIds), classify JSON extraction (handle
markdown fences), and digest block limit (cap sections at 5 items
to stay under Slack's 50-block limit).
2026-04-30 19:23:52 -04:00
bin Migrate from SAM to CDK per Sea Haven conventions 2026-04-30 19:23:52 -04:00
lib Migrate from SAM to CDK per Sea Haven conventions 2026-04-30 19:23:52 -04:00
listener Add SAM stack, Fargate listener, and shared modules 2026-04-30 17:40:58 -04:00
scripts Add SAM stack, Fargate listener, and shared modules 2026-04-30 17:40:58 -04:00
src Migrate from SAM to CDK per Sea Haven conventions 2026-04-30 19:23:52 -04:00
.gitignore Migrate from SAM to CDK per Sea Haven conventions 2026-04-30 19:23:52 -04:00
cdk.context.json Migrate from SAM to CDK per Sea Haven conventions 2026-04-30 19:23:52 -04:00
cdk.json Migrate from SAM to CDK per Sea Haven conventions 2026-04-30 19:23:52 -04:00
package-lock.json Migrate from SAM to CDK per Sea Haven conventions 2026-04-30 19:23:52 -04:00
package.json Migrate from SAM to CDK per Sea Haven conventions 2026-04-30 19:23:52 -04:00
PLAN.md Add implementation plan for ultraplan refinement 2026-04-30 16:49:04 -04:00
README.md Add SAM stack, Fargate listener, and shared modules 2026-04-30 17:40:58 -04:00
slack-app-manifest.yaml Add SAM stack, Fargate listener, and shared modules 2026-04-30 17:40:58 -04:00
tsconfig.json Migrate from SAM to CDK per Sea Haven conventions 2026-04-30 19:23:52 -04:00

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:write scopes

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