confidence < 0.60confidence ≥ 0.60requester repliesApprove · ownerSkip · ownerRetry · owner/ctx · ownermerge · owner
Slack Ping
@mention or DM — a real-time Slack event wakes Caleb Jr.
Vercel Cron
Scheduled channel scan — cron · /rescan sweeps recent messages.
Haiku Triage
Tier 1 reflex — reads every message and takes exactly one exit.
Dropped
Duplicate of a task already being tracked.
Ignored1919
Not a request — no action taken.
Chat Reply2727
Greeting or question — answered in the thread.
Declined22
Can't do it — the requester is told why.
Sonnet Brain
Tier 2 — entered on low confidence; assembles a precise brief.
Clarifying22
One targeted question out; the reply comes back to the brain. ≤3 rounds.
Pending
Approval card sent — waiting on the owner to Approve or Skip.
Rejected1515
Owner clicked Skip — closed without a build.
Dispatched to Cursor
Cursor cloud agent building on its own branch.
Failed
Agent errored — owner clicks Retry to relaunch it.
Needs Info
Finished with no PR — /ctx <detail> re-runs it.
Codex review
A Codex agent reads the diff and reasons with the PR. Changes requested go back to Cursor for another pass; a clean review is what opens pr-ready.
pr-ready44
Real GitHub PR open — squash & merge when happy.
Merged88
Done and closed — either a squash-merged PR, or an action run straight off the approval card. Requester notified either way.
Preview gate
All checks green → label vercel-preview → build preview → DM the owner the link.
Actions: lint · build
GitHub Actions on the PR head: lint → typecheck → build. checksGreen() reads these runs; Vercel-named checks are excluded so the preview never gates itself.
Requester notified
The merge fires notifyRequester(): a plain-language reply in the original Slack thread, and 👀 swaps to ✅ on the request.
July 12, 2026

Creating a multi agent pipeline on slack

The problem

For the past ~2 years I've volunteered to build websites for non-profits, using slack as the medium for communication. However, I've gotten a lot busier, and requests often come in sporadic bursts. While not particularly hard to address, I just don't have the time to extend to each of these tasks anymore.

The solution

So I built Caleb JR, a multi agent pipeline composed of 4 different agent calls, regulated by a few human bottle necks. It is optimized for minimal human effort and concurrently; maximum leverage across the flow.

RESTINGconfidence 0.30gate 0.60

How the automation works

On a high level, this is an automation chaining several agents together: context is gathered via Vercel CRON, triaged by a Claude instance, then pushed to a cloud agent which opens a PR. All of this is automated.

Context is gathered via a Vercel CRON which fires once a day. It pulls all new slack messages in channels the agent is added in. Inbound messages are then triaged via an instance of Claude Haiku and evaluated as "actionable" according to a confidence score dependant on:

1.

Ignores messages not aimed at me (random chatter ect)

2.

Tasks are then cross checked with pre existing tickets to prevent redundancies.

3.

If at this point the agent is confused, it pings for clarification

Model evaluation

When I initially set my automation up, I just threw whatever model I was using onto the line. Part of creating good scalable automations is being highly intentional with each of the parts. So I did some research to try and determine if I was really getting the most “bang for my buck”. Also, in general I figured this would be a good exercise for understanding model benchmarks in general.

Note!! These benchmarks should not be used for general evaluations, and were evaluated (through subjective multipliers) to my very specific use cases! (ie: I can't afford to run expensive models, so model cost was factored generally higher ect..)

0 tokens40.0k tokensHaikuTriageSonnetBrainHumanapprovalCursordispatchCodexcheckHumanmerge≈1.9k0≈36.8k0

Triage was evaluated on BFCL (Berkeley Function Call Leaderboard), a public standard benchmark for function/tool calling from natural language — which is basically the job of the triage layer of the agent.

This was evaluated on 3 factors:

Speed (latency), measured by how quickly the model triaged decisions from BFCL

Cost, measured by the cost to run the entire BFCL

Triage, a weighted composite of irrelevance and live / non-live accuracy

Command A Reasoning (Cohere)
Triage 84.2
CPP ($/pt) 0.036
Cost $ 3.04
Latency 3.4s
GLM-4.6 thinking (Zhipu)
Triage 84.5
CPP ($/pt) 0.055
Cost $ 4.64
Latency 4.3s
Claude Haiku 4.5
chosen
Triage 83.6
CPP ($/pt) 0.170
Cost $ 14.23
Latency 1.7s
Gemini 2.5 Flash (Google)
Triage 85.3
CPP ($/pt) 0.309
Cost $ 26.36
Latency 3.0s
Claude Sonnet 4.5
Triage 85.6
CPP ($/pt) 0.511
Cost $ 43.73
Latency 4.3s
Claude Opus 4.5
Triage 84.4
CPP ($/pt) 1.026
Cost $ 86.55
Latency 4.4s

Accuracy is composed of an irrelevance factor and the ability to parse structured prompts and messy non-structured prompts. Since we run a Vercel CRON and intake ~100–200 messages a day, and the workspace is primarily gen-z, it's imperative that chosen models are able to parse messy workspace chatter.

Triage = 0.40 × Irrelevance + 0.30 × Live + 0.30 × Non-Live

I weighed models according to Triage ability, which took into account model accuracy and ability to tool call successfully from both structured prompts and unstructured prompts (chatter). I gated the table to a triage benchmark of 83 — anything lower than that wouldn't be considered.

While Command A and GLM-4.6 feature higher triage scores and cheaper CPP, their latency was more than double Claude Haiku's, which rounded out to be the fastest model of the showing, as well as the 3rd lowest CPP (cost per performance). Not that sweating cost is that big of an issue since I'm operating on a relatively low intake scale, but latency and speed were much higher of a priority for me. The triage gate needs to quickly communicate to an impatient prompter what it's doing, and so speed being the most important factor steered me to use Haiku.

Features

Other features that help with re-seeding context, communicating what the bot is doing to the user, and generally making it's uses cases more robust.

Responds when pinged

/commands to display tasks and to rescan tasks.

each ticket has a ticket number which can be used to append context via /agent call.

Responds to correspondents when the agent has finished task with description

Uses emojis to indicate ticket status (read, finished)

Footnotes
This is still heavily work in progress, but this was a really exciting idea to brew over. The most annoying part was how constrictive Slack was with their agent integration. A lot of context and features get bottlenecked by Slack's poor agent support, forcing awkward compromises (emojis reactions … etc).
This is excessively rigid. I'd like to add a set of lightweight features I could update via the bot, then run a slash command to update it locally.
I find myself debugging via claude code 7/10 times. This is very annoying, which means the agent just isn't robust enough yet.
This gets me all the more excited to be working alongside the incredibly talented team at Ando.