Email Pipeline + Edita PA — Runbook
Email Pipeline + Edita PA — Runbook
Overview
The email pipeline classifies incoming emails and routes them to Mission Control, HiveMind, or archive. Edita PA is the autonomous email assistant operating in phased rollout (currently Phase 1).
Architecture
- Daemon:
~/system/daemons/email-agent.js - LaunchAgent:
com.john.email-agent(via wrapperemail-agent-wrapper.sh) - Vault: Bitwarden session (
/tmp/bw-session) required for IMAP credentials - Triage LLM: llama3.1:8b (Ollama ANVIL, preloaded via
ollama-triage-preload.sh)
OWN Classifier Logic
The OWN classifier identifies machine-generated emails from ALAI's own systems to prevent task spam.
Constants (email-agent.js lines 118-123)
const OWN_SYSTEM_PREFIXES = [
'noreply@', 'no-reply@', 'sentinel@', 'alerts@', 'auto@', 'daemon@',
'mailer@', 'notification@', 'notifications@', 'bounces@', 'bounce@',
'donotreply@', 'do-not-reply@', 'system@'
];
const OWN_SYSTEM_DOMAINS = ['@alai.no', '@basicconsulting.no'];
isOwnSystemEmail() Function (lines 446-456)
Two-tier check:
- Exact match:
OWN_ADDRESSESarray (hardcoded machine addresses) - Prefix + domain: Any prefix in
OWN_SYSTEM_PREFIXESon domains inOWN_SYSTEM_DOMAINS
Critical: [email protected] is NEVER in this list. VIP check runs FIRST (line 464), bypassing OWN classifier entirely.
TLDR_SKIP Routing
// line 126
const TLDR_SENDER = '[email protected]';
// line 474
if (lowerFrom.includes(TLDR_SENDER)) {
return { category: 'TLDR_SKIP', priority: 'low', summary: 'TLDR newsletter — handled by tldr-briefing.js', action: '' };
}
VIP Ordering
Classification priority (lines 464-481):
- VIP: CEO/family → bypass ALL filters, force ACTION/high, skip Ollama
- TLDR_SKIP: Newsletter → skip MC INTAKE, route to tldr-briefing.js
- OWN: System emails → archive, no task
- Other: Spam allowlist check → Ollama classification
Edita PA Phases
Phase 0: --dry-run (Log-Only)
Classification + logging only. No archive, no escalate, no respond.
node ~/system/daemons/email-agent.js --dry-run
Phase 1: --allow-archive (CURRENT)
Archive low-priority emails only. Escalate and respond actions are held (logged but not executed).
node ~/system/daemons/email-agent.js --allow-archive
Plist config: com.john.email-agent calls email-agent-wrapper.sh, which passes no flags → defaults to Phase 1 (archive-only mode is internal default in daemon code).
Phase 2: Full Live (NOT YET APPROVED)
Archive + escalate + respond. Requires CEO explicit approval.
node ~/system/daemons/email-agent.js --allow-all
Unit Testing
Test classifier without IMAP/Vault dependencies:
node ~/system/daemons/test-email-classifier.js
Scenarios (16 total):
- VIP bypass ([email protected], CEO family)
- TLDR_SKIP routing
- OWN system emails ([email protected], [email protected])
- Spam patterns with allowlist exceptions (GitHub, Cloudflare, Anthropic)
Rollback
Revert to dry-run mode:
launchctl unload ~/Library/LaunchAgents/com.john.email-agent.plist
# Edit wrapper to add --dry-run flag
echo 'exec /opt/homebrew/bin/node "$HOME/system/daemons/email-agent.js" --dry-run' >> ~/system/tools/email-agent-wrapper.sh
launchctl load ~/Library/LaunchAgents/com.john.email-agent.plist
Monitoring
- Logs:
~/system/logs/email-agent-launchd.log - Errors:
~/system/logs/email-agent-launchd-error.log - MC tasks:
node ~/system/tools/mc.js list --owner edita - DLQ: Failed vault sessions stored in
email-agent.jsin-memory DLQ (logged only, no persistence)
Generated by Skillforge | ALAI, 2026
Contact Form Handlers
This section documents all contact forms across ALAI properties and their email delivery mechanisms.
alai.no Contact Form
- Frontend:
https://alai.no/contact(Cloudflare Pages) - Handler: CF Pages Function
/functions/contact.js - Endpoint:
POST https://alai.no/api/contact - Email provider: Resend API
- Recipient:
[email protected] - Credentials: Bitwarden item "Resend API Key" → CF Pages env var
RESEND_API_KEY - Status: LIVE (deployed 2026-04-21, MC #8587)
Test procedure:
curl -X POST https://alai.no/api/contact \
-H "Content-Type: application/json" \
-d '{"name": "Test User", "email": "[email protected]", "message": "E2E test 2026-04-21 14:00"}'
# Verify inbox:
himalaya search --account info-alai --folder INBOX "subject:Contact Form"
snowit.ba Contact Form
- Frontend:
https://snowit.ba/contact - Handler: BROKEN — Vercel API route not migrated to CF Pages (MC #8591)
- Endpoint:
POST https://api.basicconsulting.no/contact(hijacked by documenso-webhook, returns false success) - Recipient:
[email protected](LumisCare side, not ALAI-managed) - Status: BROKEN — awaiting CodeCraft fix
getdrop.no Waitlist
- Frontend:
https://getdrop.no(Cloudflare Pages) - Handler: CF Pages Function
/functions/waitlist.js - Endpoint:
POST https://getdrop.no/api/waitlist - Storage: Cloudflare D1 database
drop-waitlist - Email provider: None (DB-only storage, no email sent)
- Status: LIVE
Test procedure:
wrangler d1 execute drop-waitlist --command "SELECT * FROM submissions ORDER BY created_at DESC LIMIT 5"
merdzanovic.ba Contact Form
- Status: UNKNOWN — needs audit (likely same risk as snowit.ba)
- MC Task: #8593 (audit all ALAI-managed contact forms)
Form Handler Migration Checklist
When migrating sites from Vercel/Netlify to Cloudflare Pages:
- Inventory: Identify all POST endpoints (forms, webhooks, API routes)
- Port handlers: Rewrite Vercel API routes as CF Pages Functions (
/functions/*.js) - Environment variables: Copy SMTP/API credentials to CF Pages env vars
- Update form actions: Change form targets to new CF Pages routes (e.g.,
/api/contact) - E2E test: Follow Forms E2E Testing Protocol (HTTP + inbox check MANDATORY)
- Monitor: Check inbox/DB for 24 hours post-migration to catch silent failures
Reference incident: 2026-04-21 alai.no Contact Form Failure
Himalaya IMAP Setup (for Form Testing)
Himalaya CLI provides rapid inbox verification without browser login.
Install
brew install himalaya
Configure Account
Add to ~/.config/himalaya/config.toml:
[accounts.info-alai]
default = false
email = "[email protected]"
display-name = "ALAI Info"
[accounts.info-alai.imap]
host = "imap.one.com"
port = 993
encryption = "tls"
login = "[email protected]"
passwd.cmd = "bw get password 'Email - [email protected]' --session $(cat /tmp/bw-session)"
[accounts.info-alai.smtp]
host = "send.one.com"
port = 587
encryption = "start-tls"
login = "[email protected]"
passwd.cmd = "bw get password 'Email - [email protected]' --session $(cat /tmp/bw-session)"
Usage
# Unlock Bitwarden first
bw unlock --raw > /tmp/bw-session
# List recent messages
himalaya list --account info-alai --folder INBOX --page-size 20
# Search for form submissions
himalaya search --account info-alai --folder INBOX "from:[email protected]"
# Search by date range
himalaya search --account info-alai --folder INBOX "since:2026-04-21"
Credentials: Bitwarden item "Email - [email protected]"
Updated: 2026-04-21 | Skillforge