In production
Plan sets to priced draft bids
Commercial fencing contractor. Bid aggregator, PDF plan sets, CRM.
Situation
Public and commercial jobs post to a bid aggregator every day, each with a plan set that runs to hundreds of pages. One estimator owned all of it: open the drawings, find the fence, measure it sheet by sheet, price it, and write the proposal. The company bid on the jobs one person could get to, and the rest went by.
What we built
An agent watches the company's saved searches, downloads each new plan set, and decides against the company's own rules whether the job is worth bidding. When it is, it finds the fence on the drawings, measures it, prices it, and emails the estimator a draft bid on the company's own template and letterhead. Jobs it passes on arrive in a daily digest with the reason. The estimator reviews, adjusts and submits.
How it works
Footage is measured, not read. The agent traces the fence and code measures it against the scale on the title block; printed quantity tables are never trusted.
A sheet's footage counts only if the measuring tool produced it in that run. Anything else is labeled an estimate, a gate added after an early version repeated a known answer instead of measuring.
Pricing is code: a fixed price book and a crew-day model. Taking it out of the model cut run-to-run price swing on the same job from about 20% to 3.5%.
Only a qualified job triggers a bid, and the decision is made in code. Every send is checked against the expected recipients before it counts as delivered.
Impact
38
draft bids delivered to the estimator in ten weeks, $6.86M of total bid value, from 347 projects screened.
326
plan sets read end to end, about 180,000 pages, with a median set of 422 pages.
+2%
against the estimator's own count on an 18-sheet civil job, 7,474 feet to his 7,328, with his answer withheld.
Bids are priced from the standard price book, not vendor quotes, and the estimator finishes them. The accuracy test is the job the method was tuned on. Submissions and wins are not yet tracked.
Have a function like this one?
Tell us where you would start and we will tell you what it would take.