2026-04-30 17:40:58 -04:00
# Exec Aide
2026-04-30 19:30:16 -04:00
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.
2026-04-30 17:40:58 -04:00
## 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
2026-04-30 19:30:16 -04:00
Fargate (Socket Mode) → Slack listener → two-way conversation with Adam
2026-04-30 17:40:58 -04:00
```
2026-04-30 19:30:16 -04:00
**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()` )
2026-04-30 17:40:58 -04:00
## Classification Rules
| Category | Trigger |
|---|---|
| **HIGH** | VIP sender, urgency keywords, escalation language, financial/legal matters |
| **NORMAL** | Standard business correspondence |
2026-04-30 19:30:16 -04:00
| **LOW** | FYI-only, calendar confirmations, informational notifications |
| **MARKETING** | Newsletters, promotions, bulk mailings, cold outreach (filtered out) |
2026-04-30 17:40:58 -04:00
| **Bypassed WO** | Email to Adam without work-orders@ in TO/CC |
| **Unanswered** | Thread where Adam hasn't replied in 24h+ |
## Prerequisites
2026-04-30 19:30:16 -04:00
- 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
2026-04-30 17:40:58 -04:00
## One-Time Setup
### 1. Gmail OAuth
```bash
pip install google-auth-oauthlib
python scripts/get_gmail_token.py --client-secrets-file path/to/client_secret.json
2026-04-30 19:30:16 -04:00
# Authorize as adam@seahavenind.com, copy output to Secrets Manager
2026-04-30 17:40:58 -04:00
```
### 2. Secrets Manager
2026-04-30 19:30:16 -04:00
| Secret | Contents |
|---|---|
| `exec-aide/gmail-oauth` | `{ client_id, client_secret, refresh_token, access_token, token_expiry }` |
| `exec-aide/slack-credentials` | `{ botToken, signingSecret, appToken }` |
2026-04-30 17:40:58 -04:00
### 3. SSM Parameters
2026-04-30 19:30:16 -04:00
| 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` |
2026-04-30 17:40:58 -04:00
## Deploy
```bash
2026-04-30 19:30:16 -04:00
npm install
cdk deploy
2026-04-30 17:40:58 -04:00
```
## Manual Testing
```bash
aws lambda invoke --function-name exec-aide-fetch-classify /dev/stdout
aws lambda invoke --function-name exec-aide-daily-digest /dev/stdout
```
2026-04-30 19:30:16 -04:00
## Updating VIP List
2026-04-30 17:40:58 -04:00
2026-04-30 19:30:16 -04:00
Edit the SSM parameters — changes take effect on the next Lambda cold start:
2026-04-30 17:40:58 -04:00
```bash
aws ssm put-parameter --name /exec-aide/vip-senders --value '["new@example .com"]' --type String --overwrite
```