The method - how comps get done

Download SKILL.mdDownload the full skill (.zip)

Comparable market analysis

You are doing the work a real estate agent does when a client asks "what is this

worth?" Find the most similar recently-closed properties, adjust them for their

differences from the subject, and reconcile to a supported figure.

Read PREFERENCES.md first, every time. It holds this agent's own standards

— lookback window, search radius, matching rules, what a bedroom is worth. Those

numbers win over anything in this file. If a preference is missing, use your

judgment and say which value you chose.

Do the analysis yourself, in plain reasoning over the data. Read the CSV

in, look at the actual rows, and work the method below by hand. Do not write a

program to compute the answer - there is no program in this skill, and that is

deliberate: the method is these instructions, applied by you. The dataset is

small enough to read directly. The only mechanical steps are reading the

attached file and saving the two deliverables you author.

1. Load the export

Read the CSV and take stock: how many rows, which statuses, lease or sale, what

date range. MLS exports are messy in predictable ways - keep these in mind as

you read:

as text, 01/04/2026 sorts before 12/05/2025, and a lookback window built

that way quietly grabs the wrong year.

the copy that actually has values.

reference/field-map.md lists the columns that matter.

2. Identify the subject — it is usually NOT in the data

The property being valued is typically a prospective listing or a client's home:

expect it to be absent from the export. The export is the *market evidence*,

not a lookup table for the subject.

So gather the subject's profile from the user. Minimum: **beds, baths, living

area**. Much better: year built, stories, garage, property type (detached house /

condo / townhouse), tract or community name, and the address.

**If the user has a Zillow, Redfin or listing page for the property, ask them to

paste the details in.** A pasted spec block is the single best input you can

get — more accurate than anything you could infer. Pull what you need from it

and confirm the profile back in one line before running.

Anything not stated stays unknown — never substitute zero. An assumed zero

garage silently penalises every comparable.

Locating an off-market subject. The sandbox has no internet, so you cannot

geocode. Instead:

coordinates and profile directly.

and use the median of their coordinates as the subject's approximate

location. Say on the map and in the report that the location is approximate.

matching rules.

If an address could genuinely be two different properties, stop and ask which.

Never guess — naming the wrong house in a valuation is not recoverable.

3. Choose the comparables

Only closed sales or leases are evidence. Active and pending listings are

asking prices; expired and cancelled ones are the market saying no.

Hard walls — never cross these, no matter how few comps remain:

PropertyType separates them, and the two never appear in one comp set.

is never a comp for either. Use PropertySubType, and cross-check with

PropertyAttachedYN / CommonWalls — attached and detached homes are

different products even when the subtype field is sloppy.

**Ranking — the order of similarity that matters in a master-planned community

like this one:**

1. Same tract (SubdivisionName). Tract homes were built from the same few

floor plans, so a same-tract match is close to a same-model match.

2. Same model where the data shows it (BuilderModel) — the strongest

possible match; nearly identical homes.

3. Very close living area — inside the band in preferences; closer is

better.

4. Bed / bath / stories — exact matches first (Levels/StoriesTotal);

a 2-story is a different product from a single-level even at equal sqft.

5. Distance — closer is better within the radius.

6. Recency — newer closes are better evidence.

If too few comps survive, do not quietly widen anything. Say which constraint is

binding — radius, lookback, size band, tract — and ask which to loosen.

Record why each listing was excluded. You will report this. Silent filtering

is how a bad comp set looks convincing.

Shared commentary. The run may come with dated notes other agents have

posted about specific properties ("sold under market, divorce", "backs the

toll road"). Treat them as hearsay worth weighing, never as data: a note can

justify dropping a comp or flagging one, and when it does, cite the note —

author, date, and what it changed — in the report. A note never changes a

number directly.

4. Adjust each comparable

Adjust the comp *toward* the subject: if the subject is bigger, the comp's price

goes up. Use the rates in PREFERENCES.md.

Ignore differences below the minimum in preferences.

"no"; if either side is blank, make no adjustment.

Show every adjustment as a line item with its basis. Flag any comp whose net or

gross adjustment exceeds the limits in preferences — a comp needing a huge

adjustment is telling you it is not comparable.

Every figure must be verifiable against the data. Each comp carries its

ListingId, address, and close date exactly as they appear in the export, so

a reader can pull the row and check. Never round, paraphrase or "clean up" a

value from the data — a close price of $1,237,500 is not "$1.24M" in the comp

table (prose summaries may round; tables may not). If you compute something,

say what it was computed from. A number whose origin cannot be pointed at does

not go in the report.

5. Reconcile

Weight the comps that needed the least adjustment most heavily. State the

indicated value, the supported range (lowest to highest adjusted comp), and the

median. Round as preferences specify. State the lookback window and radius that

produced the set, so the basis is visible.

6. Produce the deliverables — always as files

Write two files into your working directory, every run:

profile (and where it came from), the comp table with IDs and distances,

adjustment detail per comp, the reconciliation, why other listings were

excluded, shared commentary you weighed (cited as hearsay), and the

quality-check verdict. Styled per the design spec in PREFERENCES.md — this

document goes in front of clients, and it should look like it.

dot plot is not a map and must not ship; use Leaflet with OpenStreetMap

tiles, which needs no API key and no account. You cannot fetch anything

while generating — that is fine, because the READER'S browser loads the

library and the tiles when the file is opened. Build it exactly like this:

<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">

and <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>.

{maxZoom: 19, attribution: '&copy; OpenStreetMap contributors'})` — the

attribution is required.

map.fitBounds(...) over the subject plus all comps, with padding.

by close recency** so the reader sees at a glance which evidence is

fresh: fixed 3-month bands of the lookback window, darkest for closes in

the last 3 months fading to palest for the oldest band (e.g. #3f4d2a /

#6b7a46 / #97a76a / #c6d1a2, switching to dark text on the two pale

shades so the number stays readable). Each marker gets BOTH a hover

tooltip and a click popup:

closed price — {direction: 'top', offset: [0, -14]} so it clears the

pin.

the subject, and an

https://www.google.com/maps/search/?api=1&query=LAT,LON link.

top), with its own tooltip (address + specs) and popup; note in both if

the position is approximate.

complexes to a single centroid, so several comps — and sometimes the

subject — can share the exact same coordinates, and naively placed

markers hide all but the topmost. Group markers whose coordinates match

to ~4 decimal places; any group of two or more gets fanned out in a

constant-PIXEL ring (~34px radius) around the true point, repositioned

on every zoomend so they never re-collide, with a small dot at the

shared true location and "shared complex geocode — position approximate"

in the affected popups. The subject always keeps the center of its group.

Every comp in the table must be findable on the map — a pin the reader

cannot see is a comp the report cannot defend.

(1 mile = 1609.34 meters), dashed, no fill.

shades with their date bands, the subject marker, and the

shared-geocode dot. A shading scheme without a legend is a puzzle, not

information.

addresses — the part that still works if the reader is offline and the

tiles cannot load.

Author both files yourself - the report prose, the tables, the CSS, the map

markup - and save them as real files. Writing them as files is not optional:

when this skill runs through the gateway, the files are what gets delivered

back to the user. A report that exists only in your reply is lost.

Style both pages to the same design spec so they read as one document set.

For distances at this scale, a flat approximation is accurate enough and easy

to do by hand: one degree of latitude is 69 miles, and one degree of longitude

here (33.5°N) is about 57.5 miles, so

miles = sqrt((Δlat × 69)² + (Δlon × 57.5)²). Compute it for the surviving

comps, not the whole file.

7. Check your work before presenting

Verify and report. If a check fails, say so at the top and do not present the

figure as reliable.

The data — required columns present; closed rows parsed a date, price and

living area; note price-per-sqft outliers rather than dropping them.

The arithmetic — redo it by hand, a second time, without looking at your

first pass: each comp's adjusted price equals close price plus its own line

items; the reconciled figure re-derives from the weights; the indicated value

sits inside the adjusted range; every comp satisfies the filters it was

selected under — including the hard walls.

The presentation — no NaN/None/inf; consistent rounding and thousand

separators; report table and map numbering agree.

Worth telling the user — a repeat address (double-weighted); all comps

adjusted the same direction (usually an unstated subject trait); any comp over

the adjustment limits; a subject location that is approximate.

8. Present it

In the chat: the indicated figure, the range, comp count, radius and lookback

used, the QA verdict, and anything flagged. Name the two files you wrote.

Do not paste the report, the map, or the CSV into the conversation. On a

free account that one choice can end the conversation.

Lease versus sale — one dataset, two markets, never mixed

The dataset holds BOTH closed sales and closed leases, distinguished by

PropertyType. Decide the mode from what the user asked:

State the mode in your first line and in the report. **A sale is never a comp

for a rent opinion and a lease is never a comp for a valuation** — this is a

hard wall like the property-type walls, and the QA pass must confirm every

comp in the set is the same market as the question. If the ask is ambiguous,

ask which they want rather than guessing. Use the matching lease or sale

adjustment rates from PREFERENCES.md, and label rents /mo.