The problem
The shop ran roughly 120 pools on a weekly recurring schedule. Add-ons (chemical-balance calls, equipment installs) and cancellations ("we're out of town this Tuesday, skip us") came in by SMS and email all day. The dispatcher spent the first 90 minutes of every morning copying changes into a Google Sheet, eyeballing a new route, and texting each tech individually.
When the dispatcher took a one-week vacation, route quality collapsed — techs drove an extra 90 minutes a day because nobody else knew the service area well enough to optimize by hand.
What we built
Two pieces, wired together. An SMS / email intake agent classifies inbound messages (skip, reschedule, add-on, complaint) and writes the structured change to a Supabase table. A 5am scheduled workflow then pulls today's bookings plus any open work orders, runs them through a route optimizer with per-tech constraints (geographic zone, certifications, vehicle type), and pushes the resulting route to each tech's phone before they leave the yard.
The intake agent's "did the customer mean skip-once or cancel-forever?" disambiguation is one of the smaller pieces of the system that turned out to matter the most.
| Inbound text | Classification |
|---|---|
| "skip us next tues we're out of town" | skip-once |
| "please cancel our service" | cancel-forever |
| "can you come weds instead this week" | reschedule-once |
| "we've moved, pls update address" | update-customer-record |
The numbers
"We didn't need a new dispatcher. We needed the existing one to stop building the route by hand." — operator note, post-launch retro