This is my submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass.(https://dev.to/challenges/hacktoberfest-week1-2026-10-05)
The problem: “take a break” is easy to ignore
A lot of us spend hours at a computer. When we finally get a small gap between tasks, the default break often becomes another screen: a quick video, a game, a feed, then “just five more minutes.”
I noticed that telling myself to take a break wasn't particularly motivating. Generic advice like “go for a walk” can feel like one more chore, especially when I'm not already in the mood to exercise or go outside.
What does motivate me is having a reason to do something: a small thing I've been putting off, an interesting place to explore, a useful errand, or a story that makes me curious about what happens next.
So I wanted to try a different question:
What if a break wasn't another reminder, but a quest worth leaving the screen for?
That idea became GrassQuest.
It's built for the people most likely to recognize that pattern: developers, students, and remote workers who spend long stretches at a screen and find that "take a break" is easy to agree with and easy to ignore.
🌿 What is GrassQuest?
GrassQuest is a local-first AI quest game. It turns a user's real backlog, current situation, available time, and ongoing narrative into a few small quests. The player picks one, leaves the screen to do it, and returns to report what happened.
The core philosophy is:
The AI designs the quest. The human does the gameplay away from the screen.
The screen is where the quest begins. The real world is where you play it.
This isn't intended to be another productivity dashboard full of streaks, coins, and metrics. I wanted the story and the real-world action to be the reward—not a points system that gives users another reason to stare at the app.
🧭 How the loop works
1. Give the quest designer something real
The user adds tasks they're postponing, along with a context (home, work, outside, or personal) and a rough time estimate.
That backlog matters because a break doesn't always have to mean a walk. Sometimes the most useful nudge is to clear the coffee pot, water a plant, tidy one small area, or finally do a five-minute task that has been hanging around all day.
2. Choose the scene
The user selects their current context and how much time they have. GrassQuest filters the backlog on the backend so a home break doesn't receive a task that can only be done at work.
The local model then proposes three options: backlog quests, spontaneous real-world activities, or story-driven quests. Each should be achievable within the selected time and shouldn't require special equipment, spending money, location tracking, or another app.
3. Pick one—and put the screen away
The player chooses a quest and gets a clear action to do. Then the important part begins: they leave the screen and do it.
This is a deliberate design constraint. The instructions should be clear enough that the user doesn't need to keep checking their phone or computer every minute.
4. Return and tell the story
Afterwards, the user describes what happened in free-form text. The model interprets the report, suggests progress on any linked backlog task, and writes a small continuation of the ongoing story.
Sometimes a report reveals another task worth remembering. GrassQuest can suggest adding it to the backlog, but it asks first; it doesn't silently turn every passing thought into another obligation.
Completed attempts and story chapters are saved so the user can look back on what they did. The narrative is meant to provide continuity and curiosity, not pressure.
📖 Why narrative instead of points?
I considered the familiar gamification toolkit—XP, coins, streaks, badges—but it didn't feel like the right fit.
A points system can make the app itself the focus. GrassQuest is trying to do the opposite. I wanted the player to wonder what happens next in the story, or feel a little satisfaction from resolving something in their real life.
That means the AI has a specific role: it is a quest designer, not a boss. It offers choices rather than issuing commands. The user can choose a different quest, report partial progress, or skip one.
The story is also a work in progress. Switching between contexts such as work and home can make generated scenes feel disconnected, especially with a smaller local model. I'm addressing that by passing the previous story state and scene context into the prompts, and by instructing the model not to invent a physical journey just because the selected context changed. Prompting helps, but it doesn't make narrative consistency perfect.
🧠 Why open-weight AI—and why local inference?
The model isn't just answering questions in a chat window. It performs two central jobs in the experience:
- Quest generation: turn context, available time, eligible backlog tasks, and story state into three actionable choices.
- Quest resolution: interpret the user's report, suggest task progress, identify a genuinely useful new backlog item when appropriate, and continue the story.
GrassQuest uses an OpenAI-compatible API, so the backend can work with local runtimes such as Ollama or LM Studio. I've been developing it with local models Qwen3.5-9B and gemma-4-12b-it-qat.
Local inference is a meaningful choice for this kind of application. Prompts can contain personal tasks, routine details, and free-form reports about how someone's day went. Keeping inference on the user's machine means that, with a local endpoint, this information doesn't need to be sent to a hosted AI provider for the core loop.
It also keeps the model replaceable. Open weights make it possible to try different models and compare latency, instruction following, structured output reliability, and story quality without tying the application to one closed-model API.
There is a trade-off: running a model locally requires compatible hardware and setup, and generation can be slow. On my setup, model latency and occasional JSON or storytelling oddities are real constraints. A better model may improve the experience, but the application still needs validation and explicit continuity rules rather than assuming the model will always get everything right.
Local inference also isn't a blanket claim that every possible deployment is offline or private. Those properties depend on the configured endpoint. GrassQuest is designed for a local endpoint, but anyone who configures a remote provider should understand where their prompts are sent.
🛠️ How it's built
The prototype uses a small, straightforward stack:
| Component | Role |
|---|---|
| React + Vite | Backlog, quest board, story view, report form, and history UI |
| Python + FastAPI | API, input validation, context filtering, quest lifecycle, and persistence |
| Ollama or LM Studio | Local OpenAI-compatible inference |
| JSON file storage | Backlog tasks, story chapters, and resolved quest history |
Here's how the pieces connect:
flowchart LR
A["React + Vite app"] -->|"REST /api"| B["FastAPI backend"]
B -->|"state, validation"| C["server/store.py · JSON"]
B -->|"OpenAI-compatible /v1/chat/completions"| D["Local open-weight model<br/>Ollama / LM Studio"]
D -->|"structured JSON quests & updates"| B
C -->|"backlog + story state"| B
B -->|"quests, resolutions, story"| A
The browser only ever talks to the FastAPI backend. The backend decides which backlog items are eligible, builds a compact prompt from the smallest relevant state, and validates whatever the model returns before any state changes. The model never writes to the store directly — that's deliberate, because a local model without persistent memory shouldn't be trusted to.
I chose Python for the backend because the project is AI-heavy and I already work comfortably with Python and APIs. React is the frontend, and building this prototype is also a way for me to learn more of its state and component model by making something real.
I deliberately kept the first version small. There are no accounts, cloud database, location APIs, camera verification, leaderboards, or multiplayer features. The aim was to get the core loop working before building a larger platform around it.
🧪 What works in the current prototype?
The current manual flow supports:
- Adding backlog tasks with context and estimated duration.
- Editing or deleting active backlog tasks.
- Generating three quests for the selected context and time window.
- Choosing and completing a quest with a free-form report.
- Updating task progress and story state from that report.
- Suggesting a new backlog item for user approval.
- Saving story chapters and a reviewable quest history.
- Running the AI through a configurable local OpenAI-compatible endpoint.
I've been testing the loop locally, including backlog-linked and spontaneous quests, task suggestions, and persistence. This is still a prototype, not evidence that the app has already improved anyone's long-term screen habits. The next meaningful test is to use it repeatedly during real breaks and see whether the quests actually make it easier to step away.
⚖️ What it doesn't do yet
The long-term vision is more automatic than the current prototype.
Eventually, I'd like GrassQuest to notice broad patterns of active and idle screen use, respect user-defined work hours and quiet periods, and gently prompt the user when a long stretch at the screen has passed. After a meaningful break, it could start a fresh interval.
That monitoring isn't implemented yet. The current quest loop is started manually.
A reliable cross-device version is also future work. Monitoring a desktop, browser, phone, and tablet isn't just a matter of syncing one timer: each platform has different background and permission restrictions, and simultaneous activity across devices needs a clear counting rule. I'd rather build that carefully than claim that a web page can observe everything happening on a computer or phone.
Other current limitations include:
- The model can produce awkward or inconsistent story prose.
- Cancellation can stop GrassQuest's outgoing request, but whether the model runtime immediately stops GPU inference depends on the runtime.
- JSON persistence is suitable for a single-user prototype, not a production multi-user service.
- The backlog accepts any task, including one that would be done at a screen. Since the point is to leave the screen, a future filter should notice screen-oriented tasks and ask the user whether they really want to add one. What that filter should do exactly is still an open question.
- The app relies on the user's report rather than invasive proof of completion.
- Automatic reminders, accounts, and cross-device sync are not available yet.
These are deliberate boundaries for a first version, not hidden features.
🚀 What's next?
My next priorities are to improve story continuity across different real-world contexts, make backlog editing and completed-quest history comfortable to use, and polish the setup instructions and demo.
After the Week 1 prototype, the next larger milestone would be a desktop companion that can measure broad active/idle periods with clear user permission and trigger a gentle reminder. I'd then explore user-controlled schedules and, later, cross-device sync.
I don't want to turn GrassQuest into another application that demands constant attention. Its success shouldn't be measured by time spent inside the app, the number of buttons clicked, or the length of a streak.
It should be measured by whether it gives someone a good reason to close the app and do something in the world.
🔍 Show your process
The challenge asked builders to show how the project came together, and that show-your-work part is one of the better parts of this format. Most of the work happened in short sessions during the Week 1 window (Oct 5–11), in a tight loop: change a prompt or an endpoint, restart, run a real quest through the local model, and inspect the JSON that came back.
That loop caught a bug worth mentioning. The completion endpoint built one of its prompts as an f-string with unescaped literal braces, so every report failed before it ever reached the model. Nothing about the code looked wrong on its own — it took an end-to-end run to expose it. Working with a slow local model had a similar effect: waiting on it made it easy to tell which failures were the model's (occasionally awkward prose) and which were mine (prompt structure and missing validation). I added a small dependency-free test around the prompt-and-parsing layer so that second kind of failure stays fixed.
🖼️ See it live
The quest begins on the screen, then gets out of the way. Here is the loop:
Demo video: [https://drive.google.com/file/d/1E6vnzE8sb2a9I2IzQqb3aTaTFSHigzcM/view?usp=drive_link]
Run it locally: follow the README —
cp .env.example .env, set your local model,npm run devAll screenshots: docs/screenshots
🏅 Prize categories
-
Best Use of Gemma — GrassQuest runs on any OpenAI-compatible local endpoint, so the model is a configuration value, not an architecture decision. I verified the full loop on Gemma: I generated the three quests and then resolved the report with
gemma-4-12b-it-qatserved locally through LM Studio, changing onlyAI_MODELin.env.
On my 8 GB GPU, each call took roughly two to three minutes (about 161s to generate the quest set and 128s to interpret the report). That's slow — but it's still a good fit for a break that lasts minutes, and it's honest about the trade-off of running a 12B model locally. What mattered was reliability: Gemma returned valid JSON on both calls, kept the linked backlog task intact, produced a coherent narrative frame, and picked up a genuinely useful new task from my report ("Scrub the dish rack") instead of padding the field. Its prose was arguably more atmospheric than the smaller model I'd been using — which underlines the point that the model is the replaceable part and the loop, context filtering, and JSON guardrails are the product.
🌱 Final thought
I started with the familiar problem of spending too long at a screen and the equally familiar advice to “just take a break.” GrassQuest is an experiment in making that break feel less like an instruction and more like an invitation.
Sometimes the thing that gets us moving isn't a reminder that we should do something good for ourselves.
It's a small unfinished quest, and the desire to find out what happens when we go and do it.
Project: GrassQuest
Built for: Hacktoberfest Open-Source AI Challenge — Week 1: Touch Grass
AI: Configurable local open-weight model via Ollama / LM Studio
Code: https://github.com/Jorawar-Singh/GrassQuest
Demo: https://drive.google.com/file/d/1E6vnzE8sb2a9I2IzQqb3aTaTFSHigzcM/view?usp=drive_link
Stack: React + Vite · Python + FastAPI · local open-weight LLM · JSON persistence




Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.