Show HN: Auto-triage customer emails to Linear with Claude and pydantic-AI A developer released an open-source FastAPI webhook service that uses Claude AI and pydantic-AI to automatically triage customer emails into prioritized Linear issues, extracting priority, customer info, and issue type from raw email content and sending Slack alerts for urgent items. Automatically convert incoming emails into prioritized Linear issues using AI-powered triage. Extract customer information, priority levels, and issue types from raw email content, then instantly create structured tickets in your Linear workspace with Slack notifications for urgent items. This template provides a production-ready FastAPI webhook service that: - Accepts emails via SMTP forwarding or Gmail API integration - Extracts priority, customer, and issue classification using Claude AI - Creates Linear issues with rich metadata and proper linking - Sends Slack alerts for high-priority tickets - Stores triage decisions for audit and refinement Why use this? Cost savings: Eliminates $20-40/mo Zapier fees + manual triage overhead Speed: 30-second email-to-ticket pipeline vs. 5-minute manual routing Consistency: AI-driven classification reduces human error in priority assignment Extensibility: Built on Pydantic AI for easy customization of triage logic - Accepts raw email POST payloads SMTP webhook format or parsed JSON - Extracts sender, subject, body, and attachment metadata - Supports both plain text and HTML email bodies Uses Claude to extract from email content: Priority level urgent/high/normal/low Customer identifier email domain, name, account ID Issue type bug/feature-request/support/billing Summary auto-generated from subject + body context Suggested assignee based on issue type patterns, optional - Creates issues in your Linear workspace - Attaches original email as issue comment - Sets priority and status based on triage output - Links to customer/team projects configurable - Supports custom fields for email metadata - Posts urgent/high-priority tickets to designated channel - Includes customer info, issue link, and priority badge - Optional thread replies for follow-up updates - Stores all triage decisions in SQLite or configured DB - Enables performance monitoring and model refinement - Supports manual override and feedback loops Python 3.11+ Linear API token create in Settings API Personal API Keys https://linear.app/settings/api Claude API key from Anthropic Console https://console.anthropic.com/ Slack webhook URL optional, from Slack Apps https://api.slack.com/apps Gmail API credentials or SMTP relay service optional, for email ingestion - Docker + Docker Compose for containerized deployment - PostgreSQL for production database, defaults to SQLite git clone https://github.com/yourusername/email-linear-triage.git cd email-linear-triage python -m venv venv source venv/bin/activate On Windows: venv\Scripts\activate pip install -r requirements.txt Create .env in the project root: API Keys ANTHROPIC API KEY=sk-ant-... LINEAR API KEY=lin api ... SLACK WEBHOOK URL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL Optional Linear Configuration LINEAR TEAM ID=acme Your Linear team slug e.g., 'acme' from linear.app/acme LINEAR PROJECT ID=INB Project key for incoming emails default: 'INB' LINEAR DEFAULT STATUS=backlog Initial status for new issues Email Configuration SMTP SECRET TOKEN=your-secret-token-here For webhook authentication EMAIL DOMAIN=yourdomain.com Database optional DATABASE URL=sqlite:///./triage.db Or: postgresql://user:pass@localhost/triage Feature Flags ENABLE SLACK NOTIFICATIONS=true ENABLE AUTO ASSIGN=false TRIAGE MODEL=claude-3-5-sonnet-20241022 Claude model to use python -m alembic upgrade head Or for SQLite auto-created : python python -c "from app.db import init db; init db " uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload Server runs on http://localhost:8000 Option A: SMTP Forwarding Recommended - In your email provider, set up a forward rule: From: tickets@yourdomain.com To: {your-server}/webhook/email with authentication Option B: Gmail API - Enable Gmail API https://developers.google.com/gmail/api/quickstart/python in Google Cloud Console - Download credentials JSON to ./credentials.json - App auto-fetches labeled emails periodically Option C: Manual Testing curl -X POST http://localhost:8000/webhook/email \ -H "X-Webhook-Token: your-secret-token-here" \ -H "Content-Type: application/json" \ -d '{ "from": "customer@example.com", "subject": "Payment processing is broken", "body": "Hi, our recurring invoices havent charged for 2 days. This is urgent ", "timestamp": "2024-01-15T14:30:00Z" }' In Linear Settings Integrations Webhooks, add: URL: {your-server}/webhook/linear-event Events: Issue created, issue updated- Useful for closing issues via email replies Email arrives at tickets@yourdomain.com forwarded via SMTP Webhook handler receives POST, validates token Claude triage classifies email 2-5 seconds Linear issue created with extracted metadata Slack notification posted if urgent/high Response returned with issue URL curl -X POST http://localhost:8000/webhook/email \ -H "X-Webhook-Token: your-secret-token-here" \ -H "Content-Type: application/json" \ -d '{ "from": "sarah@acmecorp.com", "subject": " BUG Dashboard crashes on mobile", "body": "When I open the dashboard on iPhone, it instantly crashes. Happens every time. Our team cant work.", "timestamp": "2024-01-15T09:30:00Z" }' Response 201 Created : { "status": "success", "linear issue id": "INB-234", "linear issue url": "https://linear.app/acme/issue/INB-234", "triage result": { "priority": "urgent", "issue type": "bug", "customer domain": "acmecorp.com", "summary": "Dashboard mobile app crashes on iOS", "suggested assignee": "eng-mobile" }, "slack notification sent": true, "processing time ms": 3200 } Ingest raw email and create Linear issue Headers: X-Webhook-Token: {SMTP SECRET TOKEN} Content-Type: application/json Request Body: { "from": "customer@example.com", "subject": "Issue title", "body": "Email body text", "html body": "