Four Filters and a Human
Freight coordination, stripped down, is a matching problem buried under email. An offer lands in someone’s inbox — a load that needs to go from here to there, by a certain day. Somewhere out there is a contractor with a truck the right size, near the right area, willing to take it. The coordinator’s job is to read the offer, work out who could plausibly haul it, and get a request in front of them before someone else does. Then wait for quotes.
Done a hundred times a day by hand, that’s a great deal of reading and re-typing. The question worth answering was how much of it a model could take off people’s plates without taking the decisions away from them.
This was a couple of years ago, when GPT-4 was the cutting edge — cutting edge, but not the quiet, capable thing we now hand whole workflows to. It could read an email and tell you reliably what was in it. It could not yet be trusted to read an email, decide what to do, and act on its own. So the design question was never “can the model do this.” It was “how much should it do before a human looks.”
The answer was a sieve.
On-prem, on purpose
Everything ran self-hosted, on the company’s own hardware, and that was deliberate on two counts. First, the data: real commercial offers, contractor relationships, prices — not the kind of thing you send to someone else’s servers without a good reason. Second, cost: API calls and rented compute at volume add up quickly, and hardware already in the building doesn’t bill you every month.
I built the store on SQLite. Not as a scaling decision but a development one — it let me move fast, reshaping the schema as I learned what the data actually looked like, with no server to stand up and no migration overhead. Two FastAPI services carried the logic. Simple, self-contained, easy to reason about.
The sieve
The system was four filters in a row, each letting through less than the last.
The first asked one question: is this even an offer? Most email isn’t — replies, newsletters, internal back-and-forth. Deciding that cheaply and up front meant the rest of the pipeline only ever ran on messages that were actually loads.
The second read the offers that survived and pulled out what mattered: the type of freight, the destination, the timing, the truck size it needed, the area it touched. This is where GPT-4 earned its place, once the prompting accounted for the edges. Freight email isn’t written for machines — it’s terse, abbreviated, half in shorthand — and most of the work was getting the extraction to handle the ways people actually write.
The third stage took the structured offer and narrowed the field to the contractors who could realistically take it: right truck, right region.
And then it stopped, because the fourth filter was a person.
The green light
Nothing left the building on the model’s say-so. The extracted details were written back onto the email itself, as tags in Exchange, so a coordinator saw what the system had understood right there in their normal inbox — no second app, no new screen to learn. If it looked right, they tagged the email to approve it, and that tag was the green light. Only then did the request go out, from a consistent template, to every viable contractor at once.
That was the shape I wanted: the machine sifts, the person decides, the machine dispatches. The judgment stayed with the people accountable for it; the repetitive reading and typing didn’t.
What the summaries showed
The system also reported on itself. On a regular cadence it produced a summary for management: which AI-drafted requests had gone out, which emails had been tagged, and how active each coordinator had been. It made the pipeline visible — useful for seeing that it was working, and where it wasn’t.
In hindsight
I’ve been writing lately about how software has never been softer — how agents made everything fast and malleable. This project sits on the other side of that line. Two years ago you couldn’t just ask a model to run the loop; you had to build the loop yourself, filter by filter, and decide by hand exactly where a person needed to stand. That structure was the real work, and it’s the part I’m still glad I got right. The models keep improving. Knowing where to let one act, and where to make it wait, has aged better than any single prompt I wrote.