This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass
What I Built
In Belgium the weather gets a vote on every workout: is it nice enough to go out, or is it another day inside? A weather app doesn't really answer that.
workout-suggester answers it for you. You tap 📍 Here and pick what you're up for (run, ride, walk, or "surprise me"), how hard, and how long. A few seconds later you get:
- Scores for the next hour or two: run, ride and walk each scored 0–100 for the actual weather window, with the reasons ("strong gusts up to 50 km/h", "dark: bring lights").
- A pick and a plan: what to do, when to go, a warm-up / main set / cool-down that fits your intensity and time, what to wear, and a plan B. If it's truly grim, it sends you inside with a concrete HIIT session instead.
- A route: a loop of the right length that starts and ends at your door, heading out into the wind so you come home with a tailwind. Nearby signposted OpenStreetMap routes (fietsroutes, wandelroutes, the nearest knooppunt) are listed too. Every route has a GPX download for your watch or bike computer.
- Follow-ups: "make it harder", "I only have 30 minutes".
The screen part takes about a minute. After that the GPX is on your watch and your phone stays in your pocket.
It's for anyone who wants to move more but loses the first 20 minutes to weather apps and indecision.
Demo
On a phone, which is where you'll use it:
Code
git.b0b.be/bdeb/workout-suggester
It's one ~9 MB Go binary. Point it at any OpenAI-compatible model server and run it:
cp .env.example .env # LLM_BASE_URL=http://127.0.0.1:8000/v1 (oMLX), or llama.cpp, Ollama, LM Studio...
make run # → http://127.0.0.1:3000
How I Built It
The model: Gemma 4 E2B, running locally. I used gemma-4-E2B-it-qat-4bit through oMLX on a MacBook. Any OpenAI-compatible server works (llama.cpp, Ollama, LM Studio), and you swap models with one environment variable. A plan streams in about 10 seconds.
Stack: Go, Templ and HTMX, with the model's reply streamed over server-sent events. A Leaflet map shows the routes. The stack comes from my previous week's project and stays small and fast.
The most important design decision: don't let the small model do the maths. A 2B model will happily say "light breeze" about 50 km/h gusts, or invent a sunset time. So the work is split:
- The weather comes from open data. Open-Meteo is open source and needs no key. If it's overloaded (that happened during the build), the app falls back to MET Norway, then to the last forecast it had. MET Norway has no gusts for Belgium, so gusts are estimated from wind speed and marked "≈". Sunrise and sunset are calculated locally.
- Plain Go rules do the scoring. Each activity starts at 100 and loses points per condition, weighted by activity. Gusts over 45 km/h cost a ride 40 points but a run only 15. Heavy rain costs everything a lot. Thunder is a flat zero. Below 40 everywhere, you go inside. The app also looks 12 hours ahead for a clearly better daylight window ("better at 17:00").
- Routes come from open routing. BRouter generates round trips from your door in three directions, starting into the wind. Overpass finds signposted OpenStreetMap routes nearby and the nearest knooppunt. BRouter's round-trip parameter turned out to behave like a radius (ask for 10 km, get ~51 km), so the app scales it down. Long-distance trails like the 130 km Streek-GR get filtered out.
- Gemma writes the plan. All of that goes into the system prompt as a short sheet of facts: the weather, the scores and reasons, the pick, the target distance and pace, and the routes with their climb, paved percentage and wind direction. Gemma does what small models are good at. It explains the pick in plain language and builds a workout around it, and follow-ups like "only 30 minutes" can reshape the session.
Splitting it like this is what made E2B good enough. It never decides whether it's safe to ride. It gets told, and it explains.
Why Does Open Innovation Matter?
Every part can be self-hosted or swapped. The model, Open-Meteo, Overpass and BRouter are all open source, and each has one environment variable to point it at your own instance. When Open-Meteo went down mid-build, adding a fallback was a small change, not a vendor problem. If E2B isn't good enough, I switch LLM_MODEL to E4B, no new API key or pricing page needed.
It costs nothing to run. There's no per-token bill for a question I ask every morning, and no subscription for weather or routing.
OpenStreetMap knows the local routes. Flanders has signposted cycling and walking networks, numbered junctions and small park loops. They're all in OSM, mapped by volunteers. No closed fitness API gives me that for free, and none would let me generate a loop from my front door that heads into the wind first.
Route data keeps working without a connection. Signposted routes are cached on disk for a week, and the GPX goes to your watch. Once you've planned, you don't need the screen or the signal.
A closed stack would have given me a nicer chatbot and a worse product. The useful part is having the data, the routing and the model under my own control, glued together with about 3,000 lines of Go.
Prize Categories
- Best Use of Gemma. Gemma 4 E2B, running locally, is the coach: it turns rules-based weather scores and OpenStreetMap routes into a concrete workout plan, and handles the follow-ups.


Top comments (0)