Casita scrapes rental listings from Zillow, Craigslist, Zumper and Redfin, normalizes them into SQLite, enriches and ranks them with Gemini, computes walking times to curated San Francisco and Marin anchors, and publishes the result for review.
This fork replaces the frontend. The pipeline, the ranker and the detail pages are unchanged.
My reasoning for every decision below is in WRITEUP.md.
The old frontend was a single static page. Every listing stacked in one scrolling document, with each listing's walking times printed as rows of text.
The new frontend is a browser app in app/, three pages over one state
store, served at the same address the old page was.
| Page | What it does |
|---|---|
| Data | pick sources and places, set price, bedroom and walk limits, see what enters the deck |
| Review | one listing at a time, with a map of the geography the ranker scores on |
| Settings | the anchors and priorities that hold between runs |
Ranking is geographic. rank.py weights walk to trail as its primary signal and
walk to beach as its secondary, walk.py carries 19 anchors, and the fixture
ships 5,553 cached route results. The app draws that on a map instead of
printing it as a table.
A few other things changed.
visual_summarywas populated on all 137 listings but wasn't rendered anywhere for users to look at. It leads the back of the card.- The demo server now serves HTTP range requests, which the map and the video both need.
- 49 tests were added. 42 browser tests driving the real UI, plus 7 covering the dataset builder. The suite went from 18 to 67.
uv sync
uv run playwright install chromium
uv run casita demoOpen http://127.0.0.1:8765/.
The demo is credentials-free and reads a sanitized SQLite fixture with cached route times and precomputed enrichment. It does not scrape, call Vertex, read GCS, deploy to Firebase, or call the Google Maps Routes API. It does use Playwright's local Chromium to render Open Graph preview images.
Four routes are served there.
| Route | What |
|---|---|
/ |
the review app |
/listing/<slug> |
the generated detail page, unchanged |
/og/* |
Open Graph preview images, unchanged |
/classic.html |
the single page frontend this replaced |
Nothing about the app needs a build step. It is plain modules, vendored MapLibre and PMTiles, and one generated JSON file.
uv run pytest67 tests. The browser tests drive the real page in Chromium and assert on computed values, not on markup.
make checkCompiles the modules, runs the suite, runs the public leak validator, builds the docs, builds the package, and checks the CLI imports.
Unchanged from upstream, still optional and environment driven. Copy
.env.example to .env first.
uv run casita search --headed --local
uv run casita enrich --local
CASITA_FIREBASE_PROJECT=your-project uv run casita publish --localsearch and enrich can call the paid Google Maps Routes API. publish
requires Firebase Hosting and deploys to it.
app/ the frontend
index.html one shell, three pages
js/state.js membership, one rebuild(), one subscribe
js/card.js one renderer, both faces of a card
js/map.js pins, anchors, camera, legend
js/dogs.js the reject animation
js/{scrape,review,settings}.js the three pages
js/{data,share}.js the extract, and the vote payload format
map/ MapLibre style and the basemap extract
vendor/ MapLibre and PMTiles, vendored
src/casita/app_data.py builds the app's dataset from the listings DB
src/casita/__init__.py CLI, render, and the app install step
Upstream project docs are at https://matin.github.io/casita/ and in
docs/. AGENTS.md describes the repo for coding agents.
MIT, same as upstream.