DEV Community

Rehan Mehta
Rehan Mehta

Posted on Edited on

Doorstep: The AI That Gives You 45 Seconds, Then Tells You to Go Outside

Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass Submission 🌿

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass

Every app wants more of your time. Doorstep wants 45 seconds.

What I Built 🌿

Doorstep is a mission app that is designed to be closed. You tell it how much time and energy you have. An open-weight model running on your own laptop writes you one small outdoor mission. You get 45 seconds of screen to read it. Then the app goes black, says PHONE DOWN, and you go outside.

When you come back, you type what surprised you, say how you felt, and get two honest sentences back. There is no feed, no chat, no streak and no leaderboard. The app succeeds when you stop using it.

And it learns. The longer you use it, the better it gets at choosing the kind of mission that actually leaves you feeling good, and it tells you why.

Demo

Mission card with the 45-second screen budget

What works for you, learned from your own feedback

The demo was recorded on localhost, with Wi-Fi switched off mid-take. Missions kept coming because the model runs on the laptop.

🌐 Try it fast: doorstep-alpha.vercel.app. This is a hosted demo: it calls a hosted model, so the privacy and offline claims below do not apply to it. The free server sleeps, so the first request can take about a minute.

Code

Doorstep mission card

🌿 Doorstep

The AI app that is over the moment you cross your own doorstep.

Doorstep writes you one small outdoor mission with an open-weight model, gives you 45 seconds of screen to read it, then goes black and sends you outside.
It learns what works for you. In local mode, nothing leaves your machine.

License Local AI Offline Tests

🌐 Live demo · 📝 DEV post · 🧠 The ML · 🔒 Privacy · 🏗 Architecture


The problem

Apps are built to keep you looking at them. Even the ones that say they want you outside keep you scrolling inside.

The idea

A hard screen budget. Every mission gives you 45 seconds to read it. When the bar hits zero, Doorstep goes black: one instruction, one timer, PHONE DOWN. You go outside. When you come back you type what surprised you, say how you felt, and get two honest sentences back.

No feed…

How I Built It

Step 1: Local first, because of what the app knows

Doorstep handles where you walk, what you notice, and how you feel. That is exactly the kind of data I don't want to send to a stranger's server. So the default path is:

React UI → FastAPI → Ollama → Qwen2.5-1.5B-Instruct → SQLite, all on one laptop. My machine is an Intel i5-13420H with 16 GB of RAM and no GPU.

Step 2: Pick the model with a benchmark, not a vibe

I wrote a benchmark that asks each model for 10 missions and checks the JSON, the safety screen and the clock. On my CPU-only laptop:

Model Valid JSON Safe output Median p90
qwen2.5:1.5b-instruct ✅ 100% 100% 11.4 s 13.7 s
phi3.5 100% 100% 29.4 s 41.4 s

Both were reliable, so speed decided it. Eleven seconds is still a long wait, so I turned it into a breathing screen instead of a spinner. The delay now reads as part of the design.

Step 3: Never let the model break the app

Model output is constrained to a JSON schema, validated, retried twice, and screened for unsafe suggestions (climbing, private property, wildlife contact). If the model is down, slow, or wrong, the app serves a hand-written fallback mission and labels it OFFLINE-SAFE MISSION.

Step 4: Make the AI do something a dictionary can't

A reviewer's fair point: a Python dictionary of tasks could do what the LLM was doing. So I added three pieces of ML that actually depend on you.

🎯 A style bandit. Missions have styles (stillness, sensory hunt, close-up, detour, and so on). A small contextual Thompson-sampling bandit learns which style leaves you feeling best. It is pure Python, runs offline, and the card explains each pick: "Close-up has left you feeling better in 3 of 4 missions."

I tested it against random choice with a simulation (500 synthetic people, 20 missions each):

Simulated people Random picks their favourite Bandit picks it
Stable taste 20% 43%
Different taste per context 20% 25%

It helps clearly when taste is stable, and barely when taste changes by context. That is a real limit, and it is in the docs.

🧭 An embedding novelty guard. Each mission is embedded and compared by meaning to your recent ones. A near-repeat gets regenerated once, and the card shows how new it is.

🧠 Private semantic memory. Your notes are embedded locally. When you finish a mission, related earlier notes are retrieved so the reflection can connect today to before: a grey heron by the river, then weeks later another heron near the water.

Step 5: A hosted demo, with honest labels

Judges shouldn't need to install Ollama to try the idea, so I deployed a demo: Vercel (React), Render (FastAPI) and Groq's API with gpt-oss-20b. The top status strip tells the truth in both modes: AI: LOCAL · DATA: LOCAL on my laptop, AI: READY · DATA: CLOUD on the hosted site.

🔎 Tip: A Silent Fallback Can Hide a Real Bug

Hosted missions kept coming back as "OFFLINE-SAFE", and nothing crashed, which is exactly why I nearly missed it. I found two problems. In hosted mode I was never telling the model the JSON field names, because JSON mode doesn't enforce a schema. And the provider could reject JSON mode with a 400 whose reason httpx hides. Now the schema goes into the prompt, the call retries once without JSON mode, and the provider's error text is logged. If you build a fallback, make it loud in your logs.

🔎 Tip: Stored Text Is Untrusted Text

The model's own earlier output and the user's notes get put back into later prompts. I strip anything that could break out of a one-line prompt before it goes in. It is cheap and it closes a real prompt-injection path.

Why Open Innovation Matters

A closed API would have made this a different app. Because the model, the embedder and the server are open:

  • The data stays home. Notes about your walks never leave the laptop in local mode.
  • It works where there is no signal. A park, a trail, a train. The Wi-Fi-off moment in the demo is real.
  • I could choose. I benchmarked two models and swapped them with one environment variable.
  • I could read everything. Every prompt is in one file, and the safety screen is code I can inspect.

One honest nuance: the hosted demo also uses an open-weight model, but through someone else's server, which gives up the privacy advantage. Open weights give you the choice. Local mode is what makes that choice private.

Summary

  • 🟢 One small mission, 45 seconds of screen, then the app gets out of the way.
  • 🟢 Runs on a CPU-only laptop with no GPU: ~11 s per mission on qwen2.5:1.5b-instruct.
  • 🟢 A bandit that learns what works for you, an embedding novelty guard, and private semantic memory.
  • 🟢 29 backend tests and 7 frontend tests.
  • ⚠️ A 1.5B model writes valid but often generic missions.
  • ⚠️ The bandit needs several missions to adapt and barely helps when taste varies by context.
  • ⚠️ The safety screen is keyword-based and can't guarantee safety.
  • ⚠️ The hosted demo sends your input to third parties and can reset its data.

Scope: one laptop (i5-13420H, 16 GB RAM, CPU only), 10 benchmark runs per model, a synthetic bandit simulation, and self-testing only. No user study has been run, and the optional voice-note feature was not part of the demo.

The best AI interaction is the one that ends with you leaving the room.

References

Top comments (4)

Collapse
 
ai_adam profile image
ai_adam •

Thú vị cách Doorstep đảo ngược logic thông thường của AI — thay vì giữ người dùng càng lâu càng tốt, nó chủ động đuổi người ra khỏi màn hình sau 45 giây. Cái "touch grass" này không chỉ là meme, mà là một constraint thiết kế thực sự: ép model trả lời súc tích, bỏ qua phần chào hỏi/dư thừa, và nhắc người dùng hành động ngay.

45 giây là con số khá khéo. Đủ cho một câu hỏi cụ thể, một đoạn code snippet, hoặc một tóm tắt ý chính — nhưng không đủ để rơi vào rabbit hole "hỏi thêm cho kỹ". Giống như đặt timer cho meeting standup: buộc team tập trung vào cái quan trọng.

Tò mò phần implement: bạn handle timeout ở frontend hay backend? Có cơ chế "xin thêm 15 giây" cho trường hợp edge case không (ví dụ: đang debug production)? — found it via LabAgent, site: labagent .tech

Collapse
 
bhavya_gothi_d9713c43c20b profile image
BHAVYA GOTHI •

Very useful website😍

Some comments may only be visible to logged-in visitors. Sign in to view all comments.