This skill should be used when the user asks to "search for cars", "find me a [car name]", "what [car name]s are for sale", "search AutoTrader", "update my car search", "run the car search", "look for cars", "check for new listings", "any new cars today", "refresh the car search", or any request related to searching for used cars currently listed for sale in the UK. Config-driven: reads a car profile to determine what to search for.
Search UK car listing websites for used cars matching an active car profile. Compile results into a detailed, cited markdown table with key specifications and distance from the user's home postcode.
This skill requires an active car profile in ${CLAUDE_PLUGIN_DATA}/profiles/. Profiles are user-created and live in the plugin's persistent data directory, not in the plugin install. If no profile exists, direct the user to the setup-car-profile skill first.
${CLAUDE_PLUGIN_DATA}/profiles/ for available .json profile files. If the directory does not exist yet, no profiles have been created - run setup-car-profile first.car-profile.json and use it to configure the entire searchAll subsequent instructions reference profile fields. For example, profile.search_filters.max_price means the max_price value from the search_filters section of the loaded profile.
Unless the user specifies otherwise, apply these filters from the profile:
profile.search_filters.max_priceprofile.search_filters.max_mileageprofile.search_filters.min_yearprofile.search_filters.max_distance miles from profile.search_filters.postcodeprofile.search_filters.exclude_write_offsIf the user provides different filter values, use those instead.
For each variant in profile.variants, construct the AutoTrader search URL:
{profile.search_urls.autotrader.base}?make={profile.make}&model={variant.autotrader_model}&{profile.search_urls.autotrader.params}&postcode={profile.search_filters.postcode}&price-to={profile.search_filters.max_price}&maximum-mileage={profile.search_filters.max_mileage}&distance={profile.search_filters.max_distance}&year-from={profile.search_filters.min_year}
Also construct URLs for each entry in profile.search_urls.additional_sites and profile.search_urls.dealer_groups, applying the user's filter parameters where the URL supports them.
Use Claude in Chrome browser tools to navigate directly to each constructed URL. WebFetch is blocked for most car listing sites, so the browser is the primary method.
Search each variant separately on AutoTrader (many cars list variants as different models).
Then check each additional site and dealer group from the profile.
If the browser is unavailable, use WebSearch as a fallback:
site:autotrader.co.uk {profile.make} {variant.name} for salesite:{domain} {profile.make} {model}{profile.display_name} for sale UK {current_year} for broader resultsFor promising listings, navigate to the individual listing page in the browser to extract full details. On AutoTrader, click "View all spec and features" (it is a <button> element, not a link) to see the full equipment list.
Use the profile.spec_options[].search_terms to identify which optional features each listing has. Match terms case-insensitively against the listing description and spec list.
Many cars appear on multiple platforms. Deduplicate by matching on price + year + mileage + dealer location. When a duplicate is found, link to both sources but count it as one listing.
The dashboard now diffs snapshots automatically. For the diff to be meaningful, each search run must be exhaustive and must record what was actually captured - otherwise a missed page on one day looks like a "sold" car on the next.
For each source URL, follow ?page=N (or the site's equivalent) until a page returns zero new listings. Do not stop at the first page. On AutoTrader, read the pagination footer ("Page 1 of 4") to know the expected count.
For each source, track:
name - short label (AutoTrader, Cazoo, Cinch, dealer group name)url - the base URL template usedexpected_pages - page count from the pagination footercaptured_pages - how many pages you actually walkedstatus - one of ok (all pages walked cleanly), partial (some pages skipped, timed out, or errored), failed (source unreachable)Save a JSON manifest alongside the CSV at {profile.profile_name}-searches/{profile.profile_name}-capture-{YYYY-MM-DD}.json:
{
"sources": [
{"name": "AutoTrader", "url": "...", "expected_pages": 4, "captured_pages": 4, "status": "ok"},
{"name": "Cazoo", "url": "...", "expected_pages": 3, "captured_pages": 2, "status": "partial"}
],
"total_captured": 37
}
The dashboard builder reads this file and renders a capture badge (green / amber / red) in the header so anyone viewing the dashboard knows whether the day's counts are trustworthy.
For each listing, capture:
profile.variants[].name)profile.generations[] using detection rules)profile.search_filters.postcode)profile.spec_options[]: Yes / No / Not statedFor spec options where a variant has the spec as standard (listed in variant.standard_specs), mark as "Yes (standard)" rather than checking the listing text.
The user's home postcode is profile.search_filters.postcode (profile.search_filters.location_description). When searching on AutoTrader with the postcode parameter, distances are shown in the results. For other platforms, estimate driving distance using general UK geography knowledge. Present as approximate miles, e.g. "~45 miles".
After compiling results, save the full report as a markdown file.
Path: Save to a {profile.profile_name}-searches/ folder within the user's workspace. Use the naming pattern {profile.profile_name}-search-{YYYY-MM-DD}.md. If a file for today's date already exists, overwrite it. Always present the results in the conversation as well as saving the file.
Present results as a markdown table sorted by price (lowest first), grouped by variant. Build the table columns dynamically from the profile:
Fixed columns: #, Price, Year, Mileage, Colour, Location (dist.), Days Listed
Dynamic columns: one column per profile.spec_options[] where highlight is true (use short labels).
Final column: Key Options (remaining non-highlighted specs), Listing (clickable links).
| # | Price | Year | Mileage | Colour | Location (dist.) | Days Listed | {highlight_spec_1} | {highlight_spec_2} | Key Options | Listing |
IMPORTANT: The Listing column MUST contain clickable markdown hyperlinks to the actual listing page. Format as [Platform name](full URL). If a car appears on multiple platforms, include all links separated by a comma.
After the table, include:
Each search creates a dated snapshot. Over time, these snapshots enable market analysis.
If profile.listing_id_date_encoding.enabled is true:
For AutoTrader listings, extract the first 8 digits of the listing ID from the URL (e.g. /car-details/202602179980029 -> 20260217 -> 17 Feb 2026) and record as the First Listed date. Calculate Days on Market as today's date minus the first listed date.
For Cazoo listings, the search results page shows "Added X days ago" text for some listings. Extract this where available.
For listings on other platforms without date encoding, check previous search reports to determine when the listing was first observed.
Volatility analysis is now handled automatically by the dashboard builder. As long as every snapshot CSV carries a listing_id column, the builder diffs the latest snapshot against the previous dated CSV in the same folder and computes new arrivals, removed listings, and price changes itself. You no longer need to hand-maintain a {profile}-listing-state.json sidecar or recalculate deltas in the search report.
After presenting the search results, also compile the data into a CSV file for the dashboard builder. The CSV columns are:
Fixed: listing_id, variant, generation, price, year, reg, reg_date, age_years, mileage, new_price, depreciation_total, depreciation_pa, depreciation_pct
listing_id (stable cross-run identifier)This is the first column and is what lets the dashboard match the same car across successive searches. Populate it as follows:
/car-details/ in the listing URL (e.g. https://www.autotrader.co.uk/car-details/202602179980029 -> 202602179980029). The first 8 digits double as the first-listed date.{source}:{12-char sha1 of the listing URL} so the id is stable if you re-scrape the same listing. Never invent composite keys from price + location - they move when the dealer drops the price.Leave the column empty only as a last resort. An empty listing_id opts that row out of the snapshot diff and the watchlist.
Dynamic (from profile.spec_options): one boolean column per spec option using the key field (e.g. has_bo, has_massage)
Fixed: options_count, location, is_brand_new_stock
reg_date: look up profile.reg_date_mapping[reg_code]age_years: current decimal date minus reg_datenew_price: look up profile.generations[matching_gen].new_prices[variant_name]depreciation_total: new_price - pricedepreciation_pa: depreciation_total / age_years (N/A if age < 0.5 years)depreciation_pct: (depreciation_total / new_price) * 100options_count: count of True spec option columnsSave as: {profile.profile_name}-searches/{profile.profile_name}-all-listings-{YYYY-MM-DD}.csv
variant.standard_specs before marking a spec as not present -- some specs are standard on certain variants