AI feature opportunities in MEP and specialty contractors, and the data each one needs

Mechanical, electrical, plumbing, fire protection, low voltage. Field workforce, a mix of new construction and service work, an estimating system and an accounting system that were bought a decade apart. Small shops belong here too, where the owner does the estimating and the whole estate is an accounting file, a scheduling app, and a spreadsheet.

Established shops with an estimating system and a job cost system.

Job cost bleed alert

In one line: Tells the PM on Monday which job is losing money this week, by cost code, instead of at job close.

Who uses it and when: the PM, every Monday, on a short list of jobs running over by cost code instead of a report that lands after the job closes. It changes one decision: whether to pull a crew off a job or check in with the foreman this week.

What it does not do: it will not tell you why a job is bleeding, whether that is a bad estimate or a slow week. It tells you which job, early enough to still do something about it.

Usually needs work.

It depends on labor hours that are already being captured. The cost code on them often is not, and the estimating system uses a code structure accounting never adopted. Nothing new has to be built. A field becomes required, one code list wins, and until enough weeks have accumulated under the new rule the comparison runs on partial history.

The pain: “By the time the job cost report shows a problem, the labor is already spent and the job is 80 percent done.”

What it runs on
  • One row per: one labor hour block. One employee, one job, one cost code, one day. This is the whole feature. A daily lump sum with no cost code cannot be compared to anything.
  • Described by: employee or crew, foreman, job, cost code and phase, date, customer, general contractor, work type (new construction versus service), labor class.
  • Must agree across systems: the cost code list and the job number. The estimator’s cost codes and accounting’s cost codes have to be one list, or the estimate and the actuals cannot be lined up.
  • History: you need the original bid hours by cost code preserved, plus every change order with its date. Rates and crew composition change through a long job and need to be dated too.

Why it usually fails: two things, both fixable. Field time comes in as “8 hours, job 412” with no cost code, so there is nothing to compare to the estimate. And the estimating system uses a cost code structure the accounting system never adopted, so the two halves of the comparison are speaking different languages.

Service call triage and parts prediction

In one line: Predicts what the technician will need on the truck before it rolls, based on the equipment at that site and what has failed there before.

Who uses it and when: the dispatcher, when the call comes in, on a short parts list attached to the work order before the truck leaves. It changes one decision: which parts ride along on the first trip instead of the second one.

What it does not do: it will not diagnose the failure. It predicts what has failed at that site before, not what is wrong this time.

Usually needs building.

It depends on equipment history that is not tracked as a record anywhere, only as an address and a note in the work order text. The signal it runs on, that this same unit has failed four times, does not exist in any system yet. Standing up an equipment register and back-filling it from work order text is the project. The feature is what happens after it.

The pain: “Half our second trips exist because the tech got there and did not have the part.”

What it runs on
  • One row per: one line on a work order. One part consumed or one labor entry, on one visit. Keep the visit identifier on the row so a visit can be reassembled, but do not model the visit itself as the core record.
  • Described by: customer, site, the specific piece of equipment (make, model, install year, serial), technician, date, call type, contract versus time and materials, part.
  • Must agree across systems: customer, site, equipment, and part. A customer with twelve buildings is twelve sites, and each site has its own equipment. If site is just an address string, this feature cannot exist.
  • History: the equipment record needs history. Units get replaced, buildings change hands, and a rooftop unit installed last year is not the one that failed four times before it.

Why it usually fails: the equipment is not tracked as data at all, only an address and a note in the work order text. So there is no way to see that the same unit has failed four times, which is the entire signal. Close second: parts get pulled off the truck and never tied back to the work order, so consumption history is guesswork.

Bid and no-bid guidance

In one line: Shows which kinds of work you actually win and at what margin, so estimators spend their hours on the pursuits worth chasing.

Who uses it and when: the estimator, when a new invitation to bid arrives, on a short read of how similar work has scored before: won, lost, and at what margin. It changes one decision: whether this one is worth the hours to price.

What it does not do: it will not bid the job. It shows the pattern in what got won and what it made; the estimator still decides.

Usually needs work.

It depends on bids that are already tracked when they are won. Lost and no-bid submissions get deleted to keep the pipeline clean, so only winners remain, and a won bid is never linked to the job number it became. Nothing new has to be built. Losses stop getting deleted, and the win-to-job link gets made, then losing bids accumulate long enough to compare against wins.

The pain: “We bid everything that comes in because nobody can tell us what we are good at winning.”

What it runs on
  • One row per: one bid submitted, at one version. Losses count as much as wins. A bid with no outcome recorded is a wasted row.
  • Described by: general contractor or owner, market sector, geography, estimator, bid date, job size band, delivery method, outcome (won, lost, no bid, withdrawn).
  • Must agree across systems: the GC or customer, the market sector list, and the link from bid to job. When a bid is won it has to point at the job number it became.
  • History: today’s picture is mostly fine here, with one exception. The bid amount as submitted must never be edited. Freeze it and record revisions as new rows.

Why it usually fails: lost bids are never entered, or are deleted to keep the pipeline clean. The data then contains only winners, and any pattern about what you lose is unrecoverable. The second failure is that a won bid never gets linked to the resulting job number, so nobody can compare bid to actual, ever.

Small shops: an accounting file, a scheduling app, and a spreadsheet.

Job profitability review

In one line: Tells you which of the jobs you finished last month actually made money, while you can still change what you quote on the next one.

Who uses it and when: the owner, at month end, on a ranked list of last month’s jobs by what they actually made instead of a bank balance that moves for no visible reason. It changes one decision: what the next quote for that kind of job looks like.

What it does not do: it will not requote the next job. It shows which jobs made money and which did not; the owner still sets the number.

Usually needs work.

It depends on job costs that are already tracked, one line at a time. The owner’s own hours are the exception: they never get entered, because nobody invoices themselves, so the jobs the owner worked hardest look the most profitable. Material bought on a supplier account gets coded to the supplier instead of the job too. Nothing new has to be built. Both have to start getting logged against the job they belong to.

The pain: “The bank balance goes up and down and I could not tell you which jobs are the reason.”

What it runs on
  • One row per: one cost against one job. One block of labor, one material purchase, one subcontractor invoice, one equipment day, each tied to the job it belongs to. Paired with one row per line billed on that job.
  • Described by: job, customer, job type (service call, small project, new install), who did the work, date, cost type (labor, material, sub, equipment), and how the job was priced (time and materials, flat rate, quoted).
  • Must agree across systems: the job. There has to be one job number that the scheduling app, the invoice, and the accounting file all carry. A customer name is not a job number, because the same customer comes back, and when the name is the only key, five separate jobs quietly merge into one and the good ones cover for the bad ones.
  • History: today’s picture is mostly fine. Two exceptions. Freeze the quoted price when the quote goes out and record any change as its own line. And date your labor rates, because they move and last year’s jobs were done at last year’s.

Why it usually fails: the owner’s own hours never get entered, because nobody invoices themselves. Labor is then understated on exactly the jobs the owner worked hardest, which are the difficult ones, so the hardest jobs come out looking like the most profitable and the shop goes and quotes more of them. Second cause: material bought on a supplier account gets coded to the supplier rather than the job, so material cost lands in one overhead lump and every per-job margin is off by an amount that varies with how material-heavy the job was.

Whether any of these are buildable comes down to the same three steps in every industry, and they are on the index.

Book a discovery call