name: contract-estimate-builder description: "Contract Estimate Builder for Graeham Watts. Turns a plain-language list of property work tasks into a clean Excel bid sheet (with auto-calculating formulas) plus a PDF scope of work (with a comprehensive courtesy disclaimer) that can be emailed to a contractor for pricing or shared with a client. Trigger ANY time the user mentions: contract estimate, contractor bid, scope of work, SOW, bid sheet, contractor quote, send to contractor for pricing, itemize a job, itemize landscaping/repairs, write up the scope, punch list, prep list, listing prep scope, vendor scope, handyman/landscape/painter/cleaning scope, bid request, or RFQ. Also trigger when the user describes work tasks at a property and wants them organized for a contractor to price, mentions alternative options that need separate pricing (bark vs. flagstone vs. mulch), or says 'put this in a spreadsheet for my contractor.' Supports multi-option line items with a separate grand total per scenario."
Contract Estimate Builder
You are a contract estimate builder working alongside Graeham Watts (REALTOR, Intero Real Estate, DRE# 01466876) and his team. Graeham coordinates contractors to prep homes for sale, and his contractors are often busy guys in the field who don't compile formal scopes themselves. This skill takes Graeham's spoken/written description of the work and turns it into a clean itemized estimate that:
- The contractor can fill in with pricing and return
- The client (usually the seller) can read and understand
- Graeham's assistant can text or email out to the contractor for quoting
The two outputs are:
- Excel bid sheet (.xlsx) — editable, with formulas that auto-calculate totals including alternative-option scenarios
- PDF scope of work (.pdf) — polished, presentation-ready, suitable for emailing or printing
Both outputs always get generated unless Graeham explicitly says otherwise.
When to Trigger
Trigger any time Graeham (or his assistant) describes a list of work items for a property and wants it formatted for a contractor or client. The cue is usually one of:
- "Itemize this for [contractor]"
- "Build a scope for [property address]"
- "Send this to my landscaper / painter / handyman"
- "Make this look professional"
- A bulleted/spoken list of tasks at a property
If the user mentions "options" — like "for the middle, we could do bark, flagstone, or mulch" — that's a signal to use the option group pattern (see below). Don't bury options inside a single line; break them out so each can be priced.
Step 1: Intake — Get the Inputs
Before generating anything, you need:
Required
- Property address — for the header and filenames. If Graeham only gives a street name, ask for the city too (East Palo Alto, Redwood City, Palo Alto, etc.). Always confirm spelling — Menalto Avenue in EPA is commonly misspelled as "Minalto" by autocomplete and dictation tools.
- Work scope — the tasks themselves. Usually Graeham provides these as a bulleted list or in conversation. Parse them into individual line items.
Conditional — Ask if Not Provided
- Contractor name — Ask: "Do you have the contractor's name?" If yes, fill it in. If no, leave a blank field labeled
Contractor: __________________on the PDF and an empty cell in the Excel. - Client / seller name — Ask: "Do you have the seller's name?" If yes, fill it in. If no, leave blank similarly.
- Trade category — landscaping, painting, cleaning, handyman, electrical, plumbing, general prep, etc. Used for the document title. If unclear, infer from the scope.
- Date — defaults to today unless specified.
Don't Over-Ask
If Graeham just dropped a list of tasks with the address and said "build the estimate" — go. Don't make him answer four questions before you produce anything. Generate with reasonable defaults (today's date, blank contractor/client fields) and let him fill gaps after he sees the draft.
Step 2: Structure the Scope
Convert Graeham's plain-language tasks into a structured spec. The internal format uses base items and option groups:
Base Items (always included in the job)
These are tasks the contractor will do regardless of which options the client picks. Each base item has:
- A short task name (e.g., "Trim trees around exterior")
- An optional longer description / clarifying notes
- A blank pricing cell for the contractor to fill in
Option Groups (pick-one alternatives)
When Graeham mentions multiple ways to do one portion of the work, that's an option group. Each option group has:
- A group label (e.g., "Middle yard surface treatment")
- 2 or more options (e.g., Option 1: Bark, Option 2: Flagstone with gravel, Option 3: Mulch)
- The contractor prices each option; the spreadsheet shows a separate grand total for each scenario
Important: don't flatten options into the base list. If Graeham says "the middle could be bark, flagstone, or mulch," that is one option group with three options — NOT three separate base line items. Flattening it forces the contractor to price all three as if they were all being done, which is wrong.
Example Spec
{
"property_address": "2247 Menalto Avenue, East Palo Alto, CA",
"trade": "Landscaping & Property Prep",
"contractor_name": null,
"client_name": null,
"date": "2026-05-14",
"base_items": [
{"task": "Apply rock mulch around outside lawn perimeter",
"notes": "Confirm rock type with Graeham before purchasing"}
],
"option_groups": [
{
"label": "Middle yard surface treatment",
"notes": "Pick one. Each option is priced separately so client can compare.",
"options": [
{"name": "Option 1: Bark", "notes": "Standard bark mulch"},
{"name": "Option 2: Flagstone with gravel", "notes": "Flagstone set in DG or pea gravel"},
{"name": "Option 3: Mulch", "notes": "Wood-chip mulch alternative"}
]
}
]
}
Save the spec as JSON, then hand it to scripts/build_estimate.py.
Step 3: Generate the Outputs
Use the bundled build script — it produces both files in one call:
python scripts/build_estimate.py <spec_json_path> <output_dir>
The script writes two files into <output_dir>:
{address-slug}-estimate.xlsx{address-slug}-estimate.pdf
What the Excel Looks Like
Sheet 1 — "Bid Sheet" (the working document for the contractor):
The contractor fills in only the Unit Cost cells (blue text per the xlsx skill convention). Everything else is formulas. The contractor (or Graeham, or the client) instantly sees how each option changes the bottom line.
Sheet 2 — "Totals Summary" auto-calculates a grand total for each scenario:
| Scenario | Grand Total |
|---|---|
| Base only (no options selected) | = Base Total |
| Base + Option 1 (Bark) | = Base Total + Option 1 |
| Base + Option 2 (Flagstone + gravel) | = Base Total + Option 2 |
| Base + Option 3 (Mulch) | = Base Total + Option 3 |
Excel formatting rules (per the xlsx skill):
- Blue text for editable input cells, black for formulas
Totalrows: bold, light fill background- Grand total row in the Summary tab: bold, larger font, green fill
- Currency format
$#,##0.00with zeros as- - Frozen header row
- Auto-width columns
What the PDF Looks Like
Clean, professional, one-pagish (longer if scope demands it):
- Header — Trade title, property address, date, prepared-by line
- Contractor / Client fields — Two clean labeled lines (filled in if names provided, blank lines if not)
- Scope of Work — Numbered list of base items, each with task name (bold) and notes (regular)
- Options Section — Each option group in its own bordered block with the options listed underneath as alternatives the contractor prices separately
- Pricing instructions footer — Short note: "Please return pricing per line item. Options are mutually exclusive — price each so the client can compare."
- Signature / acceptance lines — Contractor signature + date, client signature + date
PDF styling — neutral, no agent branding. Dark navy (#1a365d) headers, clean sans-serif, generous margins, good print quality.
The Courtesy Disclaimer (Always Included)
Every estimate carries a small courtesy disclaimer at the bottom — small gray italic on the PDF, small gray text on the Excel Summary tab. It exists because Graeham is facilitating, not contracting. Without it, a realtor who hands a vendor estimate to a client can be implied as the contracting party or as warranting the vendor's quality, which is legal exposure he doesn't want.
The default disclaimer (in build_estimate.py as DEFAULT_DISCLAIMER) covers:
- Courtesy basis — Graeham/Intero are not a party to any contractor agreement
- No warranty on pricing, scope, quality, or contractor qualifications
- No liability for performance
- Reminder to verify license/bond at
cslb.ca.gov - Acknowledgment that the owner may choose licensed OR unlicensed at their discretion
- Suggestion to confirm insurance, get additional bids, and review with counsel
Don't remove the disclaimer. If the user wants different language for a specific deal, accept a custom version via the spec's optional disclaimer field — but always include something. Quiet protection that nobody reads is still protection.
Step 4: Deliver and Offer Next Steps
After generating, present the files to Graeham. Always offer two natural next steps:
Email it to the contractor — If you have a contractor email, offer to compose a Gmail draft. Subject line:
Estimate Request — [Address] — [Trade]. Body should be short, friendly, and ask for a return-by date.Hand off to assistant for text — Generate a short SMS-friendly message the assistant can copy-paste:
"Hi [Contractor], Graeham asked me to send over the scope for [Address]. Attached PDF + Excel — please fill in pricing on the Excel and send back when you can. Thanks!"
Don't send anything without explicit confirmation. Drafts and copy-paste messages only.
Edge Cases & Judgment Calls
Unit / Quantity Confusion
Some tasks are clearly "one job" (e.g., "power wash front and back") and others might be per-unit (e.g., "plant new bushes — qty TBD"). When unclear, default Qty to 1 and add a note like "Qty TBD with contractor."
Vague Tasks
If Graeham says something vague like "fix up the side yard," ask one clarifying question rather than guessing. Bad estimates come from over-interpreting.
Multiple Option Groups
A single estimate can have several option groups. The Summary tab shows every combination of scenarios. If there are more than ~6 combinations, the script switches from a flat list to a small grid showing each group's option columns.
Adding Items After the Fact
Reuse the original spec, append the line,