Port property assessor helpers to TypeScript
This commit is contained in:
@@ -1,38 +1,44 @@
|
||||
# property-assessor
|
||||
|
||||
Decision-grade residential property assessment skill for OpenClaw.
|
||||
|
||||
This skill is for evaluating a condo, townhouse, house, or similar residential property from an address or listing URL and ending with a practical recommendation such as `buy`, `pass`, or `only below X`.
|
||||
Decision-grade residential property assessment skill for OpenClaw, with official public-record enrichment and fixed-template PDF report rendering.
|
||||
|
||||
## Overview
|
||||
|
||||
`property-assessor` is a workflow skill, not just a scraper. It is meant to:
|
||||
`property-assessor` is for evaluating a condo, townhouse, house, or similar residential property from an address or listing URL and ending with a practical recommendation such as `buy`, `pass`, or `only below X`.
|
||||
|
||||
- normalize the target property across listing sources
|
||||
- build a baseline fact set
|
||||
The skill is intended to:
|
||||
|
||||
- normalize the property across listing sources
|
||||
- review listing photos before making condition claims
|
||||
- compare the property against nearby or same-building comps
|
||||
- underwrite taxes, HOA, insurance, and realistic carrying costs
|
||||
- identify risk drivers
|
||||
- produce a concise but decision-grade verdict
|
||||
- incorporate official public-record / appraisal-district context when available
|
||||
- compare the property against comps and carrying costs
|
||||
- produce a fixed-format PDF report, not just ad hoc chat prose
|
||||
|
||||
The skill is designed for real-world purchase decisions, especially when you need a fast read on whether a property is worth pursuing.
|
||||
## Standalone helper usage
|
||||
|
||||
## Accepted inputs
|
||||
This skill now ships with a small TypeScript helper package for two tasks:
|
||||
|
||||
The skill can start from any of:
|
||||
- locating official public-record jurisdiction from an address
|
||||
- rendering a fixed-template PDF report
|
||||
|
||||
- a street address
|
||||
- a Zillow listing URL
|
||||
- a HAR listing URL
|
||||
- an address plus user constraints such as:
|
||||
- investment only
|
||||
- owner-occupant
|
||||
- long-term rental
|
||||
- short-term rental
|
||||
- target distance/location requirements
|
||||
From `skills/property-assessor/`:
|
||||
|
||||
Preferred starting point is the address when available, because it makes source reconciliation easier.
|
||||
```bash
|
||||
npm install
|
||||
scripts/property-assessor --help
|
||||
```
|
||||
|
||||
The wrapper script uses the skill-local Node dependencies under `node_modules/`.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
scripts/property-assessor locate-public-records --address "4141 Whiteley Dr, Corpus Christi, TX 78418"
|
||||
scripts/property-assessor locate-public-records --address "4141 Whiteley Dr, Corpus Christi, TX 78418" --parcel-id "14069438"
|
||||
scripts/property-assessor locate-public-records --address "4141 Whiteley Dr, Corpus Christi, TX 78418" --listing-geo-id "233290"
|
||||
|
||||
scripts/property-assessor render-report --input examples/report-payload.example.json --output /tmp/property-assessment.pdf
|
||||
```
|
||||
|
||||
## Core workflow
|
||||
|
||||
@@ -40,16 +46,15 @@ Default operating sequence:
|
||||
|
||||
1. Normalize the address and property type.
|
||||
2. Discover accessible listing and public-record sources for the same property.
|
||||
3. Establish a baseline fact set from the best available source.
|
||||
4. Cross-check the same property on other sources.
|
||||
5. Review listing photos before making condition claims.
|
||||
6. Pull same-building comps for condos or nearby comps for houses/townhomes.
|
||||
7. Underwrite carry costs and risk drivers.
|
||||
8. End with a specific recommendation and fair-value range.
|
||||
3. Build a baseline fact set.
|
||||
4. Review listing photos before making condition claims.
|
||||
5. Pull same-building or nearby comps.
|
||||
6. Underwrite carry costs and risk factors.
|
||||
7. Render the final report as a fixed-template PDF.
|
||||
|
||||
## Source priority
|
||||
|
||||
Unless the user asks otherwise, preferred source order is:
|
||||
Unless the user says otherwise, preferred listing/source order is:
|
||||
|
||||
1. Zillow
|
||||
2. Redfin
|
||||
@@ -57,11 +62,72 @@ Unless the user asks otherwise, preferred source order is:
|
||||
4. HAR / Homes.com / brokerage mirrors
|
||||
5. county or appraisal pages
|
||||
|
||||
Use high-quality mirrors to confirm facts, not to override a clearly better primary listing without reason.
|
||||
Public-record / assessor data should be linked in the final result when available.
|
||||
|
||||
## Public-record enrichment
|
||||
|
||||
The skill should not rely on listing-site geo IDs as if they were assessor record identifiers.
|
||||
|
||||
Correct approach:
|
||||
|
||||
1. start from the street address
|
||||
2. resolve the address to state/county/FIPS/GEOID
|
||||
3. identify the official public-record jurisdiction
|
||||
4. use parcel/APN/account identifiers when available
|
||||
5. link the official jurisdiction page and any direct property page used
|
||||
|
||||
### `locate-public-records`
|
||||
|
||||
```bash
|
||||
scripts/property-assessor locate-public-records --address "<street-address>"
|
||||
```
|
||||
|
||||
Current behavior:
|
||||
|
||||
- uses the official Census geocoder
|
||||
- returns matched address, county/state/FIPS, and block GEOID context
|
||||
- for Texas, returns:
|
||||
- Texas Comptroller county directory page
|
||||
- appraisal district contact/site details
|
||||
- tax assessor/collector contact/site details
|
||||
|
||||
Important rules:
|
||||
|
||||
- Zillow/Redfin/HAR geo IDs are hints only
|
||||
- parcel/APN/account IDs are stronger search keys than listing geo IDs
|
||||
- official jurisdiction pages should be linked in the final report
|
||||
- if a direct property detail page is accessible, its data should be labeled as official public-record evidence
|
||||
|
||||
### Texas support
|
||||
|
||||
Texas is the first-class public-record path in this implementation.
|
||||
|
||||
For Texas addresses, the helper resolves:
|
||||
|
||||
- the official Census geocoder link
|
||||
- the official Texas Comptroller county directory page
|
||||
- the appraisal district website
|
||||
- the tax assessor/collector website
|
||||
|
||||
That output should be used by the skill to:
|
||||
|
||||
- identify the correct CAD
|
||||
- attempt address / parcel / account lookup on the CAD site
|
||||
- capture official assessed values and exemptions when a public detail page is available
|
||||
|
||||
Recommended fields to capture from official records when accessible:
|
||||
|
||||
- account number
|
||||
- owner name
|
||||
- land value
|
||||
- improvement value
|
||||
- assessed total
|
||||
- exemptions
|
||||
- official property-detail URL
|
||||
|
||||
## Minimum data to capture
|
||||
|
||||
For the target property, capture as many of these as the sources support:
|
||||
For the subject property, capture when available:
|
||||
|
||||
- address
|
||||
- list price or last known list price
|
||||
@@ -79,169 +145,107 @@ For the target property, capture as many of these as the sources support:
|
||||
- subdivision or building name
|
||||
- same-building or nearby active inventory
|
||||
- listing photos and visible condition cues
|
||||
- included appliances and obvious missing appliances
|
||||
- flooring mix, especially carpet
|
||||
- public-record jurisdiction and linked official source
|
||||
- account / parcel / tax ID if confirmed
|
||||
- official assessed values and exemptions if confirmed
|
||||
|
||||
## Photo-review requirement
|
||||
## Photo-review rules
|
||||
|
||||
Photo review is mandatory when the listing sources expose photos.
|
||||
Photo review is mandatory when photos are exposed by a listing source.
|
||||
|
||||
Do not make strong condition claims from structured text alone if photos are available.
|
||||
|
||||
### What counts as acceptable photo access
|
||||
|
||||
Preferred photo sources are:
|
||||
|
||||
- a scrollable all-photos page
|
||||
- an expanded photo grid
|
||||
- a photo page that exposes the full set
|
||||
- a modal/lightbox only if the site does not provide a better all-photos path
|
||||
|
||||
Do not treat these as full photo review by themselves:
|
||||
|
||||
- the listing hero image
|
||||
- a collage preview
|
||||
- a photo count without image access
|
||||
- listing shell text that mentions photos
|
||||
|
||||
### What to inspect in the photos
|
||||
|
||||
At minimum, evaluate:
|
||||
|
||||
- overall finish level: dated, average, lightly updated, fully updated
|
||||
- kitchen condition: cabinets, counters, backsplash, appliances
|
||||
- bathroom condition: vanity, tile, surrounds, fixtures
|
||||
- flooring: tile, vinyl, laminate, hardwood, carpet
|
||||
- obvious make-ready issues: paint, trim, wear, damage, mismatched finishes
|
||||
- visible missing items: refrigerator, washer/dryer, range hood, dishwasher
|
||||
- signs of deferred maintenance or water intrusion
|
||||
- exterior and common-area condition where visible
|
||||
- waterfront-facing elements, balconies, decks, sliders, and windows when relevant
|
||||
|
||||
### If photo review is incomplete
|
||||
|
||||
If the agent cannot access enough photos to make a credible read:
|
||||
|
||||
- say so explicitly
|
||||
- lower confidence
|
||||
- avoid strong turnkey claims
|
||||
- continue the broader underwriting work, but mark condition as limited-confidence
|
||||
|
||||
## Zillow and HAR integration
|
||||
|
||||
This skill now expects the dedicated `web-automation` extractors first instead of fragile ad hoc gallery automation.
|
||||
|
||||
### Zillow first
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd ~/.openclaw/workspace/skills/web-automation/scripts
|
||||
node zillow-photos.js "<zillow-listing-url>"
|
||||
```
|
||||
|
||||
Successful Zillow photo access means one of these happened:
|
||||
|
||||
- the `See all photos` / `See all X photos` path opened a usable all-photos experience, or
|
||||
- the rendered Zillow listing shell already exposed the full direct Zillow image set and the extracted count matches the announced count
|
||||
|
||||
Important rule:
|
||||
- when the extractor returns `imageUrls`, that returned set is the photo-review set
|
||||
|
||||
For smaller listings, review the full extracted set when practical. For a 20-30 photo listing, that usually means all photos.
|
||||
|
||||
### HAR fallback
|
||||
|
||||
If Zillow does not expose a reliable image set, use HAR next:
|
||||
|
||||
```bash
|
||||
cd ~/.openclaw/workspace/skills/web-automation/scripts
|
||||
node har-photos.js "<har-listing-url>"
|
||||
```
|
||||
|
||||
Successful HAR photo access means:
|
||||
|
||||
- the HAR listing opened
|
||||
- `Show all photos` / `View all photos` exposed the photo page
|
||||
- direct `pics.harstatic.com` image URLs were extracted
|
||||
|
||||
As with Zillow, the returned `imageUrls` are the review set for condition analysis.
|
||||
|
||||
### Practical photo-source order
|
||||
|
||||
Use this action order:
|
||||
Preferred photo-access order:
|
||||
|
||||
1. Zillow extractor
|
||||
2. HAR extractor
|
||||
3. Realtor.com photo page
|
||||
4. brokerage mirror or other accessible listing mirror
|
||||
|
||||
Do not stop after the first failed source if a fallback source can still expose the photos.
|
||||
Use the dedicated `web-automation` extractors first:
|
||||
|
||||
## Approval-safe execution
|
||||
|
||||
For chat-driven property assessments, prefer file-based commands under:
|
||||
|
||||
```text
|
||||
~/.openclaw/workspace/skills/web-automation/scripts
|
||||
```bash
|
||||
cd ~/.openclaw/workspace/skills/web-automation/scripts
|
||||
node zillow-photos.js "<zillow-listing-url>"
|
||||
node har-photos.js "<har-listing-url>"
|
||||
```
|
||||
|
||||
Good command shape:
|
||||
When those extractors return `imageUrls`, that returned set is the photo-review set.
|
||||
|
||||
## Approval-safe command shape
|
||||
|
||||
For chat-driven runs, prefer file-based commands.
|
||||
|
||||
Good:
|
||||
|
||||
- `node check-install.js`
|
||||
- `node zillow-photos.js "<url>"`
|
||||
- `node har-photos.js "<url>"`
|
||||
- `scripts/property-assessor locate-public-records --address "..."`
|
||||
- `scripts/property-assessor render-report --input ... --output ...`
|
||||
|
||||
Avoid when possible:
|
||||
|
||||
- `node -e "..."`
|
||||
- `node --input-type=module -e "..."`
|
||||
|
||||
Why this matters:
|
||||
## PDF report template
|
||||
|
||||
- OpenClaw exec approvals are easier to allowlist for stable file paths
|
||||
- inline interpreter eval is more likely to trigger approval friction
|
||||
- the installed approval allowlist is typically already scoped to the `*.js` files under the `web-automation/scripts` directory
|
||||
The final deliverable should be a fixed-template PDF, not a one-off layout.
|
||||
|
||||
## Make-ready normalization
|
||||
Template reference:
|
||||
|
||||
Condition should be translated into a rough make-ready range so pricing and comp comparisons stay realistic.
|
||||
- `skills/property-assessor/references/report-template.md`
|
||||
|
||||
Use simple buckets:
|
||||
Current renderer:
|
||||
|
||||
- light make-ready
|
||||
- paint, fixtures, minor hardware, small patching
|
||||
- medium make-ready
|
||||
- partial flooring replacement, appliance replacement, bathroom refresh
|
||||
- heavy make-ready
|
||||
- significant kitchen/bath work, widespread flooring, visible deferred maintenance
|
||||
```bash
|
||||
scripts/property-assessor render-report --input "<report-payload-json>" --output "<output-pdf>"
|
||||
```
|
||||
|
||||
Call out carpet separately when present, especially in bedrooms, stairs, or living areas.
|
||||
The fixed template includes:
|
||||
|
||||
## Underwriting expectations
|
||||
1. Report header
|
||||
2. Verdict panel
|
||||
3. Subject-property summary table
|
||||
4. Snapshot
|
||||
5. What I Like
|
||||
6. What I Do Not Like
|
||||
7. Comp View
|
||||
8. Underwriting / Carry View
|
||||
9. Risks and Diligence Items
|
||||
10. Photo Review
|
||||
11. Public Records
|
||||
12. Source Links
|
||||
13. Notes page
|
||||
|
||||
The final assessment should show a simple carrying-cost view including:
|
||||
### Recipient email gate
|
||||
|
||||
- principal and interest if available
|
||||
- taxes per month
|
||||
- HOA per month if applicable
|
||||
- insurance estimate or explicit uncertainty
|
||||
- realistic carry range after maintenance, vacancy, and property-specific risk
|
||||
The report must not be rendered or sent unless target recipient email address(es) are known.
|
||||
|
||||
Strong caution flags include:
|
||||
If the prompt does not include recipient email(s), the skill should:
|
||||
|
||||
- high HOA relative to price or expected rent
|
||||
- older waterfront or coastal exposure
|
||||
- unknown reserve or assessment history for condos
|
||||
- many active units in the same building or micro-area
|
||||
- stale days on market with weak price action
|
||||
- no clear rent support
|
||||
- stop
|
||||
- ask for target recipient email address(es)
|
||||
- not finalize the PDF workflow yet
|
||||
|
||||
The renderer enforces this. If `recipientEmails` is missing or empty, it fails with:
|
||||
|
||||
`Missing target email. Stop and ask the user for target email address(es) before generating or sending the property assessment PDF.`
|
||||
|
||||
## Example payload
|
||||
|
||||
Sample payload:
|
||||
|
||||
- `skills/property-assessor/examples/report-payload.example.json`
|
||||
|
||||
This is the easiest way to test the renderer without building a report payload from scratch.
|
||||
|
||||
## Output contract
|
||||
|
||||
The final answer should stay concise but decision-grade.
|
||||
The assessment itself should remain concise but decision-grade.
|
||||
|
||||
Recommended structure:
|
||||
Recommended narrative structure:
|
||||
|
||||
1. Snapshot
|
||||
2. What I like
|
||||
@@ -251,76 +255,77 @@ Recommended structure:
|
||||
6. Risks and diligence items
|
||||
7. Verdict with fair-value range and offer guidance
|
||||
|
||||
The output must explicitly include:
|
||||
It must also explicitly include:
|
||||
|
||||
- `Photo source attempts: ...`
|
||||
- `Photo review: completed via <source>`
|
||||
or `Photo review: not completed`
|
||||
- `Photo review: completed via <source>` or `Photo review: not completed`
|
||||
- public-record / CAD evidence and links when available
|
||||
|
||||
If photo review was completed:
|
||||
## Validation flow
|
||||
|
||||
- summarize the condition read from the photos
|
||||
- mention obvious finish level, flooring, appliance presence, and make-ready signals
|
||||
|
||||
If not completed:
|
||||
|
||||
- mark condition confidence as limited
|
||||
- explain why photo access was incomplete
|
||||
|
||||
## Example validation flow
|
||||
|
||||
Use these commands for a known-good regression check.
|
||||
|
||||
### Verify extractor prerequisites
|
||||
### 1. Install the helper package locally
|
||||
|
||||
```bash
|
||||
cd ~/.openclaw/workspace/skills/web-automation/scripts
|
||||
node check-install.js
|
||||
npm run test:photos
|
||||
cd ~/.openclaw/workspace/skills/property-assessor
|
||||
npm install
|
||||
npm test
|
||||
```
|
||||
|
||||
### Zillow regression check
|
||||
### 2. Run public-record lookup
|
||||
|
||||
```bash
|
||||
cd ~/.openclaw/workspace/skills/web-automation/scripts
|
||||
node zillow-photos.js "https://www.zillow.com/homedetails/4141-Whiteley-Dr-Corpus-Christi-TX-78418/2103723704_zpid/"
|
||||
cd ~/.openclaw/workspace/skills/property-assessor
|
||||
scripts/property-assessor locate-public-records --address "4141 Whiteley Dr, Corpus Christi, TX 78418"
|
||||
```
|
||||
|
||||
Expected shape:
|
||||
|
||||
- `complete: true`
|
||||
- `expectedPhotoCount: 29`
|
||||
- `photoCount: 29`
|
||||
- state/county/FIPS/GEOID present
|
||||
- official Census geocoder link present
|
||||
- for Texas: Comptroller county directory link present
|
||||
- for Texas: appraisal district and tax assessor/collector contacts present
|
||||
|
||||
### HAR regression check
|
||||
### 3. Run PDF render with the sample payload
|
||||
|
||||
```bash
|
||||
cd ~/.openclaw/workspace/skills/web-automation/scripts
|
||||
node har-photos.js "https://www.har.com/homedetail/4141-whiteley-dr-corpus-christi-tx-78418/14069438"
|
||||
cd ~/.openclaw/workspace/skills/property-assessor
|
||||
scripts/property-assessor render-report --input examples/report-payload.example.json --output /tmp/property-assessment.pdf
|
||||
```
|
||||
|
||||
Expected shape:
|
||||
Expected result:
|
||||
|
||||
- `complete: true`
|
||||
- `expectedPhotoCount: 29`
|
||||
- `photoCount: 29`
|
||||
- JSON success payload with `outputPath`
|
||||
- a non-empty PDF written to `/tmp/property-assessment.pdf`
|
||||
|
||||
### Skill-level validation
|
||||
### 4. Verify the email gate
|
||||
|
||||
When testing `property-assessor` itself, confirm the resulting assessment:
|
||||
Run the renderer with a payload that omits `recipientEmails`.
|
||||
|
||||
- attempts Zillow first
|
||||
- falls back to HAR if needed
|
||||
- references actual photo access, not just listing text
|
||||
- includes the required `Photo source attempts` line
|
||||
- includes the required `Photo review` line
|
||||
- makes condition claims consistent with the reviewed image set
|
||||
Expected result:
|
||||
|
||||
- non-zero exit
|
||||
- explicit message telling the operator to stop and ask for target recipient email(s)
|
||||
|
||||
### 5. Verify the end-to-end skill behavior
|
||||
|
||||
When testing `property-assessor` itself, confirm the assessment:
|
||||
|
||||
- starts from the address when available
|
||||
- uses Zillow first for photo extraction, HAR as fallback
|
||||
- uses official public-record jurisdiction links when available
|
||||
- does not treat listing geo IDs as assessor keys
|
||||
- asks for recipient email(s) if they were not provided
|
||||
- renders the final report through the fixed PDF template once recipient email(s) are known
|
||||
|
||||
## Related files
|
||||
|
||||
- installed skill instructions:
|
||||
- `~/.openclaw/workspace/skills/property-assessor/SKILL.md`
|
||||
- repo skill instructions:
|
||||
- skill instructions:
|
||||
- `skills/property-assessor/SKILL.md`
|
||||
- photo extractor docs:
|
||||
- underwriting heuristics:
|
||||
- `skills/property-assessor/references/underwriting-rules.md`
|
||||
- PDF template rules:
|
||||
- `skills/property-assessor/references/report-template.md`
|
||||
- sample report payload:
|
||||
- `skills/property-assessor/examples/report-payload.example.json`
|
||||
- photo extraction docs:
|
||||
- `docs/web-automation.md`
|
||||
|
||||
Reference in New Issue
Block a user