❝ A Melbourne pest control company runs 2,400 recurring contracts with 14 technicians. Every Friday afternoon the operations coordinator builds the following week's runs in a spreadsheet, working from a service-due report, which takes her about 12 hours a week. Because she schedules by due date rather than by geography, the average gap between jobs is 37 minutes. The design below extracts scheduling constraints from free-text site notes, hands them to a routing solver, and returns the week for human approval. Average travel falls to 24 minutes, jobs per technician per day rise from 5.8 to 6.9, and two planned hires are no longer needed. The agent costs about AUD $290 a month.

Dianne builds next week on a Friday afternoon. She exports the service-due report out of ServiceM8, which tells her which of the 2,400 contracted sites fall due in the coming fortnight, and she starts putting names against days.

The report is sorted by due date. So Dianne schedules by due date. Tuesday's list for one technician reads Footscray, Box Hill, Footscray again, Dandenong. Every one of those jobs is legitimately due that week. The order they appear in is simply the order the system printed them.

The technician drives 148 kilometres to complete five and a half hours of work.

The business

A pest control company in Melbourne's inner west. Fourteen technicians, AUD $4.2M in revenue, split roughly 60/40 between commercial contracts (restaurants, aged care, food manufacturing, body corporates) and residential recurring plans. Around 2,400 active contracts, each with a service frequency: monthly, quarterly, six-monthly, annual.

The tool stack is ordinary and mostly adequate. ServiceM8 holds the jobs, the sites, the contract frequencies and the technician timesheets. Xero handles invoicing. Site-specific instructions live in the ServiceM8 notes field, which is where this story actually takes place.

What is actually going wrong

The obvious diagnosis is that nobody is planning routes. That diagnosis is wrong, and it is worth being precise about why, because it is the reason this problem has survived three attempts to fix it.

Dianne knows perfectly well that Footscray, Box Hill, Footscray is a bad Tuesday. She has known it for four years. She schedules that way anyway, because clustering the jobs geographically requires her to hold, simultaneously, about nine things per job that are not in any structured field:

  • The restaurant in Richmond can only be treated after 5pm, which is in the notes.

  • The aged care facility needs 48 hours of written notice, which is in the notes.

  • The termite job needs a technician holding a current timber pest licence, and four of the fourteen hold one.

  • The external perimeter treatment cannot be done in rain, and Melbourne has opinions about that.

  • The follow-up at the Preston bakery has to fall between 10 and 14 days after the initial treatment, and the initial treatment date is in a job record, not a calendar.

  • The body corporate at Docklands wants the same technician each visit, which somebody agreed to in an email in 2024.

None of that is in a field a computer can read. It is in prose, written by fourteen different people over six years, in a box labelled Notes. The scheduling problem was never a mathematics problem. Routing software has solved the mathematics since the 1960s and you can rent it for the price of a phone plan. The problem is that the constraints the mathematics needs have never been written down anywhere a solver could reach them.

So Dianne does it in her head, and because doing it in her head is expensive, she does the cheap version: sort by due date, fill the days, send it out.

What it costs

Average travel time between jobs is 37 minutes. Each technician completes an average of 5.8 jobs a day across six travel legs, which puts roughly 3.7 hours of every eight-hour day inside a vehicle.

The company had costed two additional technicians for the coming year, at approximately AUD $78,000 each once vehicle, licensing, insurance and training are loaded in. That was the plan for absorbing contract growth, because the existing fourteen were visibly at capacity.

Separately, 173 services last year were completed outside their contracted window. Most produced nothing worse than an apology. One produced the loss of a commercial contract worth $22,000 a year, when a food manufacturing client failed an audit partly because their most recent pest report was 11 days late.

And Dianne spends 12 hours a week building runs. She is an operations coordinator being paid to be a scheduling algorithm with a worse memory than an actual one.

The design

The important decision in this design is which part of it is the AI. The model does not choose the routes. Route selection is a solved arithmetic problem with a correct answer, and a language model is a poor way to find it. The model does the thing the solver cannot do, which is read six years of English prose in a notes field and turn it into constraints.

Trigger. Thursday, 16:00. The agent pulls every service falling due in the next 14 days from the ServiceM8 API, together with each site's notes, contract terms, prior job history and location.

Stage 1, constraint extraction. For each job, a language model reads the free text and returns a structured object: earliest and latest permissible date, access window, licence required, estimated duration, weather dependency, whether the visit is tied to a prior treatment date, and whether a named technician is required. Every field carries a confidence score. This is the only stage where a model makes a judgement.

Stage 2, feasibility check. Deterministic code validates the extracted constraints against structured ServiceM8 fields, the technician licence register and van stock levels. Contradictions and low-confidence extractions are pulled out into an exceptions list rather than guessed at.

Stage 3, the solve. A vehicle routing solver receives the validated job list, the technician roster with licences and start locations, and a cached distance matrix. It returns fourteen daily runs for the week that respect every hard constraint and minimise total travel. Jobs it cannot place are returned with the binding constraint named.

Checkpoint, human review. Dianne receives a review sheet on Friday morning: the proposed week, the total travel time against last week's, and every unplaced job with the reason it could not be placed. She moves what she wants to move and approves. This is the point of the whole design. She is deciding, rather than assembling.

Stage 4, write-back. Approved runs are written to ServiceM8 as scheduled jobs. Technicians see next week in the app. Customer confirmations go out on the existing ServiceM8 templates.

The loop that matters. Every manual move Dianne makes at the checkpoint is logged with her reason and written to a persistent constraint store against that site. The Docklands body corporate wanting the same technician stops being something Dianne remembers and becomes something the solver is told. The system gets more accurate every Friday, which is the opposite of how the spreadsheet behaved.

The Monday morning test

On the first Monday after go-live, two things should be true. Any technician's run should sit inside one or two adjacent suburbs for the whole day. And Dianne should not have opened the spreadsheet on Friday afternoon. If she opened it, the constraint store is missing something and the exceptions list will tell you what.

Before and after

Measure

Before

After

Average travel between jobs

37 minutes

24 minutes

Jobs per technician per day

5.8

6.9

Coordinator time building runs

12 hours a week

90 minutes a week

Services completed outside contract window

173 a year

20 to 30 a year

Technicians needed to absorb growth

2 planned hires

0

Fleet distance

Baseline

About 105,000 km a year lower

The build guide

Recommended stack. n8n for orchestration, an LLM API for constraint extraction, Google Maps Routes API for the distance matrix, and a vehicle routing solver. For a fleet of this size, a self-hosted OR-Tools service on a small virtual machine is the cheapest solver and takes a competent developer about three days to stand up. A hosted routing API is faster to integrate and costs more per month.

Architecture pattern. Extract, validate, solve, review, write back. Deterministic code sits on both sides of the model, and the model's output never reaches the customer without passing a human.

The n8n nodes, in order. Schedule Trigger (Thursday 16:00). HTTP Request to ServiceM8 for jobs due, sites and notes. Code node to normalise and deduplicate. LLM node with a structured output schema for constraint extraction, batched about 25 jobs per call. Code node for validation and the exceptions split. HTTP Request to Google Maps Routes API, reading from and writing to a cached matrix. HTTP Request to the solver. Google Sheets node to write the review sheet. Webhook node waiting on approval. HTTP Request to ServiceM8 for write-back. Slack node for the Friday summary.

Build steps. Week one, define the constraint schema and iterate the extraction prompt against 200 real site notes until the confidence scoring is honest. Week two, integrate the solver and the distance matrix cache. Week three, build the review sheet, the approval webhook, the write-back and the constraint store. Run in parallel with the spreadsheet for a fortnight before switching.

Estimated build time. 60 to 80 hours. The constraint schema is where the time goes, and shortening that week is a false economy.

What it costs to run

Component

Monthly (AUD)

n8n cloud

$50

LLM API, constraint extraction

$45

Google Maps Routes API, cached

$120

Solver VM

$25

Monitoring and error alerting

$50

Total

$290

Year one, including an outsourced build at the upper end, lands around $15,000. The two deferred hires alone are $156,000, and the fuel and vehicle running cost of 105,000 fewer kilometres is roughly $29,000 a year.

Failure modes and edge cases

The model is confidently wrong about an ambiguous note. "Check with Pete before attending" is not a constraint the model can resolve. Set a confidence threshold and route anything below it to the exceptions list. An unplaced job is a small annoyance. A technician arriving at a locked food factory at 7am is not.

A mathematically perfect route that breaks an unwritten rule. This will happen in week one and it is the reason the constraint store exists. If Dianne's corrections are not being captured and reused, you have built a system that makes the same mistake fifty times.

Distance matrix costs rising with the book. A full matrix across 2,400 sites is expensive and mostly wasted. Pre-cluster by postcode, request matrices within and between adjacent clusters only, and cache aggressively. Site locations rarely move.

Weather. External treatments cancelled on a wet Tuesday will cascade through the rest of the week. Build a partial re-solve that takes the remaining days and the displaced jobs, rather than rebuilding the whole week and disrupting runs that are working.

Partial write-back. If the ServiceM8 write fails halfway, you have half a scheduled week and no clear record of which half. Stage the whole week to a holding structure, verify it, then commit.

Technicians who feel managed by software. A route that arrives without explanation reads as surveillance. Publish each technician's travel time weekly against the fleet. People who can see the hour they got back tend to stop objecting to where it came from.

The arithmetic

The agent costs $290 a month. It returned the equivalent of two technicians the company had already budgeted for, gave an operations coordinator back most of a working day and a half every week, and cut 105,000 kilometres a year out of a fourteen-van fleet.

None of that came from better routing software. The routing software was always available. It came from writing down the rules that had been living in a notes field and a coordinator's memory, which is the part everybody skips because it is not the interesting part.

Your industry is probably already in the back catalogue. One bottleneck, mapped end to end, every week, free to read and precise enough to build from. Subscribe here. If your workflow is not in there yet, raise your hand and it can be the next one we map.

Keep Reading

View more