My renovation cost tool ships with an empty price book. Out of the box, it will not price a single line. I think that is the most useful design decision in the whole project, and I expect some of you to disagree.
The setup
I build HousingWizard, a set of open source agent skills for home buyers. One of them takes a floor plan image and turns it into a checked plan, a list of quantities (floor area, wall length, stair counts), a cost range, and per trade quote packages you can send to contractors.
The obvious way to build this in 2026 is to hand the floor plan to a model and ask it for a budget. It would answer confidently. It would probably even look reasonable.
I split the job instead:
- A model may transcribe the plan and explain a result.
- Every quantity, price and rule answer comes from deterministic Python with no dependencies.
The release notes say it in four words: no AI in the numbers.
What "empty" actually means
This is the default price book, the whole file:
{
"schema": "housingwizard.costbook/1",
"name": "My costbook",
"entries": []
}
Every price has to be added by the buyer. Each entry needs a source, a date someone looked at it, a kind, and a license:
{
"id": "quote-floor-001",
"kind": "quote",
"item": "Refinish oak floor",
"unit": "sf",
"value": 4.5, "low": 4.0, "high": 5.0,
"source": "Name of the contractor or shop, quote number",
"source_url": "file:quote-q1.pdf",
"checked_on": "2026-10-01",
"license": "own-quote"
}
(That entry is an example from the docs. Example entries are labeled "example, not a price" and the tool never uses them.)
The allowed kinds are short: a quote you received, a retail price you looked up yourself with the URL and date, public wage data from the US Bureau of Labor Statistics, your own measurement, or a placeholder clearly labeled as an assumption. Numbers copied from paid or scraped estimating sites are refused, even if you retype them.
If a takeoff line has no matching entry, it stays unpriced. It does not get a "typical" number.
Why I did it this way
A number feels like a fact. If a tool tells a first time buyer "refinishing floors: about $X," that number travels. It goes into a spreadsheet, then into an offer, then into a conversation with a partner. Nobody remembers it came from a model that had never seen a contractor's quote in their zip code.
A model is a great reader and a bad source. Reading a floor plan image is exactly the kind of messy job models are good at. Inventing a unit price for labor in a specific city is exactly the kind of job they will do confidently and wrongly. So the model gets the reading job, and a person signs off on it. If nobody confirmed the overlay, every output is marked UNCONFIRMED, and there is a flag that refuses to write outputs at all until someone does.
Wages are not prices. This one surprised me while building it. BLS wage data is public and easy to use, so it is tempting to multiply hours by wage and call it labor cost. But what a worker earns is not what a contractor charges. So the tool shows a BLS wage as a floor and never adds it to the total.
Determinism makes bugs boring. Because the math is plain Python, a bug is a stack trace, not a vibe. One I fixed recently: a stair with no usable destination and no riser count had a quantity of None, the JSON was written fine, and then the printed summary crashed with a TypeError. Annoying, but I could write a test for it in a few minutes. I do not know how I would write a regression test for "the model priced the stairs a bit high this time."
What it costs me
I want to be honest about the downside, because it is real.
The first run is underwhelming. You give it a floor plan and it gives you quantities and a lot of blanks. There is even a "fill in before sending" checklist listing what your inputs left empty. Nothing on that list gets filled in for you. Compared to a chatbot that hands you a full budget in ten seconds, this feels like homework.
The tool has also only been tested on fixtures. I have not validated it on real plans with real buyers, and I do not know yet whether the quote packages actually get contractors to send itemized quotes. That is the open question the project is built to answer, and it has not been run.
So I am betting on something I cannot prove yet: that a buyer would rather see "unpriced" than a confident number they cannot trace.
Where I think this generalizes
I suspect this split applies well beyond home renovation. Anywhere a number turns into a decision (budgets, medical dosing, tax estimates, SLAs), the model should probably read and explain, and something boring and testable should compute. The model's output becomes an input a human confirms, not an answer.
But I also notice the market is moving the other way. Most AI tools I see compete on how complete the first answer looks.
The repo is HousingWizard if you want to see how the split works in practice.
My question for you
If you are building with LLMs, where do you draw the line on what the model is allowed to produce directly? Have you shipped a tool that shows blanks instead of estimates, and did users accept it, or did they leave for the tool that just gave them a number?
Top comments (0)