Creative Mantra
TTMS Mailer's dispatcher-facing inbox surface rendered on a laptop in a working office context — the autonomous freight agent that lives inside Red Dog Logistics's Outlook.
Client Project · Red Dog Logistics · Freight Brokerage

An autonomous freight agent that never books a load it can't verify.

Built for Red Dog Logistics. Lives in the dispatcher's own Outlook. Scores carriers on a hundred-point scale, negotiates within margin guardrails, and stops the moment it isn't sure. It runs while you sleep. It never overrides your judgment.

9
Vercel cron jobs
100
Point carrier score
$0.01
Per agent cycle
455,057
Rows in production
Red Dog Logistics brand mark
The Client
Red Dog Logistics

A freight brokerage. A crowded inbox. A better place to put the AI.

Client
Red Dog Logistics · US-national freight brokerage
Industry
Truckload freight · shipper-to-carrier matching · rate negotiation
Role
Product, design, and engineering — end-to-end build
Stage
In production · 455,057 rows on Hostinger-hosted Supabase VPS

Red Dog Logistics runs a mid-market freight brokerage on Microsoft Outlook and their in-house TMS. Their dispatchers spend most of their day inside two applications: their inbox and their order system. We built TTMS Mailer to close the loop between them — so the AI doesn't sit alongside the dispatcher's workflow, it lives inside it.

The TMS order surface at Red Dog Logistics, where loads extracted from carrier email are matched, assigned, and written back into the dispatcher's order-of-record system.
The TMS order surface that receives loads extracted by TTMS Mailer — after the agent's overnight cycle finishes.
The Bottleneck

In freight brokerage, the inbox is where margin gets made — and lost.

Beat 01 · The volume

Two to three hundred freight emails a day per dispatcher.

Tender requests, carrier quotes, rate counters, status inquiries, RFP CSVs, PDFs, forwarded threads with signature noise. Every single one is a load, a lane, a margin decision — or spam. Sorting them is the job.

Beat 02 · The mistakes

The mistakes are expensive. Freight brokerages don't lose money in big dramatic events.

Booking a load to the wrong carrier. Missing a shipper's counter. Quoting a lane below margin because the DAT number moved and nobody updated the spreadsheet. Losing a customer to a competitor who replied first. They lose it three cents per mile at a time.

Beat 03 · The trust problem

The tools that promised to fix this failed on trust.

Black-box pricing models that spit out a number with no math. TMS-bundled AI assistants that replied on top of a teammate's thread. Autonomous email agents that fuzzy-matched a load and booked it to the wrong shipper. Dispatchers turned them off after the first incident and never turned them back on.

unread
unread
unread
unread
unread
unread
unread
unread
tender
quote
counter
status
rfp
spam
tender
quote
sent
held
sent
sent
sent
held
sent
sent

We built TTMS Mailer to close the loop — without losing the trust.

Discovery

Six months inside a working brokerage before we shipped a single autonomous reply.

0+
Emails per day per dispatcher
0
Sub-intent classifications required to route correctly
0
Tolerance for booking a load to the wrong shipper
Three product laws, enforced in code

The verify law.

If a specific order ID is referenced but not found in TTMS, the agent stops. No fuzzy fallback. Ever.

The margin law.

No autonomous booking below the margin floor. 14% target, $125 hard floor, 10% carrier-side floor — enforced server-side, not in a prompt.

The teammate law.

If a pod member has already replied on a thread, the agent defers. Multi-tenant trust is a code path, not a config toggle.

2026-03-09
First tracked commit. The codebase is formalized.
2026-04-30
Agent testing phase. The planner and executor separated.
2026-05-21
product.md freeze. The guardrails become the doctrine.
2026-05-29
Lane-norm re-key (migration 053) · VPS Supabase migration.
2026-06-03
Production cutover to VPS Supabase.
2026-07-30
Live and running · this case study.

An autonomous agent that a dispatcher cannot interrogate is a support ticket. So we built the agent that answers to the dispatcher — that shows its math, keeps its receipts, and stops the moment it isn't sure.

— TTMS Mailer product principle #1
Architecture

One agent. Two pipelines. Nine cron jobs. One database of record.

TTMS Mailer runs two parallel pipelines against a shared state machine in Supabase. The outward-facing pipeline reads carrier and shipper email from the dispatcher's Outlook, classifies it, extracts loads, scores carriers, negotiates rates, and books loads in TTMS. The internal pipeline listens on category-scoped internal addresses (qq@ · rates@ · loadwork@ · status@ · carriersourcing@ · loadbuilding@) so teammates can hand off work to the agent by email. Both pipelines share the same guardrails, the same margin engine, the same carrier scoring, the same ledger.

TTMS Mailer system architecture A five-layer architecture diagram: ingress from Microsoft Graph and Outlook, agent layer with Claude Sonnet 4.6 planner and tool router, domain engines including the load matcher, carrier scorer, margin engine, and guardrails, a data layer on Supabase self-hosted on Hostinger, and a highlighted trust layer with the wrong-order guard, pod-awareness, and margin transparency. Ingress outlook + graph api Microsoft Graph API delta-sync · webhook subscriptions · dedup Dispatcher's Outlook user's real mailbox · OAuth via Azure AD Email store Upstash Redis dedup · Supabase thread stitch Agent planner · router · executor Planner Claude Sonnet 4.6 · tool-use prompt caching · $0.01 / cycle Tool router extract_loads · score_carriers · send_offer lookup_order · negotiate_rate Executor shipper · tender · carrier-reply · status idempotent handlers · state machine Engines freight domain logic Load Matcher 3 paths · Order ID → PO → addr hard stop on ID miss Carrier Scorer 100-point · 5 factors ±15 response modifier Margin Engine 5 sources · Sonnet 4.5 synth 14% target · $125 floor Guardrails circuit breaker server-side enforcement Data state of record Supabase Postgres self-hosted on Hostinger VPS 455,057 rows · 512.7 MB · RLS srv1714085.hstgr.cloud TTMS history client TMS · order lookups past_carriers · orders lane_norms_cache DAT integration live posted-loads API spot rates · fuel surcharge junk exclusion < 40% Trust the safety architecture Wrong-Order Guard Order ID missing in TTMS → hard stop · no fuzzy fallback product principle #2 Pod-Awareness Teammate already on thread → agent defers · no override the teammate law Margin Transparency 14% target · $125 floor · 10% carrier visible math trail · server-enforced LLM cannot underprice Send graph /sendmail Outbound: dispatcher's real Outlook address via Microsoft Graph /sendMail — no bot name, no forwarding rule, no custom DMARC
The Mailbox

Not a bot address. Not a forwarding rule. The dispatcher's own Outlook.

Every outbound email the agent sends — every offer to a carrier, every reply to a shipper, every internal auto-reply — goes out from the dispatcher's real Outlook address via Microsoft Graph's /sendMail endpoint. The carrier sees the dispatcher they've been working with for years. The shipper sees the person whose voice is on the phone every Tuesday.

The AI doesn't have a name, doesn't have a signature, doesn't announce itself. That was the requirement. The user's identity is the interface.

Inbound is a delta-sync from Graph API's subscription mechanism, with webhook notifications for real-time updates. Duplicate webhook deliveries are caught in Upstash Redis. Conversation threads — including the Reply-All chains, forwards, and signature noise that make freight email unique — are reconstructed through Graph's conversation ID and parent references.

OAuth via Azure AD · daily subscription renewal at 12 PM ·
no custom DMARC/SPF/DKIM (client's Outlook tenant handles email security)
Delta-sync sequence · live
01
Webhook
Graph fires
02
Dedup
Upstash Redis
03
Parse
unpdf · Mammoth
04
Stitch
conv-ID thread
The Cycle

9:00 PM UTC. One cron. Every enabled user's inbox, in sequence.

The main agent cycle is a single Vercel cron: POST /api/cron/agent. It fires once a day at 9 PM UTC and iterates over every enabled user's Outlook inbox in sequence. For each user, the planner (Claude Sonnet 4.6, with tool-use and prompt caching) reads unprocessed emails and decides which specialized handler to invoke. The handler executes. The state machine updates. The cycle costs about a penny.

The 9 PM agent cycle A horizontal timeline showing the eight steps of a single agent cycle: 9 PM UTC trigger, read inbox, classify emails, match loads, score carriers, draft response, guardrail check, then send or hold for review. the cycle 9 PM UTC Fire POST /api/cron/agent 01 Read inbox unprocessed emails supabase query 02 Classify 6 categories · 23 intents gemini 3 flash 03 Match loads 3-path matcher order → PO → addr 04 Score carriers 100-point engine past_carriers table 05 Draft response margin engine synth sonnet 4.5 06 Guardrail check wrong-order · margin · pod enforced in code Send graph /sendMail from dispatcher Hold for review escalation queue dispatcher am One cycle. Iterated per enabled user's inbox in sequence. Fully idempotent — safe to re-run. ≈ $0.01 total LLM cost

One cycle. About a penny in LLM cost. Fully idempotent — safe to re-run.

The Signature

The wrong-order guard. The one guardrail we won't ship without.

Order 134637
Beat 01 · The trigger

When a carrier reply mentions a specific order ID, the agent extracts it and does one thing before anything else.

“Quoting on order 134637.” “ORD-134637.” “Load #588.” The regex catches all three shapes. Direct API call. GET /api/orders/{id}. Single source of truth. Nothing else runs first.

Beat 02 · The match

If the order exists in TTMS, the agent proceeds down the negotiation pipeline.

Score carriers. Draft rate. Send. Standard cycle. The verification is invisible in the happy path — which is exactly the point. The guard is only expensive when it fires.

Beat 03 · The failure mode

If the lookup returns empty, most agents would fall through to fuzzy matching.

Search by PO number, then by address, then by rate. That is how you book a load to the wrong shipper. The dispatcher wakes up to a rate confirmation on the wrong customer's account, and the trust is gone forever. TTMS Mailer refuses that path.

Beat 04 · The escalation

TTMS Mailer stops. Replies to the carrier. Flags the thread. Escalates to human.

“Couldn't find that order — could you resend with the correct reference?” The miss is logged. The thread is queued for the dispatcher's morning review. The agent does not guess.

From: pacific-freight@example.com 09:42 UTC
Hi — we can cover this move.
Quoting on order 134637 at $1,485. Truck departs Kankakee 06:00 tomorrow.

Pacific Freight Lines · MC-512334
Match · TTMS 200 OK
order 134637 found
proceed to negotiation pipeline
Hard Stop
order 134637 · not found
TTMS returned 404. Fuzzy fallback disabled.
Agent will not proceed.
To: pacific-freight@example.com · From: dispatcher@reddoglog.com
Re: Kankakee → Willoughby · Order 134637
Escalate · morning review

“One wrong-book is worth a thousand right-books that never happened.”

— TTMS Mailer product principle #2
The wrong-order guard decision flow A decision tree showing what happens when a carrier email references an order ID: the ID is extracted, the system searches TTMS by ID, and either proceeds when found or hard-stops and escalates when not found. Fuzzy matching is explicitly rejected as a fallback path. wrong-order guard Order ID extracted from email /order\s?(\d+)|ORD-(\d+)|load\s?#(\d+)/ Search TTMS by ID GET /api/orders/{id} direct API call · single source of truth found not found Proceed continue negotiation pipeline score carriers · draft rate · send HARD STOP agent does not guess reply: "couldn't find that order" flag thread · escalate to human escalate to dispatcher Fuzzy fallback search by PO · then by address · then by rate — rejected path — one wrong-book is worth a thousand right-books that never happened.

The wrong-order guard is joined by two siblings: the margin floor and the pod-aware handoff. Together they form the safety architecture. The LLM never overrides them; they are enforced in code, not in prompts.

Load Matching

Three paths. One hard stop.

When a carrier replies about a load, the agent tries to match the reply to an order in TTMS in strict priority order. Each path is faster and more specific than the next; the agent only falls through if the higher-priority path has no signal to work with. And the guard on top of all three: if a specific order ID was extracted but not found, the fall-through does not happen. The agent stops.

Three-path load matcher Three horizontal lanes stacked in strict priority order: Path 1 order ID lookup with hard-stop on failure, Path 2 PO/reference number lookup, Path 3 address and rate corroboration. Each path shows its input signal, lookup mechanism, and confidence level. load matching strict priority order — falls through only if higher path has no signal signal lookup confidence 1 Order ID highest priority Order ID regex "quoting on order 134637" /order\s?\d+|ORD-\d+|load\s?#\d+/ Direct TTMS lookup GET /api/orders/{id} hard stop on miss — no fall-through HIGH — DIRECT HIT single source of truth · 100% 2 PO / Reference fallback if no ID PO number extraction "our PO 4400823-7" reference_number field Filtered TTMS query GET /api/orders?reference_number= multi-hit disambiguated by rate proximity MEDIUM — DISAMBIGUATED closest-rate wins on multi-hit 3 Address + Rate last resort · flagged Origin/dest + rate "Kankakee IL → Syracuse NY $2,240" city + state + rate parse Fuzzy address search searchOrdersByAddress closest-rate matching · logged LOW — FLAGGED logged for dispatcher review
if (extractedOrderId && !ttmsLookup(extractedOrderId)) { return escalate("couldn't find order; please resend with correct reference"); } // no fall-through to PO or address matching when an ID was named
Carrier Scoring

One hundred points. Five factors. Two modifiers.

Every carrier the agent considers for a load gets a score between zero and one hundred, computed from the past_carriers table in TTMS and modified by the response-history data the agent has collected itself. Scores drive the offer-email order: the top-scored carriers get the offer first. Scores are visible in the UI with badge colors — 80+ green, 60–79 amber, 40–59 gray, under 40 red — so the dispatcher can see at a glance which lanes have deep coverage and which are thin.

100-point carrier scoring engine A circular 100-point gauge on the left with five weighted factor bars in the middle showing lane history 35, carrier rating 25, approval 15, insurance 15, and active status 10, plus a plus-or-minus 15 response-history modifier column on the right. 100-point carrier score 85 / 100 sample score 80+ · green 60–79 · amber 40–59 · gray < 40 · red five weighted factors Lane history 35 6+ loads = 35 · 4–5 = 28 · 2–3 = 20 · 1 = 10 · 0 = 0 Carrier rating 25 SATISFACTORY or CONDITIONAL = 25 · else 0 Approval status 15 carrier_approved = 1 → 15 Insurance valid 15 insurance_valid = 1 → 15 Active status 10 carrier_status = 1 → 10 modifiers +15 reliable responder −15 serial ghoster applied post-sum from response history table

Reliability is scored. Ghosts are penalized. The scoring updates every time a carrier does something.

Margin Engine

One recommended rate. Five sources. A visible math trail.

Most AI pricing tools are one-shot LLM calls. Prompt in, number out, no math. That is the wrong shape for a freight brokerage. Margin teams need to see how the number was formed — because half the job is defending it to the shipper. So we built the Margin Engine: a rate synthesis pipeline that pulls from five sources, applies a Claude Sonnet 4.5 synthesis step, and returns a recommended rate with the math trail attached. Every source, every weight, every override — visible.

Margin Engine formula assembly A horizontal calculation diagram: five source cards (TTMS history, live DAT query, lane boundaries, learned macros, rate feedback) flow into a central synthesizer running Claude Sonnet 4.5, which outputs a recommended rate that passes through a 14 percent target and $125 floor enforcer before emerging as the final buy rate. margin engine — visible math five sources TTMS history 15 pages × 100 orders · corridor lane_norms_cache · 24h TTL Live DAT query posted-loads API · fuel surcharge junk exclusion < 40% DAT avg Lane boundaries user-maintained min/max per corridor · dispatcher-owned Learned macros DAT reports · NTI · OTRI · LTR shipper-vs-carrier pressure Rate feedback prev negotiations · overrides rate_feedback · learning write path synthesizer Claude Sonnet 4.5 weighted synthesis reasoning · math trail out rate $2,240 recommended enforcer Guardrails 14% target $125 floor 10% carrier server-enforced final buy rate $2,240 client · $1,935 carrier projected margin $305 (13.6%) ✓ within guardrail · Kankakee IL → Syracuse NY Every source has a weight. Every override is logged. The LLM cannot underprice. sample lane — illustrative
Sample lane · real data
Kankakee, IL → Willoughby, OH · 53FT reefer · 46,000 lbs
TTMS history (90d)3 loads · $1,620 · $1,550 · $1,680
DAT anchor$1,580 mid (Line Haul $1,500 + Fuel $80) · 47 moves last 7 days
Lane boundaryfloor $1,400 · target $1,600 · ceiling $1,800
Recommended (client)$1,650 · +4% over DAT mid
Top past carrierPacific Freight Lines · MC-512334 · 92/100
Carrier history6 loads · 87% response rate · last rate $1,620 (2026-04-22)
Offer to carrier$1,485 · target minus 10% (negotiation room)
Target margin14% · hard floor $125
Projected margin$1,650 − $1,485 = $165 · 10.0%
Below 14% target but above the $125 hard floor. Agent proceeds — dispatcher notified in the morning review. The math is visible; the dispatcher can accept, counter, or reset the target for this lane.

14% target margin. $125 hard floor. 10% carrier-side floor. Enforced server-side. The LLM cannot underprice.

Model Orchestration

One request. Three models. Prompt caching keeps the whole cycle at a penny.

TTMS Mailer routes every LLM call through OpenRouter using the OpenAI-compatible SDK. The hot path — classification, extraction, drafting — runs on Gemini 3 Flash: fast, cheap, and good enough for structured extraction from PDFs and DOCX. The planner — the model that decides which tools to invoke next — runs on Claude Sonnet 4.6 with tool-use and prompt caching enabled; the system prompt, tool definitions, and historical learnings are cached so repeated cycles don't re-tokenize static context. Lightweight reasoning runs on Claude Haiku 4.5. Vercel AI Gateway sits behind the whole thing as a fallback.

Multi-model LLM orchestration A central agent request node fans out through OpenRouter to five model endpoints: Gemini 3 Flash for the hot path (brand-gradient default), Claude Sonnet 4.6 as the planner with tool-use and prompt caching, Claude Haiku 4.5 for lightweight reasoning, Claude Sonnet 4.5 for margin engine synthesis, and Vercel AI Gateway as fallback. the request Agent request classify · plan · negotiate /api/cron/agent the router OpenRouter openai-compatible SDK gateway + fallback the models use case · cost Gemini 3 Flash classify · extract · draft — hot path $ · FAST DEFAULT Claude Sonnet 4.6 planner · tool-use · prompt caching $$ · CACHED PLANNER Claude Haiku 4.5 thread resolver · rate fast path $ · LIGHT Claude Sonnet 4.5 Margin Engine synthesis · reasoning $$ · MATH Vercel AI Gateway fallback · reliability — · FAIL-OVER primary paths (hot + planner) specialised paths ≈ $0.01 / cycle · ≈ $7/mo/user at 24/7 Live mode
ModelProviderUse caseNotes
Gemini 3 Flash (preview)OpenRouterClassify · extract · draftHot path
Claude Sonnet 4.6OpenRouterPlanner (tool-use)Prompt caching
Claude Haiku 4.5OpenRouterThread resolver · rate fast pathLightweight
Claude Sonnet 4.5OpenRouterMargin Engine synthesisReasoning
Vercel AI GatewayVercelFallbackReliability

Cost target held: ~$0.01 per agent cycle · ~$7/mo/user at 24/7 Live mode.
LLM usage tracked per request in the llm_usage table.

The Loop

3:00 AM UTC. Pattern distillation. Not fine-tuning.

Every night at 3 AM UTC, a cron job named distill-patterns reads the previous day's carrier blast history and lane-level negotiation outcomes and distills them into two pattern sets. The first is carrier-level: this carrier accepts on this lane at this rate window; that carrier ghosts. The second is lane-level: this corridor's average closing rate, time-to-close, acceptance rate. Both pattern sets are injected into the next day's LLM prompts.

This isn't fine-tuning. There is no LoRA. No RLHF. No custom-trained model. The loop is observation → distillation → prompt injection, and it runs on commodity models.

The advantage is that the learning is inspectable — you can read the patterns as text, argue with them, correct them. The disadvantage is that it doesn't compound the way a fine-tuned model would. For a freight brokerage that changes lanes and carriers every quarter, that trade is correct. Rigidity is the enemy.

The nightly learning loop A circular observation-distillation-injection loop: today's agent activity feeds into the 3 AM distill-patterns cron, which extracts carrier and lane patterns, stores them as macros, and injects them into tomorrow's decisions. Not fine-tuning — pattern distillation. the learning loop · not fine-tuning 1 Agent activity today carrier blasts · negotiations blasts · replies · outcomes 2 3 AM · distill-patterns nightly cron · idempotent 03:00 UTC 3 Extract patterns L1 carrier · L2 lane this carrier · this lane · this rate 4 Store as macros Supabase · text-inspectable read · argue · correct 5 Inject into prompts tomorrow's LLM context no LoRA · no RLHF observation → distillation → injection pattern distillation a loop that actually ships not fine-tuning · not RLHF Two levels: L1 carrier blast history · L2 lane intelligence. Both distilled nightly. Both injected into the next cycle's prompts.
Two levels: L1 carrier blast history · L2 lane intelligence. Both distilled nightly. Both injected into the next cycle's prompts.
The Teammate Law

If a teammate is already on the thread, the agent stands down.

Red Dog Logistics runs its dispatchers in pods — a pod is a team that shares visibility on a set of loads. TTMS Mailer respects the pod boundary at every level. A user only sees loads assigned to their pod. The agent only auto-replies on threads where no pod member has already engaged. If a teammate has drafted, replied, or commented on a thread, the agent defers. This is not a config toggle; it's a hard-coded query gate.

Pod membership sourced from TTMS · queried on every cycle ·
no cross-pod load bleed · no override

Combined with the wrong-order guard and the margin floor, the pod-aware handoff completes the safety architecture. The agent is autonomous, but it operates inside three concentric fences: it verifies, it prices honestly, and it defers to humans. Nothing about that should be revolutionary. It is what an autonomous agent for a working brokerage should look like.

Pod · live
Pod A
S
m
j
r
Pod B
k
a
t
Pod C
p
n
c
l
Thread · Pod A · 08:14 UTC
Sandeep · dispatcher: Already on this — will send counter at 09:00.
Agent: Deferred. No draft, no send.
— agent stands down until pod is clear.
Infrastructure

Nine cron jobs. That's the architecture. That's the whole thing.

We didn't build a queue. We didn't build a worker fleet. We didn't build an event bus. We took a hard look at the workload — daily batch cycles, occasional real-time email triggers, everything idempotent — and decided that nine Vercel cron jobs and a Supabase state machine would do the job.

It did. It has been in production for two months. It costs a rounding-error amount of money. It has no ops overhead. Every cron is idempotent; every cron can re-fire safely; every cron writes state to Postgres and reads state from Postgres. Nothing is in memory.

The main agent cycle fires at 9 PM UTC. Delta-sync at midnight. Pattern distill at 3 AM. Token refresh at 6 AM. Ghost detect at 9 AM. Graph subscription renew at noon. VAPI extract at 3 PM. TTMS sync at 6 AM. Quote-board refresh at 4 AM. That is the whole async architecture.

Nine-cron 24-hour architecture A 24-hour clock face with nine cron markers positioned by their scheduled UTC hour: agent at 9 PM, delta-sync at midnight, distill-patterns at 3 AM, quote-board-refresh at 4 AM, token-refresh and TTMS sync at 6 AM, ghost-detect at 9 AM, graph-renew at noon, and VAPI extract at 3 PM. 00 06 12 18 the architecture 9 vercel cron jobs no queue · no worker fleet · no event bus 21:00 agent — main cycle 00:00 delta-sync 03:00 distill-patterns the learning loop 04:00 quote-board-refresh 06:00 token-refresh 06:00 ttms-sync 09:00 ghost-detect 12:00 · graph-renew 15:00 vapi-extract the 24-hour clock · utc BullMQ · SQS · Kafka · Celery · Redis Streams
Not in the stack: BullMQ· SQS· Kafka· Celery· Redis Streams

Every one of these was considered. Every one was rejected.

The Surgery

Three stories from the parts of the system that don't ship in a demo.

Every autonomous agent in production has parts that are custom, surgical, and embarrassing to talk about at a conference. Here are three of ours. They are the reason the agent works on real customer data. They are also, we think, the most honest thing we can say about the system.

Production pragmatism tiles Three story tiles showing the parts of TTMS Mailer that don't ship in a demo: IKO Kankakee hardcoded values, Aunt Millie's PDF content fingerprinting versus filename regex, and the lane-norm cache migration from city strings to customer IDs. tile 01 · the hardcode IKO Kankakee every order for two years, byte-identical. bill_type: "COLLECT" total_weight: 42775 freight_description: "Shingles" notes: "standard IKO shipping" // fires on origin.name ~= /iko.*kankakee/ Tier-3 resolution. Inference here was slower AND wrong. tile 02 · the fingerprint Aunt Millie's filename regex broke. content fingerprint didn't. BEFORE /aunt.?millies.*\.pdf/i AFTER pdf content fingerprint: if (pdf.contains("Walmart Retail Link") && pdf.contains("supplier 2124641")) → collapseTrailMail() · override ship-from/to Multi-load collapse. Latest PO wins. tile 03 · the re-key lane-norm cache city names silently broke matching. so we changed the key. BEFORE (client_id, origin_city, origin_state, dest_city, dest_state) AFTER migration 053: (client_id, shipfrom_customer_id, shipto_customer_id) "Grand Rapids" and "Wyoming" — same warehouse. Now fixed.

Three tiers of resolution: (i) what the document said, (ii) what the client's history said if 80% of orders agreed, (iii) hardcoded for byte-stable clients. Higher tiers short-circuit lower ones. Every resolved value carries provenance.

The Stack

Boring on purpose.

Frontend
Next.js 16 (App Router, Turbopack) · React 19.2 · TypeScript 5 · Tailwind CSS 4 · shadcn/ui · Lucide React · Recharts 3.8 · React Quill · Sonner
Backend & API
Next.js API Routes (50+ endpoints) · Vercel serverless + cron · Upstash Redis (hot-path caching · webhook dedup)
Data
Supabase Postgres (self-hosted on Hostinger VPS · 2026-05-29) · Supabase RLS (multi-tenant isolation) · Supabase Realtime (WebSocket UI updates) · 26 migrations · 455,057 rows in production
AI
OpenRouter (primary) →
Gemini 3 Flash (classify/extract/draft) · Claude Sonnet 4.6 (planner + prompt caching) · Claude Haiku 4.5 (fast-path reasoning) · Claude Sonnet 4.5 (Margin Engine synthesis) · Vercel AI Gateway (fallback)
@microsoft/microsoft-graph-client · unpdf (serverless PDF) · Mammoth (DOCX) · puppeteer-core · date-fns · DOMPurify · xlsx
Not in the stack: no BullMQ, no SQS, no vector database, no MCP servers, no multi-agent framework, no fine-tuning pipeline, no custom domain/DMARC infrastructure. Every one of those was considered. Every one was rejected.
Operating

In production. In the dispatchers' inbox. In the wild.

TTMS Mailer is not a prototype. It is a working product handling real freight for a real brokerage. The numbers below are architectural and operational — they are the ones we can verify from the codebase and the production database. Business-outcome numbers belong to the client to publish, not to us.

0
Rows in production Supabase (VPS-hosted)
0
Total database size
0
Active cron jobs
0
API routes
0
Per agent cycle (with prompt caching)
0
Per active dispatcher at 24/7 Live mode
2026-03-09
Initial codebase formalized.
2026-04-30
Agent testing phase.
2026-05-25
Lane-norm coverage deepened · Aunt Millie's carve-out shipped.
2026-05-29
Migration 053 (lane-norm re-key) · VPS Supabase migration.
2026-06-03
Production cutover to VPS Supabase (srv1714085.hstgr.cloud).
2026-06-08
Lane-norm PDF upload + canonical client auto-fill.
2026-07-30
Live and running · this case study.
What We Learned

Four observations from shipping an autonomous agent into a working brokerage.

Lesson i.

The hardest engineering was making the LLM safe to leave running.

The LLM part of the system is small. The guardrails around it — the wrong-order guard, the margin floor, the pod-aware handoff, the circuit breaker — are most of the work. If we had spent that effort on prompt engineering instead, the agent would be smarter and unshipped.

Lesson ii.

Hardcoding beats inferring, when the client is stable.

For IKO Kankakee, every order is byte-identical. Trying to infer stability with a machine learning loop was slower, less reliable, and philosophically worse than typing the constants into a config. Sometimes the honest answer is a hardcode.

Lesson iii.

Nine cron jobs is enough.

Every time we felt tempted to build a queue, we found a way to solve the problem with an idempotent cron. Two months in, we haven't regretted a single one of those decisions. The queue is a hedge against a scale we don't have and may never have.

Lesson iv.

A dispatcher's trust is the whole product.

Every conversation with the client's dispatchers came back to the same question: “what does the agent do when it's not sure?” Everything downstream — the guardrails, the visible math, the escalation queue, the pod-aware handoff — is a different-shaped answer to that single question.

Keep Reading

More AI products we've shipped and run.

Three more case studies from Creative Mantra — author-first AI editors, voice-driven logistics platforms, and 35-mailbox healthcare ops.

See all case studies
Building Something With Sharp Edges?

TTMS Mailer was built for one brokerage.
We build the same way for anyone who needs an agent they can leave running.

If you're planning an AI product where the trust story matters — where the agent has to be safe enough to run overnight against real customer data — we would like to hear about it.