The Dispatch Problem in 90 Seconds
A dispatcher at a 30-truck HVAC shop does this job in real time, every day, with no algorithm:
- A new job comes in — residential AC repair, 2pm window, zip code 95128
- She scans which techs are currently available
- She checks who has the right EPA 609 certification
- She estimates drive time from each tech's current location (mentally, with some Google Maps help)
- She checks who hasn't had a complaint in the last 30 days
- She picks someone and moves on
This works fine at 8 trucks. At 25, it starts falling apart. At 40, she's making decisions based on gut feel and crossed fingers — and that's when the $300 missed-window callbacks start.
The dispatcher bottleneck has four layers:
- Cognitive load: Holding 40+ technicians' live states, certifications, locations, job histories, and customer relationships in your head while the phone rings
- Window misses: A tech who was 8 minutes away gets reassigned because the dispatcher didn't notice the ETA. Customer waits 2 hours.
- After-hours: No dispatcher on at 9pm when a job comes in from a commercial customer. It gets scheduled for tomorrow instead of tonight.
- Turnover: Good dispatchers are rare and expensive. Training a replacement takes 6–9 months. Meanwhile, knowledge walks out the door every time someone leaves.
CrewOps was built to remove that bottleneck. Not to replace dispatchers — to do the triage work they don't have time for, so they can handle the exceptions that actually need a human.
Here's how the agent actually works.
The Scoring Model: How Each Tech Gets Rated Against a Job
When a new job arrives, the agent doesn't pick the closest available tech. It scores every available technician against every dimension of the job, then ranks them. The winner gets the dispatch.
Here's the full scoring breakdown:
1. Skill Match (weight: 30%)
Does this tech actually know how to do this job? This isn't just "HVAC" — it's the specific capability required.
If a tech can't handle the job's technical requirements, they're excluded entirely — not scored low, removed from the candidate pool.
2. Certification & License Check (binary gate, not scored)
Before scoring even begins, the agent verifies:
- License validity (not expired)
- Insurance certificates current
- Trade-specific certifications valid (EPA 609 for HVAC, journeyman card for electrical, backflow cert for plumbing)
- City/county permits valid for the job location
A tech fails this gate → excluded from scoring. The agent logs why (helpful for the dispatcher reviewing the queue).
3. Distance + Traffic-Adjusted ETA (weight: 25%)
Not "straight-line distance." Real drive time.
The agent pulls:
- Current GPS location (from the mobile app, updated every 3 minutes)
- Live traffic data from a routing API (Google Maps / Mapbox)
- Job time window (e.g., "2pm–5pm")
It calculates: can this tech arrive within the job window, accounting for current traffic?
If not, that tech is deprioritized. If they'd arrive 40+ minutes late even in ideal conditions, they're excluded.
4. Current Job Status (weight: 20%)
Where is this tech right now?
- En route to a job: How close to finishing? ETA to completion estimated based on job type + historical avg duration
- On-site, mid-job: What's the estimated time remaining? (uses job type averages with tech-specific adjustment)
- Between jobs: Available immediately
- At home / not yet started shift: Available from shift start time
A tech 5 minutes from finishing their current job ranks higher than one just starting a 90-minute job — even if the second tech is geographically closer.
5. Shift Remaining (weight: 15%)
Does this tech have enough hours left to complete this job and travel to the next one?
Jobs that would push a tech past their scheduled shift end are flagged, not automatically excluded — the dispatcher reviews flagged assignments.
6. Customer History with This Tech (weight: 10%)
Has this customer been assigned to this tech before? How did it go?
- Previous 5-star job: +10 bonus points (repeat tech is fast — they already know the customer's property, equipment, and preferences)
- Previous 3-star or lower: -15 points (customer explicitly preferred not to have this tech return)
- No prior history: Neutral (0 points)
This is not a dominant factor — but in a close call between two equally-skilled, equally-located techs, it breaks the tie.
7. Equipment & Parts on the Truck (binary gate, then weight: included in job fit)
Some jobs require tools or parts the tech might not have. The agent checks:
- Required tools: Does the tech's vehicle carry what's needed? (e.g., Confined Space Entry cert + harness for sewer jobs)
- Parts inventory: Is the replacement part in stock on the truck? If a job requires a specific compressor model and the tech doesn't carry it, the job gets flagged for the dispatcher — or the tech gets a routed detour to the supply depot first
A Concrete Worked Example
It's 2:00pm. A new job arrives: residential heat pump repair, 1317 Willowbrook Lane, job window 2pm–5pm, estimated 90 minutes.
Candidate techs:
| Tech | Location | Skills | Certs | Current Status | Shift End | Customer History | Parts on Truck |
|---|---|---|---|---|---|---|---|
| Maria S. | 3.1mi / 11min | Heat pump specialist | EPA 609 ✓ | Between jobs (free) | 6:00pm | 3 prior visits, 4.8★ | R-410A 25lb + common capacitors ✓ |
| James K. | 6.4mi / 18min | Master HVAC | EPA 608 Universal ✓ | En route, ETA done 2:15pm | 5:00pm | 1 prior visit, 3.2★ | R-410A 25lb ✓ |
| David L. | 8.2mi / 24min | HVAC + Electrical | EPA 609 ✓ | Mid-job, ETA done 3:15pm | 7:00pm | No history | R-410A 50lb ✓ |
| Priya N. | 2.8mi / 8min | HVAC | EPA 609 ✓ | Between jobs | 4:30pm | No history | R-410A 25lb ✓ |
Scoring:
| Dimension | Maria S. | James K. | David L. | Priya N. |
|---|---|---|---|---|
| Skill Match (30%) | 30 | 30 | 30 | 30 |
| ETA Fit (25%) | 25 | 20 | 8 | 25 |
| Job Status (20%) | 20 | 12 | 0 | 20 |
| Shift Remaining (15%) | 15 | 13 | 15 | 9 (only 90min left vs 90min job) |
| Customer History (10%) | +10 | -15 | 0 | 0 |
| Total Score | 100 | 60 | 53 | 84 |
Winner: Maria S. — 100/100. Available now, closest, known to the customer, has parts.
Priya N. scores 84 — she's very close and available, but she'd be cutting it razor-thin on shift time (90min job + return travel, 4:30pm end doesn't work). Flagged for dispatcher review.
The Routing Math: TSP-Style Optimization, Not Greedy Assignment
Most dispatch systems do this: find the best tech for the next job, assign them, repeat. Greedy next-job optimization.
It sounds reasonable. It isn't.
Here's why: a dispatcher running greedy assignment at 7am might assign techs to early-window jobs that look good in isolation — but collectively, they scatter techs across the city in ways that make 3pm jobs unreachable. You get a technically-correct sequence of individual decisions that produces a catastrophically bad day.
CrewOps does TSP-style optimization. Instead of "who's best for this job?" the question is: "how do we route all available techs across all remaining jobs today in a way that maximizes coverage, minimizes drive time, and leaves zero jobs unserviced?"
The agent solves this as a constrained optimization problem:
This runs at the start of each day (morning optimization pass), then re-solves whenever a significant event changes the state — a job completes early, a tech calls out, a new urgent job arrives.
The output isn't a static schedule — it's a live, continuously-improving route plan that the dispatcher can see and the techs receive via their mobile app.
Why End-of-Day Route Quality Beats Single-Job Optimization
At 7am, you have 40 techs and 80 jobs. The greedy approach picks the best tech for job #1, then job #2, then job #3 — each in isolation. By 3pm, you're left with the hardest jobs (furthest from remaining techs, tightest windows) and the most exhausted techs.
TSP optimization front-loads the problem: it looks at all 80 jobs and all 40 techs simultaneously and solves for the best overall day, not the best next decision.
Exception Handling: The Decision Tree the Agent Walks
Every day throws something unexpected. Here's how the agent handles the five most common exceptions:
1. Tech Runs Long
Trigger: A tech's current job hasn't completed within the expected time window.
Decision tree:
- If ETA overrun < 15 min: flag the tech's next job as "arriving late," auto-update customer ETA via SMS
- If ETA overrun 15–30 min: re-score the tech's remaining route; if downstream jobs are now at risk, propose reassignment to the dispatcher
- If ETA overrun > 30 min: immediately open the tech's remaining jobs for re-bid, notify the dispatcher, and surface replacement options ranked by score
- If the tech marks "job complete" late in the app: close the job, update route, recalculate next-job ETA, push new ETA to the customer automatically
2. Customer Reschedules
Trigger: Customer calls or messages to change the time, or no-shows.
Decision tree:
- If reschedule request: validate against tech availability, check parts inventory, propose a new slot from available options
- If no-show detected (tech arrives, customer unreachable): hold the job open for 20 minutes, notify dispatcher, and assign the tech to a nearby walk-in or emergency job if one exists
- If reschedule creates a gap: leave the slot open; notify the dispatcher of the "tentative" window so they can try to fill it (or leave it as buffer time for the tech's route adjustment)
3. Part Not Available on Truck
Trigger: Tech diagnoses a job and needs a part they don't have.
Decision tree:
- Check nearby supply depots / supply trucks for the part
- Calculate detour time cost vs. sending a different tech who's closer to the supply depot
- If detour is < 45 min: route the tech through the depot, push updated ETA to customer
- If detour is > 45 min: reassign the job to a tech who has the part on their truck; current tech gets routed to next job while supply is sourced
- If no tech has the part: flag for dispatcher, log the part as "unavailable," send customer notification that we'll reschedule once the part is sourced
4. Weather Event
Trigger: Severe weather warning or active storm conditions in the service area.
Decision tree:
- Pull weather API data: active alerts, road conditions by zip code
- If weather affects job zone AND job is non-emergency: defer all jobs in the zone, notify customers with rescheduling CTA
- If job is emergency (no heat, gas leak, water main break): score techs who can still operate in conditions, flag reduced-speed routes
- If roads are impassable: park affected techs, route around weather zones, surface delay ETAs
- Dispatcher sees a unified weather dashboard showing all affected jobs and recommended actions — one-click defer if appropriate
5. Tech Calls Out
Trigger: Tech notifies the system (or dispatcher notifies the system) that they're not coming in.
Decision tree:
- Identify all jobs assigned to that tech for today
- Re-score each job across all remaining techs
- Auto-generate proposed reassignments, ranked by score
- Dispatcher reviews reassignments in bulk via a single approval action
- Customers of reassigned jobs receive an SMS: "Your technician has been updated. [New tech name] will arrive around [new time]. Reply STOP to opt out of SMS."
- If no available tech can cover a job, flag it for the dispatcher to call the customer directly
The Human Override Layer: How the Agent Earns Autonomy
The agent isn't running your dispatch board on day one. Here's how the trust is built:
Phase 1: Shadow Mode (Days 1–14)
The agent watches the board, scores all jobs, and shows its proposed assignments — but doesn't dispatch anything. The dispatcher sees the agent's recommendations next to the human assignments and can compare them.
This is how the agent learns: when the dispatcher overrides, the system logs why. After 14 days, the agent has enough override history to understand when human judgment exceeds its model — and when it doesn't.
Phase 2: Supervised Autonomy (Days 15–30)
The agent now dispatches automatically — but surfaces every decision to the dispatcher in a review queue. Dispatchers can pull back any assignment with one click. Override rate is tracked and reported.
When override rate drops below 5% of total dispatches, the system flags the shop as candidate for full autonomy.
Phase 3: Full Autonomy (Day 31+)
The agent runs the board unsupervised. Exceptions and boundary cases still surface to the dispatcher — the system is conservative about uncertainty. If the agent encounters a situation it hasn't seen before, it defers to the dispatcher automatically rather than guessing.
What's Next: The Roadmap
The current dispatch agent handles real-time job assignment and day-level routing. Here's what's coming:
Multi-Day Planning
The agent currently optimizes today's route. Next phase: it will optimize across a rolling 3-day window, anticipating known demand patterns (e.g., "Thursday the school district has 6 jobs scheduled") and pre-positioning techs to reduce travel.
Predictive Callbacks
Right now, the agent responds to what's happened. The next layer adds prediction: based on job type, equipment age, and seasonal patterns, it will flag jobs with high callback probability before the tech leaves the property — "this capacitor has a 40% failure rate at this age, order the replacement now."
Autonomous Customer Communications
Today, the agent sends ETAs and rescheduling notifications. Soon: it will handle customer confirmations, no-show follow-ups, and post-job satisfaction checks — all without dispatcher involvement. Dispatchers review the message log, not the composing.