howl/README.md
lorentz 3bfda9e585 Initial commit: Howl M365 email management daemon
Full implementation of the Howl email triage system:
- Microsoft Graph API integration with MSAL auth (client-credentials and delegated modes)
- Claude LLM classification via tool use for structured output
- PostgreSQL database with customers, vendors, whitelist, and email_log tables
- Alembic migration for full schema
- APScheduler daemon with graceful shutdown
- Typer CLI (run, dry-run, status commands)
- Business rule classifier with overrides (whitelist protection, low-confidence fallback)
- Action executor (move to folders, flag, escalate with webhook)
- 35 passing unit tests
- README, SETUP, and NEXT_STEPS documentation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 16:02:24 -04:00

125 lines
4.4 KiB
Markdown

# Howl
An M365 email management daemon that uses the Microsoft Graph API and Claude AI to automatically classify and route incoming email based on your customer, vendor, and whitelist database.
## How it works
```
Inbox (M365)
Graph API polls for unread mail
PostgreSQL lookup — is the sender a customer, vendor, or trusted contact?
Claude (LLM) classifies the email using sender context + body content
Business rules applied (whitelist always wins, low-confidence → hold for review)
Action taken: move to folder / flag / escalate with notification
email_log table records every decision for audit and retry
```
## Features
- Supports both **shared mailboxes** (app-only, no user login) and **personal mailboxes** (delegated device-code auth)
- **No emails are ever deleted** — only moved, flagged, or escalated
- **Dry-run mode** — analyze and log without touching any email
- **Idempotent** — safe to restart; already-processed messages are skipped
- **Automatic retry** — failed messages are retried on the next poll cycle
- **Full audit log** — every classification, confidence score, and action is stored in PostgreSQL
## Folder routing
| Sender type | LLM classification | Action |
|---|---|---|
| Customer | Inquiry / correspondence | Move to `Customers` folder |
| Vendor | Invoice / notification | Move to `Vendors` folder |
| Whitelist | Trusted contact | Mark read, stay in Inbox |
| Any | Urgent / escalation | Move to `Escalate` + webhook notification |
| Any | Uncertain (low confidence) | Move to `Needs Review` |
| Unknown | Spam / newsletter | Move to `Junk Email` |
## Quick start
```bash
# 1. Create and activate a virtual environment
python3 -m venv .venv && source .venv/bin/activate
# 2. Install dependencies
pip install -e ".[dev]"
# 3. Configure environment
cp .env.example .env
# Edit .env with your Azure, Anthropic, and PostgreSQL credentials
# 4. Run database migrations
alembic upgrade head
# 5. Test with dry-run (no email mutations)
howl dry-run --limit 10
# 6. Start the daemon
howl run
```
## CLI commands
| Command | Description |
|---|---|
| `howl run` | Start the daemon (blocking, polls on schedule) |
| `howl dry-run [--limit N]` | Classify up to N emails, log results, take no action |
| `howl status [--limit N]` | Display recent email_log entries in a table |
## Project structure
```
howl/
├── howl/
│ ├── config.py # All configuration (pydantic-settings + .env)
│ ├── main.py # CLI entry point (Typer)
│ ├── logging_config.py # structlog setup (JSON or text)
│ ├── db/
│ │ ├── engine.py # Async SQLAlchemy engine
│ │ ├── models.py # ORM models
│ │ └── queries.py # lookup_sender(), email log helpers
│ ├── graph/
│ │ ├── auth.py # MSAL token provider (client-credentials or delegated)
│ │ └── client.py # Graph API: list, read, move, flag messages
│ ├── llm/
│ │ ├── client.py # Anthropic SDK wrapper with retry
│ │ ├── prompts.py # Prompt builder (system prompt + per-email user turn)
│ │ └── schemas.py # EmailClassification model + tool definition
│ ├── pipeline/
│ │ ├── processor.py # EmailProcessor — orchestrates the full pipeline
│ │ ├── classifier.py # Business rule overrides on LLM output
│ │ └── actions.py # ActionExecutor — Graph mutations + webhook
│ └── daemon/
│ └── scheduler.py # APScheduler poll loop + graceful shutdown
├── migrations/ # Alembic database migrations
├── tests/ # Unit and integration tests
├── .env.example # Configuration template
├── SETUP.md # Detailed setup and configuration guide
└── NEXT_STEPS.md # Roadmap and future improvements
```
## Running tests
```bash
pytest tests/ -q # All tests (no external services needed)
pytest tests/ -q -m "not integration" # Unit tests only (default)
pytest tests/ -q -m integration # Requires real M365 + Anthropic credentials
```
## Requirements
- Python 3.11+
- PostgreSQL 14+
- Microsoft Azure app registration with `Mail.Read` + `Mail.ReadWrite` permissions
- Anthropic API key