This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass
What I Built
My laptop has been quietly charging me interest. Not money. Minutes outside.
Grass Owed is a local-first web app that turns screen time into outdoor debt. For every 10 minutes on a screen you owe 2 minutes outside (both numbers are settings). Walking pays it back, and whatever you don't pay carries over to tomorrow. Like a loan, except the lender is a park.
It reads your calendar (an .ics file; only start and end times are kept, never titles) to find free gaps, and scores each gap with a weather comfort model for your town. Then it nudges you, but only at sensible moments:
- at most three nudges a day
- quiet from 22:00 to 07:00
- a 90-minute cooldown
- never during an event
- never for tiny debts
It also knows when to tell you not to go. At 2 PM on a June day in Jaipur (39 °C) it says: stay in, go out in the evening. An app that tells you to skip the walk is, I think, an app you can trust.
I built it for myself: phone at college, laptop in the hostel. It's for anyone who sits at a screen all day and keeps meaning to go outside.
Demo
In the video: a walkthrough of Grass Owed working, from the debt counter and the best free gap to a nudge appearing and the debt going down.
Note: I added this video on 12 Oct 2026 after 5 minutes of deadline. The app itself is unchanged.
Run it yourself: clone the repo, open a terminal in the app folder, run python -m http.server 8000, and open http://localhost:8000.
Want to see what it says at a different time of day? Add ?t=2026-06-10T14:00 to the address and time-travel to a very hot afternoon.
A few real nudges from the app:
Time for a little fresh air. You have 6 minutes owed.
The weather is nice. Try a quick walk now.
The 32 degrees C are perfect for a quick break.
Code
Grass Owed: You owe the park
Tracks how much outdoor time you owe, finds the best free gap in your day, and nudges you to go outside with short, funny notifications.
Built for the Hacktoberfest Open-Source AI Challenge, Week 1: Touch Grass (DEV) Project started 7 Oct 2026, inside the challenge window (5-11 Oct 2026). Any commits after the deadline will be listed under "Post-deadline commits" below.
Status: work in progress.
What it is
- Debt is the score: a daily outdoor-minutes goal and a balance that carries over.
- Gaps come from your calendar file (.ics), so suggestions fit your real day.
- Comfort comes from a TabPFN model trained on historical weather, so it will not send you out at 2 PM in a hot month.
- Tone is your choice (gentle, funny, cheeky). Gemma writes the words; plain code decides when and what.
Architecture
- Build time (Colab, run once): TabPFN turns…
How I Built It
The rule I set myself: the models do their work once, in Colab, and ship two tiny files. No model and no server at runtime.
TabPFN: "when is it actually nice outside?"
I pulled 4 years of hourly weather for Jaipur from Open-Meteo (apparent temperature and rain), held out the most recent 12 months, and ran a face-off: a simple baseline (average by month and hour) against TabPFN-3.5 running locally in Colab. TabPFN trained on a 10,000-row sample. The output is a 12 x 24 lookup file, comfort_table.json, about 13 KB.
| Model | MAE on held-out year (apparent temp, °C) |
|---|---|
| Baseline (mean by month and hour) | 2.340 |
| TabPFN | 2.303 |
TabPFN wins! By about 0.04 °C, roughly 1.6%. I'll be honest: that's one split scored on a 5,000-row sample, so it could be noise. I'm reporting it as it came out, because a tiny honest win beats a big imaginary one.
Gemma: "say it like a friend, not a calendar"
I ran Gemma 4 E2B (google/gemma-4-E2B-it, Apache-2.0) once on a free Colab T4 to write the nudge lines: 180 lines across 6 situations and 3 tones (gentle, funny, cheeky), 10 per combination. The app started with 36 hand-written placeholder lines, so this is five times the variety.
I didn't trust the model blindly. Plain code checks every line for length, allowed placeholders (like {best_time}), required details and banned words before it's kept. Of 181 lines Gemma returned, 180 passed (99.4%). The one rejected line invented a placeholder that doesn't exist, which is a very creative way to fail.
Generation took about 20 seconds per call (18 calls, roughly 6 minutes total, about 2 seconds per kept line), and lines average about 60 characters. The result is one small JSON file, so nudges work with no signal.
The app
A vanilla JavaScript PWA with no backend. The logic (debt ledger, .ics parser, gap finder, rules engine) lives in one pure module with 8 Node tests. A service worker caches everything so it opens offline.
On a laptop it counts screen time automatically with the browser's Idle Detection API (Chrome or Edge). On a phone you use start/stop buttons, because browsers can't read phone screen time.
How the debt moves
With laptop auto-tracking on, every 10 minutes of active use adds 2 minutes of debt, so it keeps climbing for as long as you work. Walking pays it back one minute for one minute, so a 20-minute walk clears 20 minutes of debt, which is what 100 minutes of screen time creates. Debt never goes below zero and carries over to the next day.
I Actually Went Outside
Yes, I tested it outdoors, which feels like the least I could do for a Touch Grass challenge. On 12 October 2026 I went outside for 20 minutes with the app's "I'm out" button running, and my debt went from 40 to 20 minutes.
What worked
- The debt number dropped as soon as I tapped "I'm back", and it matched the minutes I was outside.
- Laptop auto-tracking counted my screen minutes without me pressing anything.
- A Gemma-written nudge showed up on the screen.
- It kept working with the network off.
What didn't, or isn't done
- The TabPFN improvement is tiny.
- Rain probability per hour is noisy (about 120 days per cell), so comfort scores jump a little between neighbouring hours.
- Calendar time zones are ignored, and repeating events are only expanded daily and weekly for 14 days.
- Notifications only fire while the app is open. Reliable delivery to a closed phone app needs a push server, which I didn't build.
- Laptop auto-tracking works only in Chrome or Edge on desktop.
- It isn't deployed to a public URL, so the demo runs locally.
Why Does Open Innovation Matter?
Because this app knows your calendar and your screen habits, and that is exactly the kind of data you don't want to send to someone else's server.
Open weights meant both models could run in a free Colab notebook, and their output became two tiny files. There's no cloud API at runtime, no per-request cost, and no personal data leaves the device. Open weather data from Open-Meteo made the training set free to get.
One honest note: TabPFN's weights are free for non-commercial use under Prior Labs' licence, so this is a hackathon project and not a product.
Prize Categories
- Best Use of TabPFN: it predicts outdoor comfort by month and hour from historical weather, exported as the lookup the app uses, with the error reported against a simple baseline.
- Best Use of Gemma: Gemma 4 E2B wrote the app's 180-line nudge bank, with code validating every line.
Credits: weather data from Open-Meteo. The comfort table was generated with TabPFN-3.5 by Prior Labs GmbH under the TabPFN-3.5 Non-Commercial License. Gemma 4 by Google DeepMind (Apache-2.0).



Top comments (0)