Property turnover estimate
Tektolo prices with a deterministic, source-cited engine. You turn what the user has (an
inspection report, photos, notes) into findings. The engine returns standardized tasks
by trade, regional low / expected / high costs, priorities, vendor scopes, refer-outs, and
every assumption it made. The rules always decide; an AI model (gpt-6-luna on Microsoft Azure
OpenAI) may only read the user's words into findings, and you always see what it read.
quick_estimate reads words the matcher cannot place with the AI model. scope reads with
the matcher alone unless you send read: "ai". An answer that used an AI reading is a draft
(review.status: "draft") and carries reading: every finding the rules answered, in the
shape scope accepts. The same findings under the same ruleset give the same result
(result_hash), but a reading can differ from one run to the next, so show the user the
findings the AI read before you quote a number.
When to use
- Move-out or turnover inspections, make-ready planning, "what will this turn cost", "what do I send the painter", owner approval estimates.
- Re-running an estimate with the owner's approve/decline decisions or the manager's own vendor prices.
When not to use
- Diagnosing mold, asbestos, lead, gas, electrical or structural hazards. The engine flags these for a licensed professional; do not price their remediation yourself.
- Legal advice on deposits or tenant charges. Responsibility labels are hints only.
- Remodels, new construction, non-US properties.
How to call it
- MCP (preferred in assistants): add the remote server
https://tektolo.com/mcp. Start withproperty_turnover_quick_estimate(zip, bedrooms, bathrooms andissuesas plain strings); useproperty_turnover_scopefor rooms, measured quantities, rate cards and decisions.property_turnover_issue_codeswith no arguments lists the areas and codes. If the ZIP is missing or not 5 digits, ask the user; never guess it. For the Excel or owner estimate, give the userlinks.web_tool_prefilledfrom the result. - REST:
POST https://tektolo.com/v1/property-turnover/scopewith the JSON below. Downloads:POST .../scope/render/xlsx(workbook),.../render/html(owner estimate),.../render/csv(work orders),.../render/vendor_csv(zip of per-trade scopes),.../render/bids_html(work lists for bids: one section per trade, no prices). - Catalog and schemas:
https://tektolo.com/catalog.json,https://tektolo.com/capabilities/property-turnover. - Web: the free tool is
https://tektolo.com/tools/rental-property/property-turnover; typical costs by area are athttps://tektolo.com/turnover-costs/. - Next step: the scope is step 1 of the move-out workflow; step 2 settles the security
deposit (
deposit_settlement_settle, web tool/tools/rental-property/deposit-settlement).
Building the request
- property:
zip(5 digits, never a street address),bedrooms(0 = studio),bathrooms(halves as 0.5), and if knownsq_ft,year_builtandunit_type. Year built matters: pre-1978 triggers lead-safe-work handling (priced).unit_typesingle_familyortownhomegets house-sized defaults (floor area, lock count, yard). If you know whether there is carpet, sendfloor_coverings:{"carpet_present": true}or{"carpet_sq_ft": 600}. Without it, carpet findings imply carpet; otherwise whole-unit carpet cleaning is left out and listed inunknowns. - findings: one per observed condition.
- Use
codewhen you know it (e.g.walls.nail_holes,carpet.pet_urine), otherwise a short plaindescription("dog urine stains in bedroom carpet"). Words the matcher cannot place come back as a manual-quote line withsuggested_codes; resend with a code. Withread: "ai"they go to the AI reader first: a finding it reads comes back withresolution: "ai"andneeds_review: true, its lines are flagged, and the answer is a draft. A finding sent with a code never goes to the AI model. - To confirm what the AI read, send the findings from
reading.findingsback toscope(keep each finding'sextraction, fix any the user corrects) withconfirmed: trueon each one the user checked. The answer is thenverified, and the result still shows those findings as read by AI. location.area(bedroom, bathroom, kitchen, living_room, ..., whole_unit) and an optionallabel("Bedroom 2").extent:spot|partial|fullwhen you can tell.quantity{value, uom}when measured (sq_ft,sq_yd,linear_ft,each,room, ...). Otherwise typical sizes are assumed and listed.
- Use
- standards.profile:
minimum|standard(default) |premium. Optional overrides:paint_policy,carpet_policy,cleaning_policy,always_rekey,markup_pct.standards.price_tier:pm_vendor(default, a manager buying from local vendors) |bulk_contract(portfolio contract prices) |retail_one_off(an owner hiring one contractor). - Optional:
rate_card(the manager's prices:{task_id, unit_price, uom?}or{trade, min_charge, trip_charge}; whole-unit wall paint is persq_ft_floor, so senduomto have a mismatched price rejected rather than misapplied),trade_vendors,tax_rate, anddecisions({finding_id | line_id, action: approve|decline|defer}). Re-run with decisions to get the approved scope. detail: MCP defaults tosummary(totals, trade scopes, every line tied to a finding, refer-outs, notes; routine lines summed inomitted_note). Ask forfullwhen the user needs every line. A finding'slocationmay be a plain string ("Bedroom 2"). Hedged notes ("mold?") come back as "check first" refer-outs that hold no work until confirmed.
From photos
Tektolo does not look at photos. You do, then you send findings and the engine prices them.
- Describe only what is visible, one finding per condition. Give its location (the room or
area) and what it is. Use an issue code when one clearly fits (look it up with
property_turnover_issue_codes); otherwise write a short plaindescription. - Give
extent(spot,partialorfull) only when the photo shows how far it goes. Otherwise leave it out and say so in your reply. - If you are not sure what a photo shows, or how far damage goes, hedge the description
("possible water stain on bedroom ceiling", "mold?"). The engine marks hedged findings
uncertain: their lines are priced but kept out of the totals (totals.to_confirm) until someone confirms them, and hedged safety items become check-first refer-outs. You can also ask the user for a better photo or a closer look. - Ask the user about what photos cannot show, and do not guess it: whether appliances and
fixtures work, odors and smoke, pests, and size or extent (square feet, counts). Send a
quantityonly when the user gives you a measurement or a count. - Never write that the tenant caused something because of a photo. A photo shows a condition,
not who caused it. Leave tenant fault out of the descriptions: the
responsibility_hinton each line comes from the engine and is only a hint. - A photo of a written checklist or inspection report is different. Transcribe what it says, as it says it, one finding per entry, and do not add your own reading of the rooms.
- Never send faces, names, addresses or other personal details. Describe the room, not the people or the street.
- Mention what you could not see in your reply, and list what you asked the user to confirm.
Example
{
"property": {"zip": "28205", "unit_type": "apartment", "bedrooms": 1, "bathrooms": 1, "year_built": 1998},
"findings": [
{"code": "walls.nail_holes", "location": {"area": "living_room"}, "extent": "spot"},
{"description": "carpet heavily soiled in bedroom", "location": {"area": "bedroom"}},
{"code": "safety.smoke_alarm_missing", "location": {"area": "bedroom"}}
],
"standards": {"profile": "standard"}
}
Relaying the result
- Lead with
summaryand the expected total plus the range. Say clearly that these are estimate ranges, not quotes. - Call out every
refer_outsitem and what professional to engage. Quote-required lines are $0 in the totals;totals.allowancesis a budget range for them, outside the total. - A
responsibility_hintofmixedmeans the line carries wear and damage findings; see itsresponsibility_by_findingbefore discussing tenant charges. - List
unknownsand the importantassumptions(e.g. assumed room sizes, national prices used), so the user can correct them and re-run. - When
review.statusisdraft, show the user what was read (reading.findings: the words, the item and the room) before you quote a number, and ask them to confirm or correct it. For a verified answer, send the confirmed findings toscopewithconfirmed: true. - Name every finding with
needs_review: the AI reader read it from the user's words, so ask the user to confirm it. Areview.notemeans the reader was not available (daily limit or an error) and the text was read by the matcher alone. - Group the work by
trade_scopeswhen the user wants to brief vendors. Offer the workbook or vendor CSV downloads. - If the user needs an audit trail, keep the
result_hashandrun.ruleset_version. Over MCP they come back only when you call withaudit: true(REST always returns them). - If a call says the daily free limit is reached, tell the user when it resets (the message names the time) and do not retry. On a hosted assistant (Claude, ChatGPT) the shared server URL has one limit for everyone; the message names the page for a free personal connector URL. Volume and integrations go through the Contact page.
Make it yours
Fork this skill and add your company's standards (default profile, paint/carpet rules,
markup), your rate_card, and your trade_vendors, so every estimate uses your prices
and vendors.
