[TERMINAL · SKILLS]
> mounting /skills...
> indexing 295 manifests...
> linking agents: claude · codex · gemini · cursor
> ready.
[░░░░░░░░░░░░░░░░░░░░░░░░░░░░] 0%
Terminal.skills
Use Cases/Build a Smart Email Routing and Auto-Response System

Build a Smart Email Routing and Auto-Response System

Route inbound emails to the right team with AI classification, auto-draft responses for common queries, and track SLA compliance — cutting email response time from 12 hours to 45 minutes.

#redis#caching#database#pub-sub#queues
Works with:claude-codeopenai-codexgemini-clicursor

Skills stack · 7 skills

Avg quality 93/100·All SAFE
>

typescript

v

Not yet scored
View skill
>

vercel-ai-sdk

v

Not yet scored
View skill
>

redis

v1.0.0

Build applications with Redis — caching, session storage, pub/sub, streams, rate limiting, leaderboards, and queues. Use when tasks involve in-memory data storage, real-time messaging, distributed locking, or performance optimization with caching layers.

93/100 quality
1.81× impact
SAFE
View skill
>

postgresql

v1.0.0

Assists with designing schemas, writing performant queries, managing indexes, and operating PostgreSQL databases. Use when working with JSONB, full-text search, window functions, CTEs, row-level security, replication, or performance tuning. Trigger words: postgresql, postgres, sql, database, jsonb, rls, window functions, cte.

87/100 quality
1.53× impact
SAFE
View skill
>

bull-mq

v1.0.0

You are an expert in BullMQ, the high-performance job queue for Node.js built on Redis. You help developers build reliable background processing systems with delayed jobs, rate limiting, prioritization, repeatable cron jobs, job dependencies, concurrency control, and dead-letter handling — powering email sending, image processing, webhook delivery, report generation, and any async workload.

93/100 quality
3.00× impact
SAFE
View skill
>

zod

v1.0.0

You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.

100/100 quality
1.21× impact
SAFE
View skill
>

hono

v1.0.0

You are an expert in Hono, the ultrafast web framework for the edge. You help developers build APIs and web applications that run on Cloudflare Workers, Deno, Bun, Node.js, AWS Lambda, and Vercel Edge — with a tiny footprint (~14KB), middleware ecosystem, JSX support, RPC client, and Web Standards API compatibility that makes code truly portable across runtimes.

93/100 quality
3.00× impact
SAFE
View skill
$

The Problem

A B2B company receives 500 emails/day to support@, sales@, and info@. Emails land in shared inboxes where 5 people manually read, classify, and forward them. Average first-response time: 12 hours. 20% of emails get lost — nobody responds. Sales leads sit in support@ for days because nobody realized it was a $50K opportunity. The CEO manually forwards emails when she notices they're in the wrong inbox. The team tried rules-based filtering but 40% of emails don't match any rule.

Step 1: Email Classifier

typescript
// src/email/classifier.ts
import { generateObject } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';

const EmailClassification = z.object({
  category: z.enum([
    'sales_inquiry', 'support_bug', 'support_how_to', 'billing',
    'partnership', 'feedback', 'spam', 'legal', 'press', 'job_application',
  ]),
  priority: z.enum(['urgent', 'high', 'normal', 'low']),
  sentiment: z.enum(['positive', 'neutral', 'frustrated', 'angry']),
  routeTo: z.string(),
  summary: z.string().max(200),
  estimatedDealSize: z.number().optional(), // for sales inquiries
  autoRespondable: z.boolean(),
  language: z.string(),
  suggestedTags: z.array(z.string()),
});

export async function classifyEmail(email: {
  from: string;
  subject: string;
  body: string;
  attachments: string[];
  previousThreads: number;
}): Promise<z.infer<typeof EmailClassification>> {
  const { object } = await generateObject({
    model: openai('gpt-4o-mini'),
    schema: EmailClassification,
    prompt: `Classify this inbound email and determine routing.

From: ${email.from}
Subject: ${email.subject}
Body: ${email.body}
Attachments: ${email.attachments.join(', ') || 'none'}
Previous threads from this sender: ${email.previousThreads}

Routing rules:
- sales_inquiry → sales-team (respond within 2h)
- support_bug → engineering-support (respond within 4h)
- support_how_to → customer-success (respond within 8h)
- billing → finance-team (respond within 4h)
- partnership → business-dev (respond within 24h)
- legal → legal-team (respond within 24h)
- spam → archive (no response)
- press → marketing (respond within 24h)

For sales inquiries, estimate deal size based on context clues (company size, use case).
Mark autoRespondable=true for common how-to questions and billing inquiries.`,
  });

  return object;
}

Step 2: Auto-Response Drafter

typescript
// src/email/auto-responder.ts
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
import { Pool } from 'pg';

const db = new Pool({ connectionString: process.env.DATABASE_URL });

export async function draftResponse(email: {
  from: string;
  subject: string;
  body: string;
  classification: { category: string; summary: string };
}): Promise<{ draft: string; confidence: number; sources: string[] }> {
  // Find relevant knowledge base articles
  const { rows: articles } = await db.query(`
    SELECT title, content, url FROM knowledge_base
    WHERE category = $1
    ORDER BY similarity(content, $2) DESC
    LIMIT 3
  `, [email.classification.category, email.body]);

  const context = articles.map(a => `[${a.title}]: ${a.content.slice(0, 500)}`).join('\n\n');

  const { text } = await generateText({
    model: openai('gpt-4o-mini'),
    prompt: `Draft a professional email response.

Original email:
From: ${email.from}
Subject: ${email.subject}
Body: ${email.body}

Relevant knowledge base articles:
${context}

Rules:
- Professional but warm tone
- Include specific links to docs/articles when relevant
- If unsure about the answer, acknowledge the question and say the team will follow up
- Keep under 200 words
- Sign as "Support Team" (not a specific person)
- Don't promise things you can't guarantee (timelines, features)`,
  });

  return {
    draft: text,
    confidence: articles.length > 0 ? 0.85 : 0.5,
    sources: articles.map(a => a.url),
  };
}

Step 3: SLA Tracker

typescript
// src/email/sla.ts
import { Pool } from 'pg';
import { Redis } from 'ioredis';

const db = new Pool({ connectionString: process.env.DATABASE_URL });
const redis = new Redis(process.env.REDIS_URL!);

const SLA_HOURS: Record<string, number> = {
  sales_inquiry: 2,
  support_bug: 4,
  support_how_to: 8,
  billing: 4,
  partnership: 24,
  legal: 24,
  press: 24,
};

export async function trackSLA(emailId: string, category: string): Promise<void> {
  const slaHours = SLA_HOURS[category] ?? 24;
  const deadline = new Date(Date.now() + slaHours * 3600000);

  await db.query(`
    INSERT INTO email_sla (email_id, category, sla_deadline, status)
    VALUES ($1, $2, $3, 'pending')
  `, [emailId, category, deadline.toISOString()]);

  // Schedule SLA warning at 80% of deadline
  const warningMs = slaHours * 3600000 * 0.8;
  const { Queue } = await import('bullmq');
  const queue = new Queue('sla-alerts', { connection: redis });
  await queue.add('sla-warning', { emailId, category }, { delay: warningMs });
}

export async function getSLADashboard(): Promise<{
  pending: number;
  breached: number;
  respondedInTime: number;
  avgResponseHours: number;
  byCategory: Array<{ category: string; avgHours: number; breachRate: number }>;
}> {
  const { rows: [stats] } = await db.query(`
    SELECT
      COUNT(*) FILTER (WHERE status = 'pending' AND sla_deadline > NOW()) as pending,
      COUNT(*) FILTER (WHERE status = 'pending' AND sla_deadline <= NOW()) as breached,
      COUNT(*) FILTER (WHERE status = 'responded' AND responded_at <= sla_deadline) as in_time,
      AVG(EXTRACT(EPOCH FROM (responded_at - created_at)) / 3600) FILTER (WHERE status = 'responded') as avg_hours
    FROM email_sla
    WHERE created_at > NOW() - INTERVAL '30 days'
  `);

  const { rows: categories } = await db.query(`
    SELECT category,
      AVG(EXTRACT(EPOCH FROM (COALESCE(responded_at, NOW()) - created_at)) / 3600) as avg_hours,
      COUNT(*) FILTER (WHERE status = 'pending' AND sla_deadline <= NOW())::float / NULLIF(COUNT(*), 0) as breach_rate
    FROM email_sla
    WHERE created_at > NOW() - INTERVAL '30 days'
    GROUP BY category
  `);

  return {
    pending: parseInt(stats.pending),
    breached: parseInt(stats.breached),
    respondedInTime: parseInt(stats.in_time),
    avgResponseHours: parseFloat(stats.avg_hours ?? '0'),
    byCategory: categories.map(c => ({
      category: c.category,
      avgHours: parseFloat(c.avg_hours),
      breachRate: parseFloat(c.breach_rate ?? '0'),
    })),
  };
}

Results

  • First response time: 45 minutes average (was 12 hours)
  • Lost emails: zero (was 20%) — every email tracked with SLA
  • Sales leads misrouted: zero — AI detects sales inquiries with 96% accuracy
  • $50K lead: would have been caught immediately, not buried in support@ for 3 days
  • Auto-draft acceptance: 65% of drafts sent with minor edits, saving 3 hours/day
  • SLA compliance: 94% (was unmeasured, estimated ~60%)
  • Email classification accuracy: 93% correct routing on first pass