An AI support agent that classifies incoming email into 10 categories and drafts replies grounded only in company documentation. Built in n8n for the Inbox Inferno community challenge. Final judged score: 30/30, zero misclassifications.
Watch the demo · Built with n8n and Claude
- Self-evaluation: 5.00/5.00 across 20 test emails using n8n's Evaluation feature with a strict match judge
- Challenge judging: 30/30. That is 20/20 on the known test set plus 10/10 on novel emails the judges sent to the live webhook, unseen during development
- Correct handling of
escalate_finance, a category present in the data but absent from the challenge template
workflow/triage-ai-workflow.json: the complete workflow export, importable into any n8n instance. API key scrubbed to a placeholder.prompts/classification-prompt.md: the classification system prompt, 10 categories and 13 decision rules.prompts/draft-reply-prompt.md: the grounded reply-drafting prompt and its no-hallucination design.examples/: screenshots of the canvas, a live execution, and the evaluation runs.
An email arrives as a POST to the webhook with from, subject, and body. The pipeline runs five stages:
- Classify Email. Claude assigns exactly one of 10 categories (pricing, setup, security, four escalation routes, hr, spam, misdirected) under 13 decision rules, at temperature 0, returning strict JSON.
- Lookup Docs. A code node parses the classification, matches the sender against the 50-customer Nexus dataset to pull company, plan, and SLA, then loads the documentation set for that category.
- Draft Reply. A second Claude call writes the reply using only the injected documentation. If the docs do not answer the question, it acknowledges and escalates rather than inventing anything.
- Format Output. Normalizes everything into the
{category, draft_reply}response contract. - Respond to Webhook. Returns the JSON to the caller.
A parallel evaluation lane (dataset trigger, test email loader, and a strict 0/1 scoring node) runs the same pipeline against the test set without touching the production path.
Here is a live execution end to end: a Starter-plan customer reporting a Salesforce authentication failure, classified as setup, answered with the documented fix.
The hardest problem was not the AI. It was the plumbing.
n8n lets you pin test data on a webhook node while building. Pinned data arrives with fields at the top level. Real production POSTs arrive with the payload nested inside body. The workflow ran perfectly against pinned data and would have failed on every single judge request, because judging happened against the live webhook.
The fix is the first thing in the Classify Email node:
// Handle both pinned data (top-level) and production webhook (nested in body)
const email = {
from: raw.from || (raw.body && raw.body.from) || '',
subject: raw.subject || (raw.body && raw.body.subject) || '',
body: (typeof raw.body === 'string') ? raw.body : (raw.body && raw.body.body) || ''
};Every ingress point in the workflow handles both shapes. Sometimes the hardest debugging is not the model, it is the pipe feeding it.
Runs 1 and 2 finished with errors while the eval lane itself was being wired. Run 3 completed at 4.80: nineteen emails scored 5.00 and one scored 1.00.
Test case #20 sat on the boundary between security and legal: compliance documentation requests read like security questions but a DPA is legally a contract matter. The fix was not a bigger model or a longer prompt. It was two explicit decision rules: a SOC 2 report or BAA request stays in security with an escalation note, a DPA or GDPR agreement goes to escalate_legal. Run 4: 5.00, twenty for twenty.
The lesson that stuck: when a classifier misses, the answer is usually a sharper boundary, not a smarter model.
- Deterministic where it counts. Classification runs at temperature 0. Drafting runs at 0.2, warm enough to read human, tight enough to stay grounded.
- Hallucination control is structural. The reply model never sees the open internet or its own general knowledge as a source. Documentation is selected by category and injected into the prompt, and the rules force escalation when the docs run out.
- Graceful degradation. If classification fails to parse, the email defaults to
escalate_supportso a human always catches what the machine drops. - A strict judge. The scoring node awards 1 for an exact category match and 0 for anything else. No partial credit, no vibes.
Built for n8n's Inbox Inferno community challenge, March 2026. Nexus Integrations is a fictional company; all customer data in this repository is fictional challenge data provided by n8n.




