# Email Pipeline + Edita PA — Runbook

# Email Pipeline + Edita PA — Runbook

**MC:** #8521 | **Related:** #8466 (OWN classifier fix) | **Date:** 2026-04-20

---

## 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 wrapper `email-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:

1. **Exact match:** `OWN_ADDRESSES` array (hardcoded machine addresses)
2. **Prefix + domain:** Any prefix in `OWN_SYSTEM_PREFIXES` on domains in `OWN_SYSTEM_DOMAINS`

**Critical:** `alem@alai.no` is NEVER in this list. VIP check runs FIRST (line 464), bypassing OWN classifier entirely.

---

## TLDR\_SKIP Routing

Newsletters from `dan@tldrnewsletter.com` do NOT create MC tasks. They are handled exclusively by `tldr-briefing.js` daemon.

```
// line 126
const TLDR_SENDER = 'dan@tldrnewsletter.com';

// 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):

1. **VIP:** CEO/family → bypass ALL filters, force ACTION/high, skip Ollama
2. **TLDR\_SKIP:** Newsletter → skip MC INTAKE, route to tldr-briefing.js
3. **OWN:** System emails → archive, no task
4. **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 (alem@alai.no, CEO family)
- TLDR\_SKIP routing
- OWN system emails (noreply@alai.no, sentinel@basicconsulting.no)
- 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.js` in-memory DLQ (logged only, no persistence)

---

*Generated by Skillforge | ALAI, 2026*