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 df56bd6e9a Add AI-driven marketing filter, activate Fargate listener, update docs
Bedrock Haiku now classifies marketing/promotional emails as MARKETING
and they are filtered out before saving or alerting. This replaces
Gmail label-based filtering for more accurate classification.

Also: enable Fargate listener (desiredCount=1), update README for CDK,
update Notion AWS Architecture Map and Slack Apps Inventory.
2026-04-30 19:30:16 -04:00
bin Migrate from SAM to CDK per Sea Haven conventions 2026-04-30 19:23:52 -04:00
lib Add AI-driven marketing filter, activate Fargate listener, update docs 2026-04-30 19:30:16 -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 Add AI-driven marketing filter, activate Fargate listener, update docs 2026-04-30 19:30:16 -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 AI-driven marketing filter, activate Fargate listener, update docs 2026-04-30 19:30:16 -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 via a dedicated Slack app.

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
Fargate (Socket Mode) → Slack listener → two-way conversation with Adam

Stack: CDK (TypeScript), stack name exec-aide, region us-east-1

Services

  • exec-aide-fetch-classify (Lambda): Polls Gmail via History API every 15 minutes, classifies each new message via Bedrock Haiku, filters out marketing, sends immediate Slack DM for HIGH priority, tracks thread state for unanswered detection.
  • exec-aide-daily-digest (Lambda): Runs weekdays at 5 PM ET (DST-aware). Summarizes high-priority items, bypassed work orders, and unanswered threads older than 24h.
  • exec-aide-listener (Fargate): Socket Mode Slack bot for two-way conversation. Runs in a dedicated VPC (10.30.0.0/16) on ARM64.
  • DynamoDB exec-aide: Single-table design (MSG#, THD#, META# prefixes). GSI by-date for daily digest queries. 90-day TTL.

CDK Constructs

  • lib/constructs/email-pipeline.ts — DynamoDB table, both Lambda functions, EventBridge schedules
  • lib/constructs/socket-mode.ts — VPC, ECS cluster, Fargate service, ECR repo (image built automatically via ContainerImage.fromAsset())

Classification Rules

Category Trigger
HIGH VIP sender, urgency keywords, escalation language, financial/legal matters
NORMAL Standard business correspondence
LOW FYI-only, calendar confirmations, informational notifications
MARKETING Newsletters, promotions, bulk mailings, cold outreach (filtered out)
Bypassed WO Email to Adam without work-orders@ in TO/CC
Unanswered Thread where Adam hasn't replied in 24h+

Prerequisites

  • AWS CDK CLI (npm install -g aws-cdk)
  • Node.js 18+, Python 3.12
  • Docker (for Lambda bundling and Fargate image builds)
  • Gmail API enabled in Google Cloud Console (project: exec-aide)
  • Slack app "Exec Aide" with Socket Mode enabled

One-Time Setup

1. Gmail OAuth

pip install google-auth-oauthlib
python scripts/get_gmail_token.py --client-secrets-file path/to/client_secret.json
# Authorize as adam@seahavenind.com, copy output to Secrets Manager

2. Secrets Manager

Secret Contents
exec-aide/gmail-oauth { client_id, client_secret, refresh_token, access_token, token_expiry }
exec-aide/slack-credentials { botToken, signingSecret, appToken }

3. SSM Parameters

Parameter Value
/exec-aide/adam-email adam@seahavenind.com
/exec-aide/adam-slack-user-id Slack user ID
/exec-aide/vip-senders JSON array of email addresses
/exec-aide/vip-domains JSON array of domains
/exec-aide/work-order-addresses ["work-orders@seahavenind.com","work-orders@seahaven.com"]
/exec-aide/unanswered-threshold-hours 24

Deploy

npm install
cdk deploy

Manual Testing

aws lambda invoke --function-name exec-aide-fetch-classify /dev/stdout
aws lambda invoke --function-name exec-aide-daily-digest /dev/stdout

Updating VIP List

Edit the SSM parameters — changes take effect on the next Lambda cold start:

aws ssm put-parameter --name /exec-aide/vip-senders --value '["new@example.com"]' --type String --overwrite