Inspiration

Local information is scattered. One neighbour posts about a water leak, another mentions a road closure in a group chat, and someone else repeats what a friend told them. Neighbourhood apps show each of these as a separate post or pin, ranked by engagement. You can't easily tell what's true right now, what has changed, or what nobody knows yet. The same rumour repeated ten times looks like ten confirmations.

I wanted to build something that answers one question: what does the available evidence currently support about this local situation?

## What it does

Nearhood turns scattered neighbourhood reports into Happenings: real situations that change over time, like a burst pipe, a power outage or a trunk-or-treat. Every claim links back to the evidence behind it.

  • Report: a neighbour describes what they saw in their own words. They say whether they saw it themselves or heard it from someone, when they saw it, and where (by place search or a map pin). Their original words are always kept and can be read.
  • Observation: Nemotron breaks the Report into structured claims: what, what state, when, and which part of the place. Each claim traces back to the Report it came from.
  • Happening: Nearhood checks whether the new Report describes something already on the map. The model suggests the Each claim traces back to the Report it came from.
    • Happening: Nearhood checks whether the new Report describes something already on the map. The model suggests the best match and cites its evidence, and the contributor confirms the match before anything changes. Five differently worded reports about one leak become one Happening, not five pins.
    • Shared Account: a provisional summary of what the evidence supports. Tap any statement to see the Observations behind it and the neighbour's original words.

The design rules behind it:

  • Popularity isn't evidence. Ten reports quoting the same source aren't ten confirmations.
  • When it was seen is not when it was posted. An old sighting submitted late doesn't become the latest state.
  • Disagreement is data. "North entrance blocked" and "south entrance open" can both be true.
  • Unknowns stay unknown. The model never fills gaps with plausible-sounding details.
  • AI output is derived, never the evidence itself.

How I built it

  • Stack: Next.js on Vercel, with Supabase Postgres + PostGIS for spatial queries. The database is only reached from server code, never from the browser.
  • Map: Leaflet with MapTiler tiles over Detroit. The demo uses everyday scenarios on real street names.
  • AI: NVIDIA Nemotron 3 Ultra through Nebius Token Factory, used in two separate steps:
    1. Extraction: turns a Report into structured Observations.
    2. Matching: compares the Report against a small set of nearby candidate Happenings found by a PostGIS search, using their original evidence. The model can only choose a candidate ID I supplied, or answer "no plausible match" or "uncertain".
  • Prompt engineering, no fine-tuning: strict JSON schemas, temperature 0, thinking disabled for speed, and required evidence citations. I went through seven extraction prompt versions and six matching versions, each fixing a failure seen in testing.
  • Checking the model in code: my code assigns every ID and timestamp, checks every reference the model returns, and never lets the model write to the database. If a step fails, the saved Report stays safe and can be retried, and a failed search is never treated as "no match".
  • Testing: Playwright tests run against the real app, API and a real Postgres/PostGIS database at mobile and desktop sizes. I also ran a live model evaluation in which each case runs three times and every request and response is saved.

Challenges I ran into

  • Deciding when two reports describe the same situation. "Water on Elm St" this morning and "pipe fixed on Elm" tonight are one Happening, but a new leak next week might not be. I settled on a rule: a Happening follows the real situation, not its category or location.
  • Keeping the model honest. Free-form answers invented details and IDs. A fixed list of choices, required citations and code-side checks solved this. Splitting one combined call into separate extraction and matching steps took my pass rate from 3/8 to 7/8 on the same test cases.
  • Handling uncertainty without forcing an answer. When a match is ambiguous, Nearhood shows a visible "possible connection" instead of silently merging or splitting Happenings.

Accomplishments that I'm proud of

  • A deployed app where you can tap any claim and follow it back to a neighbour's original words.
  • An end-to-end contribution flow: sign in, report, extract, review the suggested match, confirm, and watch the summary update.
  • In 144 live matching calls, Nemotron almost never merged unrelated situations. When it was wrong, it usually said "uncertain", which is the safe mistake for a trust-focused product.

What I learned

  • Wording and the data model matter as much as the AI. Most of the hard decisions were about what a "Happening" is, not about prompts.
  • Asking a model to choose from fixed options and checking its answer in code is far more reliable than letting it write answers freely.
  • Testing through the real product, without mocking my own database, caught problems that unit tests would have missed.

Built With

Share this project:

Updates

Submission history