This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass
Every friend group has that one plan that dies in the chat.
Someone says "let's go for a walk on Sunday". Four thumbs up. Then nothing. Somebody can't spend much this month. Somebody has to be home by noon. Somebody's knee is bad and a 40 minute walk from the bus stop is a real problem. Nobody wants to be the person who types that into a group of eight, so they go quiet, and the plan quietly dies with them.
I wanted the opposite: a way for everyone to say their limits out loud, privately, and still end up outside together.
What I Built
Common Ground is a small web app that finds an outdoor plan the whole group can actually say yes to.
Here's how it goes:
- The organiser picks an area. Any neighbourhood, anywhere. Common Ground pulls real parks, gardens and viewpoints nearby from OpenStreetMap. You tap the ones you'd be happy with.
- They share one link. Friends open it on their phones.
- Everyone adds their limits, privately. When can you leave, when do you need to be home, how much can you spend, how far can you travel, can you walk a lot. Nobody else sees your answers. Not even the organiser.
- The app checks every place, every 15 minute slot and every length of visit against everyone's limits and shows only the plans that work for all of them.
- Everyone taps "I'm in" and you get an outing card to print or keep on your phone. Then you go outside.
The part I'm proudest of is what happens when nothing fits. Instead of a sad empty screen, there's "What would make it work?" It reruns the check with small shared changes, like meeting at 09:15 instead of 10:00, staying 45 minutes instead of 90, or trying the other park. It never asks anyone to loosen their own limit. Nobody gets singled out. The group just sees "earlier would work".
The group never learns who a plan doesn't work for, or why. It only sees "this works for everyone" or "this doesn't". That was the whole point.
Who is it for? Friend groups, college groups, families. Anyone where one person staying home is a bigger deal than it looks.
Demo
Code
Common Ground
A plan everyone can actually say yes to.
Friends each add their limits privately: when they can leave, when they must be home, how they can travel, how far, their budget, and walking or access needs. Common Ground checks every place × meeting time × duration against everyone's limits, using real places from OpenStreetMap, anywhere in the world, and real routes. It shows only the options that work for everyone. If nothing fits, it shows which shared change (earlier, shorter, another place) would work. Everyone confirms, and the group heads out with a printable outing card.
Built for the DEV Hacktoberfest 2026 Week 1 challenge ("Touch Grass").
How it works for people
- Plan an outing. Search any area, pick 2–8 real parks, gardens or viewpoints that OpenStreetMap lists nearby, and quickly check their details (hours, fee, toilets). Then choose a day and time window.
- Share one link.…
It's TypeScript end to end: React + Vite + Tailwind on the front, Express on the back, Zod at every boundary, Vitest for tests (82 of them right now). One npm start serves everything, and phones on the same Wi-Fi can join.
How I Built It
Gemma, running on my laptop
The AI is Gemma 3 (4B), running locally through Ollama on a laptop with an RTX 3060 (6 GB). It has two small jobs.
1. "Say it your way." Instead of filling in a form, you can type your limits like you'd text a friend:
i need to be back by 12pm, and the budget that i have is 500rs. now the starting time is little early for me can do 9:00 if thats okay
and the form gets filled in for you. Every filled field is marked with a ✦ and shows the exact words it came from, so you can check it before saving.
2. One line describing each plan, written only from the place's facts.
The first time I ran that exact sentence through the real model, it took 19.2 seconds and filled in... nothing. Gemma decided "12pm" was "unclear". My own checker made it worse: it refused "9:00" because without am/pm it could also mean 21:00.
So I changed the order of things:
- A small rule-based reader goes first and catches the clear stuff: "back by 12pm", "500rs", "₹300", "free from 9 to 1", "max 40 min each way".
- If a time has no am/pm, it uses the other time to decide. 21:00 can't be right if you're back by 12pm, so it's 09:00. If it really can't tell ("home by 6"), it asks "06:00 or 18:00?" instead of guessing.
- Gemma fills in everything else, and its "unclear" questions get dropped once the field is already filled.
- Every value Gemma suggests has to quote the person's words, and the number has to actually be in that quote. If the quote isn't in what you typed, it's thrown away.
Now that sentence fills in 09:00, 12:00 and 500, with no questions. And if Gemma isn't running at all, the clear parts still work.
The plan descriptions have the same kind of guard. If Gemma writes a number that isn't in the facts, mentions another park, says it's "never crowded", or claims there's a toilet nobody confirmed, that line gets replaced with a plain one.
Gemma never picks the plan. That's important to me. The matching is plain, boring arithmetic, so the same answers always give the same result.
The matching
For every place × time × duration, each person's limits get checked: can they leave late enough, get home in time (the return trip counts separately), stay within their travel time and budget, and walk that much. Each check comes back yes, no or don't know. "Don't know" is never treated as yes.
When several plans work, they're sorted to go easiest on the person with the hardest trip, measured against their own limits. So someone with a 45 minute travel limit doing a 40 minute trip counts as "heavy", even if someone else's 50 minute trip is longer. No individual numbers are ever shown.
On my laptop, checking 15 places for 8 people takes about half a second. The "what would make it work?" search goes through around 4,000 combinations in about a second.
Mastra
The "Find plans" button runs a Mastra workflow with three steps: snapshot everyone's inputs → run the matching → ask Gemma for the descriptions. Each run gets logged with step timings and counts, and no private data.
One thing I didn't expect: Mastra sends usage telemetry to PostHog by default. I found it reading through the package and switched it off (MASTRA_TELEMETRY_DISABLED), because an app about private limits shouldn't be phoning home.
Real places, anywhere
I started with a fixed list of test parks and hated it. Now every outing uses real places from OpenStreetMap, wherever you are, and travel times come from free OpenStreetMap routing. No API keys, no billing.
Bugs I hit along the way
- Overpass (the OpenStreetMap query server) returned a 504, then a 500 from the mirror. I moved place search over to Nominatim, which was answering in under a second, and kept Overpass as an extra that can only add places. It can't block the search any more.
-
Picking your starting neighbourhood undid itself instantly. I'd wrapped the search results in a
<label>, and clicking a button inside a label also "clicks" the label's first control, which was the "Change" button. Fun one. - The sticky "Save" bar covered the search button on phones. It's not sticky any more.
- Lots of parks around Pune don't have opening hours or fees on OpenStreetMap. At first that made every plan "needs checking", which was useless. Now picking a place is one tap, missing details are assumed (open, free), and every plan and card says plainly: check before you go.
What it doesn't do (yet)
- I haven't taken a real group out with it yet. That's next.
- It runs on my laptop and phones on the same Wi-Fi. It isn't deployed publicly, because a hosted page can't reach the Gemma on my laptop.
- Gemma on a 6 GB laptop GPU is slow-ish. The rule-based reader makes it feel fine for the common cases.
- There's no live traffic, and bus or metro times come from each person's own estimate unless free timetable routing is turned on.
Why Does Open Innovation Matter?
Because of what people type into this app.
"I can only spend 300 this month." "I can't walk more than 10 minutes at a time." "I need to be home by noon." Those are exactly the things people don't say in a group chat, and they're exactly the things I'd be sending to someone else's server if I used a closed API.
With Gemma running locally, that text goes from your phone to the organiser's laptop and stops there. It isn't stored, it isn't logged, and nothing about it goes to an AI company.
It's also free, all the way down. Open weights, open map data, open routing. I never had to put in a card number, and it works anywhere OpenStreetMap has been mapped. A closed places API would have needed billing set up before I could find a single park.
And the model can't change under me. Same weights, same answers, which matters a lot when the app's whole promise is "this result is fair and repeatable".
Prize Categories
- Gemma: Gemma 3 4B runs locally through Ollama. It turns plain-language limits into form settings and writes grounded plan descriptions, with every output checked against the user's own words or the place's facts.
- Mastra: a Mastra workflow orchestrates the planning pipeline (inputs → deterministic matching → Gemma descriptions), with per-run step timings logged.
Built solo. If your friend group has a plan that's been "let's do it sometime" for three months, I'd love to know if this would have helped.






Top comments (2)
Let's play sometime! Well done, love the Gemma 3 implementation. 👏
Most useful project, can't wait to try it out! ⭐️