Inspiration

Recently, Toronto lived through a wildfire-smog season, and much of the online argument was about policy, which decisions amplified a natural disaster into a public-health event. We noticed two things. First, climate-policy debates run almost entirely on rhetoric, while satellites have been quietly keeping receipts for 40 years, nobody was connecting the two. Second, the tempting AI product here: "paste a policy, get a 30-year climate forecast" is exactly the thing a language model shouldn't do. It's confident confabulation, and any expert judge would dismantle it in ten seconds. So we flipped the question. Instead of predicting the future, Downwind retrieves precedent: "Here's what measurably happened, from orbit, in places that already tried a policy like this one."

What it does

You paste a policy, either a climate law, or an economic one that never mentions the climate (a zoning change, a fire-suppression budget cut, an agricultural subsidy). Downwind:

  1. Extracts its mechanisms with Gemini: sectors, causal levers, geography, deliberately surfacing the hidden economic levers that quietly move the climate.
  2. Retrieves real enacted analog policies via MongoDB Atlas Vector Search, and re-ranks them with Gemini to confirm they're genuinely comparable in mechanism and context.
  3. Grounds the answer in real satellite before/after imagery and numeric deltas (NDVI, burn severity, fire counts) for the analog regions, with a vision model corroborating that the picture agrees with the numbers.
  4. Reports three horizons with honest epistemic labels — 3y observed, 10y extrapolated, 30y speculative and flagged — and translates near-term impact into a visceral local metric ("≈ +6 smoke days/year in Toronto").
  5. Shows its receipts. Every claim links back to the analog and dataset it came from, plus a carbon receipt reporting tokens / Wh / gCO₂e per analysis.

How we built it

A Next.js 16 / React 19 / TypeScript frontend owns the UI, Gemini calls, MongoDB, and Auth0; a thin Python FastAPI sidecar owns everything geospatial, because Node's EO ecosystem is weak and Python's is mature. The two talk through one shared JSON contract (mirrored as a TypeScript type and a Pydantic model) that grows as it flows through the pipeline — which meant any layer could be stubbed and the demo still ran. Gemini handles extraction, embedding, and re-ranking; MongoDB Atlas does vector search + a 2dsphere geo-index + result caching in one datastore; Auth0 does passwordless magic-link login with MFA. For real imagery we went REST-first: Sentinel Hub on CDSE for 10m before/after PNGs and numeric NDVI/NBR deltas, with NASA GIBS as a zero-auth fallback and NASA FIRMS for fire counts, deliberately avoiding Google Earth Engine's multi-day verification wait. Vision corroboration runs on a local Gemma-3-4b model via Ollama, precomputed on-laptop and cached in Atlas. The orchestrator is a plain sequential driver since LLM-generated geospatial code fails to run over half the time.

Challenges we ran into

  1. Keeping the AI honest. The impact-evaluation literature shows naive before/after comparisons overstate avoided deforestation by 50-65% due to non-random siting. Our answer was a strict discipline: the LLM never produces a number, every number is provenance-tagged, and we ship a precomputed, cited difference-in-differences counterfactual rather than inventing one.
  2. Gemini's sharp edges. responseSchema doesn't validate value ranges (we added our own guards), and forcing verbatim policy quotes kept tripping RECITATION blocks that masquerade as malformed output. We also lost two runs to the free tier silently capping gemini-2.5-pro at zero requests, resulting in everything had to move to Flash.
  3. Real satellite data on a deadline. OAuth token refresh, cloud-cover mosaicking, season-matching windows (or you measure seasonal swing, not policy effect), and the CDSE API paths having just changed in March 2026 all ate time. The zero-auth GIBS fallback is what made a live demo survivable.
  4. Vision without a cloud VLM budget. Getting multimodal Gemma running locally and caching its reads so production (Vercel, no Ollama) could serve them.

Accomplishments that we're proud of

For a beginners team, we completed a lot of work over the hacking period. In particular, we gathered real satellite imagery and deltas end-to-end with a fallback path that means the demo can't be killed by a flaky API.

What we learned

We should draw a clean seam between "the model interprets" and "tested code measures," and both halves get simpler.

What's next for Downwind

  1. Live EO on demand. Wire the Sentinel-2 / GIBS image-pair fetch into the request path instead of precompute, with the counterfactual "recompute live" button.
  2. Policy diff. Paste two competing bills, get side-by-side impact cards.
  3. A self-consistency / narrative-stability meter and a real historical satellite timelapse of the analog region as the closing visual — footage of what actually happened, never a generated future.

Built With

Share this project:

Updates