Problem
Small service businesses lose leads when quotes are slow, and lose margin when prices are inconsistent. Pricing often lives in one person's head, with no record of why a number was given.
Research & analysis
I started with what actually drives a service quote for a single contractor: labour, job category, whether the customer is a repeat client, and the season. Those factors already sit in the business's past quotes, so the pricing should be learned from that history, not invented.
Three conclusions shaped the product:
- A price must be explainable and repeatable. A customer-facing number cannot come from open-ended AI generation, so AI was excluded from pricing entirely.
- Weak data should produce a refusal, not a guess. When the history doesn't support a confident price, the honest output is "can't quote this automatically".
- A pilot needs a narrow scope. One contractor, no payments, no automated emails. Fewer moving parts meant the core workflow could be tested properly.
Solution
- Estimate request intake: a mobile-friendly form with consent capture and spam protection.
- Deterministic pricing fitted from the business's own historical quotes, with six confidence checks that must pass before a price is returned.
- An explicit approval workflow: every quote moves from draft to awaiting approval to approved before it can be shared, and every step is recorded.
- AI limited to wording. An optional assistant can polish the quote text, but it never sees customer details and never touches the price.
- Output that fits existing tools: branded PDF quotes, CSV export, and a preview-first import for historical quote data.
Build
A Flask app with SQLite storage, served by Waitress. A deterministic pricing engine fits labor cost, category markup, repeat-customer discount, and seasonal effects from validated historical quotes, then applies six confidence gates before returning a price — a failed gate produces a refusal instead of a fabricated number. Every quote moves through an explicit approval state machine (draft → awaiting approval → approved → shared → accepted/rejected/expired) with an audited event history, and an optional Anthropic-powered wording assistant can polish quote text without ever touching pricing or customer data.
AI-assisted development was used for implementation; I defined the requirements, the pricing rules, the approval step and the acceptance criteria, and verified behaviour with 18 automated tests covering the pricing engine, the optional AI wording client, and the web app.
Result
A working local build with 18 automated tests. It currently runs on synthetic demo pricing history, and it has not yet been used by a real business, so no time or revenue savings are claimed. Current status: pilot candidate.
Next step: a controlled pilot with one contractor. Import their historical quotes, then compare the engine's prices against the quotes they actually sent.
What I learned
Knowing when not to answer is a feature. A pricing tool that refuses when its data is weak is more trustworthy than one that always produces a number.
Adoption depends on the data more than the interface. The engine is only as good as the business's own quote history, so the import-and-validate step matters as much as the quote screen.
AI belongs where mistakes are cheap. Polishing the wording of a quote is low-risk; setting the price is not. Drawing that line early kept the design simple and the output defensible.