Skip to main content

Email-Reactor — Strategic-Inbox Auto-Triage Daemon

Email-Reactor — Strategic-Inbox Auto-Triage Daemon

Why It Exists

Incident: 2026-05-26 — CEO had to phone Asmir Merdžanović to learn that Asmir sent critical SEO partnership email three days earlier (email #8421, dated 2026-05-24). This email sat in the database with status 'new' for 72+ hours while we continued building the exact SEO automation partnership Asmir was offering.

"Niko ne cita i reaguje na mailove. Ovo smo probali vec 4 mjeseca da odradimo. Ako ne uspijemo mozemo zatvorit firmu."
— CEO Alem Basic, 2026-05-26, after discovering the Asmir email gap

Previous email systems (email-agent, email-briefing, inbox-queue) classified and queued but no human acted on them. Email-Reactor solves this by implementing a 3-step security-first pipeline that creates Mission Control tasks with macOS push notifications for revenue-critical emails automatically.

What It Does

Email-Reactor is a daemon that polls ~/system/databases/email-inbox.db every 5 minutes (via LaunchAgent no.alai.inbox-watcher) and processes every new email through a 3-step pipeline:

  1. SECURITY SCAN (always first) — rule-based phishing/macro/spoof detection → quarantine on fail
  2. KNOWN-CONTACT CHECK — parallel lookup in Paperless archive.alai.no correspondents + DB email history → if KNOWN, create MC task + push notification
  3. LLM REVENUE CLASSIFIER (unknown senders only) — Gemma-4 26B asks "Is this revenue-relevant?" → YES = MC task + push, NO = queue silently

Strategic override: VIP senders in ~/system/config/strategic-partners.json skip all steps and go straight to MC + push (tier-1 phone-grade urgency).

Architecture

flowchart LR
    A[Email arrives in DB] --> B{Strategic Partner?}
    B -- YES --> Z[Create MC + Push]
    B -- NO --> C[STEP 1: Security Scan]
    C -- FAIL --> Q[Quarantine + Alert]
    C -- PASS --> D{STEP 2: Known Contact?}
    D -- YES
Paperless/DB --> Z D -- NO --> E{Newsletter/Transactional?} E -- YES --> N[No MC — Audit as llm_no] E -- NO --> F[STEP 3: LLM Classifier] F -- YES --> Z F -- NO --> N Q --> X[STOP] N --> X Z --> X[Done]

Components

Component Path Purpose
Watcher daemon ~/system/tools/inbox-watcher.js 738-line Node.js script, runs every 5 min
LaunchAgent ~/Library/LaunchAgents/no.alai.inbox-watcher.plist Schedules daemon (StartInterval=300s)
Email DB ~/system/databases/email-inbox.db SQLite, emails table, mc_task_id linkage
Strategic allowlist ~/system/config/strategic-partners.json VIP senders (tier-1 = phone-grade), hot-reloaded
Audit log ~/system/state/inbox-watcher-audit.log JSONL, every action: linked/llm_yes/llm_no/quarantine
Quarantine log ~/system/state/inbox-watcher-quarantine.jsonl Security failures, phishing attempts
Ops watchdog ~/system/config/ops-watchdog.json Lists no.alai.inbox-watcher in critical_services
Mission Control ~/system/tools/mc.js Task creation, dedup detection, linkage

Routing Logic Detail

Step 1: Security Scan

Rule-based checks (no LLM cost):

  • Phishing keywords: "urgent password", "verify account", "bitcoin transfer", "lottery winner", "tax refund"
  • Suspicious URLs: unencrypted (http://), TLDs (.tk, .ml, .ga, .cf)
  • Macro attachment hints: .docm, .xlsm, .scr, .exe, .lnk, .msi
  • Domain spoofing: sender name claims "PayPal" but email is @gmail.com

On failure: email goes to inbox-watcher-quarantine.jsonl, audit log records security_quarantine, processing STOPS (no MC, no push).

Step 2: Known-Contact Check

Parallel signals (first match wins):

  1. Strategic override: email matches strategic-partners.json (Asmir, SnowIT, paying clients) → immediate MC + push
  2. Paperless Correspondents: HTTPS GET to https://archive.alai.no/api/correspondents/ with Bitwarden token + Cloudflare Access headers, searches by domain + sender name → if found, contact is KNOWN
  3. DB email history: SQL query SELECT COUNT(*) FROM emails WHERE to_addr LIKE '%sender%' AND classification='OWN' → if we ever emailed this person, they're KNOWN

If KNOWN via any signal: create MC task, fire macOS push notification, audit log records source (override/paperless/db).

Step 3: LLM Revenue Classifier (unknown senders only)

Pre-filter heuristic (saves LLM tokens): detect obvious newsletters/transactional via regex patterns:

  • Transactional senders: no-reply@, noreply@, notification@, alert@, billing@, invoice@, receipt@, kontakt@fiken, support@stripe
  • Newsletter senders: newsletter@, digest@, news@, marketing@, promo@, tldr, naeringsliv, mail-list
  • Digest subject lines: "This week in", "Your weekly digest", "Daily digest", "Unsubscribe here", "View in browser", "Automated notification"

If heuristic matches: audit as llm_no with reason newsletter_heuristic or transactional_heuristic, no MC, STOP.

LLM call (if heuristic passes):

  • Endpoint: http://10.0.0.2:11435/v1/chat/completions (Ollama FORGE, Gemma-4 26B)
  • Timeout: 15 seconds
  • Prompt: "Is this a business opportunity, paying client request, partner inquiry, invoice, contract, or revenue-relevant? Answer YES or NO."
  • Temperature: 0.3 (0.1 on retry)
  • Response parsing: strict regex ^YES$|^NO$ — malformed = retry once with stricter prompt
  • Default on error/timeout: NO (conservative fail-safe — real opportunities arrive via KNOWN-CONTACT path)

YES → create MC task + push + audit llm_yes
NO → audit llm_no, no MC

How to Add a Strategic Partner

  1. Edit ~/system/config/strategic-partners.json
  2. Add new entry to senders array:
{
  "email": "[email protected]",
  "name": "Partner Name",
  "tier": 1,
  "reason": "Business reason — e.g., paying client, key integration partner"
}
  1. Save file
  2. No daemon reload needed — file is loaded fresh on every 5-min cycle

Audit Log Codes

Action Meaning MC Created?
linked Known contact, MC task created (first time) ✅ YES
relinked_via_dedup Duplicate MC task found, linked to existing (no new push) ❌ NO (existing)
security_quarantine Failed security scan (phishing/macro/spoof) ❌ NO
llm_yes LLM classified as revenue-relevant ✅ YES
llm_no LLM classified as NOT revenue-relevant (or heuristic match) ❌ NO
newsletter_heuristic Pre-LLM heuristic detected newsletter/digest ❌ NO
transactional_heuristic Pre-LLM heuristic detected automated notification/billing ❌ NO
dry_run --dry-run mode, would have created MC ❌ NO (test mode)
create_failed mc.js add command failed ❌ NO (error)
update_failed DB update (mc_task_id linkage) failed ⚠️ YES (orphaned)

Debug Runbook

Query Audit Log

# Last 50 actions
tail -50 ~/system/state/inbox-watcher-audit.log | jq .

# Count actions by type (last 24h)
grep "$(date -u +%Y-%m-%d)" ~/system/state/inbox-watcher-audit.log | \
  jq -r .action | sort | uniq -c | sort -rn

# Find specific email
grep '"email_id":8421' ~/system/state/inbox-watcher-audit.log | jq .

Query Quarantine Log

# Show all quarantined emails
cat ~/system/state/inbox-watcher-quarantine.jsonl | jq .

# Count by reason
cat ~/system/state/inbox-watcher-quarantine.jsonl | jq -r .reason | sort | uniq -c

Manual Trigger (Dry-Run)

node ~/system/tools/inbox-watcher.js --dry-run

Shows what would happen without creating tasks or updating DB.

Manual Trigger (Live)

node ~/system/tools/inbox-watcher.js

Check Daemon Status

launchctl list | grep inbox-watcher

Expected output: no.alai.inbox-watcher with recent PID.

Restart Daemon

launchctl unload ~/Library/LaunchAgents/no.alai.inbox-watcher.plist
launchctl load ~/Library/LaunchAgents/no.alai.inbox-watcher.plist

Tail Daemon Logs

tail -f ~/system/logs/inbox-watcher.out.log
tail -f ~/system/logs/inbox-watcher.err.log

Check Email DB for Pending

sqlite3 ~/system/databases/email-inbox.db <<EOF
SELECT id, from_addr, subject, status, created_at
FROM emails
WHERE mc_task_id IS NULL
  AND status = 'new'
  AND created_at > datetime('now', '-7 days')
ORDER BY created_at DESC
LIMIT 20;
EOF

Failure Modes & Alerts

Failure Symptom Alert Mechanism Recovery
Daemon crash launchctl list shows no PID ops-watchdog auto-restart (critical_services) Auto (watchdog), or manual reload plist
Paperless 401 Log shows "HTTP 401" WARN in out.log, no Slack (non-blocking) Refresh Bitwarden /tmp/bw-session token
Ollama FORGE down LLM timeout 15s Log WARN, defaults to NO (safe) SSH to FORGE, restart Ollama service
MC duplicate flood Many relinked_via_dedup in audit None (expected behavior) Normal — dedup prevents task spam
DB locked SQLite BUSY error ERROR in err.log Wait 5min (next cycle), or restart daemon
Strategic override miss VIP email not getting MC CEO notices delay Verify strategic-partners.json email exact match (case-insensitive)

Known Limitations

  1. LLM is safety net, not primary path. Real opportunities should arrive via KNOWN-CONTACT (Paperless correspondents + DB history). LLM classifier is conservative: defaults to NO on error to avoid false-positive task spam. If a genuine new opportunity is missed by LLM, it will appear in email DB and CEO can manually promote to MC.
  2. Paperless lookup is best-effort. If Bitwarden token expires or Cloudflare Access headers are missing, Paperless signal fails silently and daemon falls back to DB-history-only KNOWN check. This is by design (non-blocking).
  3. Default NO on malformed LLM response. Policy changed 2026-05-26 after 6 false positives from verbose LLM responses. Strict regex parsing + retry ensures only clean YES/NO answers create tasks. This may miss 1 real opportunity but prevents 6 noise tasks.
  4. No auto-reply generation. Out of scope for Phase 2. Email-Reactor creates MC tasks; human writes replies.
  5. 30-day recency filter. Only processes emails from last 30 days to avoid re-scanning old newsletter backlog every 5-min cycle. Older emails must be manually triaged.
  6. Single-account scope. Currently queries all accounts in email-inbox.db, but strategic-partners.json does not differentiate by account. Future: add account-specific allowlists if needed.

References

  • MC #102077 — Phase 1 (whitelist model, paused after CEO feedback)
  • MC #102113 — Phase 2 (3-step pipeline, current implementation)
  • Incident email: #8421 (Asmir Merdžanović, 2026-05-24)
  • Peer review: /tmp/alai/p2p-pairing-evidence/mesh-thr-102113-peer-ask.md

Authored by: Skillforge (ALAI knowledge management)
Document type: Runbook + Architecture
Audience: Future John during 3am incident
Last updated: 2026-05-26