Blog / Recipes / FIG. 74
Build a Slack Triage Bot on Jev
Build a Slack AI triage bot with Jev: route Slack messages, filter channel noise, and escalate what matters. Step by step, with real receipts.
Every team has the channel. The one where bug reports, "quick questions", praise, and actual emergencies all arrive in the same font. Slack AI triage fixes that by asking a small set of closed questions about each message and routing on the answers, and Jev, TypeSafe AI's decision model, is built for exactly that shape.
Why triage matters, and how to design the categories for a support org, is covered in support triage with Jev. This page is the build.
What the receipts say
The closest public number is Riley Brown's run: 500 emails classified in seconds for 3.5 cents, as reported (build). Slack messages are shorter than most emails, so that's a reasonable ceiling for your per-message math. Another builder reports Jev watching 25-plus customer WhatsApp groups in real time and only waking an LLM to draft a message when something needs attention (build). Same pattern, different chat app.
These are builder-reported numbers. No official Jev benchmarks exist, so treat them as directional and test on your own channel.
The recipe
-
Create a Slack app that listens to one channel. Subscribe to message events for a single noisy channel first. Resist wiring up the whole workspace on day one; you want a small blast radius while you tune.
-
Write three questions, not one. A good starter battery:
- "Is this message asking for help, reporting a problem, or neither?"
- "Does this message describe something blocking a customer or production right now? YES / NO / UNCLEAR"
- "Which team should own this: billing, product, engineering, other?"
Separate questions give separate confidence scores, and that's what you route on.
-
Call Jev from your event handler. Per ecosystem documentation, the model is typesafe-ai/jev via the Vercel AI Gateway, returning a probability per choice. Syntax lives at docs.typesafe.ai. The shape:
# pseudocode, not real API syntax
on slack_message(msg):
kind = jev.choose(KIND_Q, msg.text, ["help", "problem", "neither"])
urgent = jev.choose(URGENT_Q, msg.text, ["YES", "NO", "UNCLEAR"])
owner = jev.choose(OWNER_Q, msg.text, ["billing", "product", "engineering", "other"])
route(msg, kind, urgent, owner)
-
Route with confidence gates. High-confidence urgent problems get reposted to the owning team's channel with a link back. High-confidence "neither" gets nothing (no emoji, no reply). Everything low-confidence lands in a triage queue a human skims. The threshold logic is the routing cascade in miniature.
-
React, don't reply. Start with emoji reactions or a thread note like "routed to engineering". Jev doesn't write text, so if you want a drafted reply, that's a chat model's job, triggered only after the verdict says a reply is warranted.
-
Log everything for two weeks. Store message ID, the three verdicts, and their confidences. Then read the disagreements. You'll find one or two questions that need rewording, which is normal.
Channel noise filter: the underrated half
Most of the value isn't routing emergencies, it's not routing everything else. A "neither" verdict with high confidence is the bot quietly deciding a message needs nothing from anyone. That's how you get channel noise down without muting humans.
The obvious objection: "What if it buries something important?" That's why "UNCLEAR" exists and why low-confidence items go to a queue instead of the void. The bot never deletes, hides, or archives. It only adds routing signals on top of a channel people can still read.
Guardrails worth keeping
No irreversible actions on a lone verdict. Don't auto-close tickets, page on-call, or DM customers because one question returned YES. Paging someone at 3am is reversible in theory and very much not in morale. Require a second signal or a human click.
Mind the retry loop. Slack retries events if your handler is slow. Acknowledge fast, process asynchronously, and dedupe on event ID, or you'll triage the same message three times.
Version your questions. Keep the question text in one config file. When you change wording, note the date so your logs still make sense.
If you'd rather build this in a no-code tool, the webhook pattern in Jev automations maps directly onto Slack triggers.
Frequently asked questions
Can a Jev Slack bot reply to messages on its own?
Jev returns decisions, not text, so replies need a separate chat model. The clean split is Jev deciding whether a reply is needed and a generative model drafting it, with a human approving anything customer-facing.
How much does it cost to triage a busy Slack channel?
Builders report classification costs in fractions of a cent per item, such as 500 emails for 3.5 cents as reported. Multiply your daily message count by your number of questions for a rough estimate, and see support triage with Jev for the broader economics.
Will it work for routing Slack messages across many channels?
Yes, the same questions work across channels, but start with one and expand once your logs show the questions hold up. Channel-specific ownership rules usually need their own question.
What happens when the bot is unsure?
Low-confidence verdicts should land in a human triage queue rather than being guessed. That fallback is the core of the routing cascade.
Numbers throughout are as reported by the build authors, not verified by shipwithjev. Code-shaped examples are pseudocode; the official docs live at docs.typesafe.ai.