DEV Community

Mike “Demo” Demopoulos
Mike “Demo” Demopoulos

Posted on AI-assisted

Grass Journal: a private voice journal that wants you to put your phone down

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

What I Built

I do my best thinking on walks. Not at a desk. Halfway around the block, when a thought finally finishes itself, and I need somewhere to put it before it's gone.

Grass Journal is the somewhere. It's a voice and text journal that runs entirely on your device. No account, no backend, no analytics. Your entries live in your browser's local database and nowhere else. It transcribes voice notes with Whisper tiny.en and writes optional reflections with Qwen2.5-0.5B or Gemma 2 2B IT, your pick. Every model runs on-device, in the browser. The app makes zero network requests.

Your thoughts stay with you. That's the whole product.

Grass-textured phone case at the stadium
Touch grass: the phone case says it before I do.

Getting people off the screen is the design brief, not a side effect. Three ways to capture a moment, each built to take seconds:

Speak. Hit record, talk, done. The app saves your audio before it does anything else, then transcribes on-device. Transcription fails? You still have the recording. Nothing uploads anywhere because there's nowhere to upload it to. This is the walking mode. Speak while you move.

Tap. The /watch/ page is a feeling wheel for your wrist. Eight feelings, one tap, saved in about ten seconds. I built it for the Apple Watch web viewer, which gives web pages no microphone and hijacks long-press to open a new tab. So: tap a feeling, put your wrist down, keep walking.

Write. A plain text editor with autosave. No toolbar fighting for your attention.

Typing an entry with autosave
Type, and it's saved on your device before you lift your thumbs.

It's for anyone who thinks better outside and wants a journal that respects that instead of competing with it.

Demo

Try it live:

Grass Journal

A private, offline-first voice and text journal. Your thoughts stay with you.

favicon grass-journal.view.fast

The 10-second version:

Full demo (54 seconds):

Feeling wheel walkthrough
Tap the hub, tap a feeling, saved. Phone resolution, real interaction.

Feeling wheel on Apple Watch, real device
The wheel on a real Apple Watch, out in the world. Ten seconds, one tap, wrist back down.

On the full app, record a voice note and watch it transcribe with the network idle. Then open the privacy screen and run the check yourself:

Privacy check running and passing
The app's own audit, runnable by anyone: "Passed — zero network requests during the test."

The AI setup screen is where you pick your reflection model:

AI setup: reflection model picker

I took it to the USMNT game. Getting through security was frustrating, so I opened the wheel on my watch and tapped how I felt — no data, didn't matter. Being able to capture it in the moment instead of reconstructing it later is the whole point. And having a way to continue my Fable journaling habit is good too.

What's verified and what isn't. The challenge grades technical execution, so here's the honest version:

  • Voice capture, transactional save, SHA-256 integrity checks: covered end-to-end in automated tests (12/12 Playwright, 50/50 Vitest on this build).
  • Whisper tiny.en transcription and Qwen2.5-0.5B reflection: verified on desktop Chrome with WebGPU.
  • Offline: it's a PWA with a full offline cache. Model weights download once, then everything runs with no connection.
  • Apple Watch: the page loads and the wheel works on a real watch. watchOS gives web pages no microphone, so there's no voice capture there. That's Apple's restriction, not a bug. It's why the wheel exists.
  • Reflection quality: these are small models. They write short, simple reflections. I claim nothing more. No WebGPU? You get a deterministic keyword fallback instead.

Code

GitHub logo Mike-Demo / grass-journal

A private, offline-first voice and text journal PWA. Your thoughts stay with you.

🌱 Grass Journal

A personal project. Built by Mike Demopoulos for personal use and shared publicly as-is. No warranties, no support queue — just the app as it runs.

A private, offline-first voice and text journal — as a Progressive Web App.

Core promise: “Your thoughts stay with you.”

No account. No backend. No cloud. No analytics. No ads. No remote transcription or hosted AI. Entries, recordings, transcripts, and reflections live in IndexedDB on your device. On-device AI (Whisper transcription, Qwen reflection) is optional manually triggered, and never blocks saving.

Product principles (in priority order)

  1. Never lose the original entry.
  2. Never send journal content to an external service.
  3. The journal works without AI.
  4. AI never blocks saving.
  5. Audio is saved before transcription begins.
  6. Original content is authoritative; AI output is optional metadata.
  7. No user account. 8. No cloud service.
  8. Brief interactions — then back to real life.
  9. Privacy claims are…

Personal project, MIT. The repo has everything: React + TypeScript + Vite PWA, Dexie.js over IndexedDB, MediaRecorder capture, encrypted backups (AES-GCM-256, PBKDF2 with 600k iterations), and the on-device AI workers.

How I Built It

Open weights all the way down:

  • Whisper tiny.en (MIT) handles every transcription, on-device, through Transformers.js in a Web Worker.
  • Reflection runs on-device through WebLLM, also in a worker, and you choose the model: Qwen2.5-0.5B-Instruct (Apache 2.0, default, ~450 MB) or Gemma 2 2B IT (Gemma Terms of Use, ~1.5 GB, usually richer). The worker loads whichever you picked. Every saved reflection records the model ID and the versioned system prompt, so you can always trace what wrote it.
  • The prompt asks for JSON and the client validates the reply, retrying once with a repair prompt when parsing fails. I skipped grammar-constrained decoding on purpose: WebLLM's xgrammar WASM won't initialize on iOS WebKit. Plain code validation instead.
  • No WebGPU, no problem: reflection falls back to deterministic on-device keyword tags. AI never blocks saving. The entry saves first, always.

Full credits for every library, model, and tool — with licenses — are on the open-source credits page.

And the disclosure the challenge asks for: I built this October 5–6, inside the challenge window, with an AI coding agent (Muse). I set the architecture, the privacy constraints, every product call. The agent wrote code; I verified it against the test suites and real devices.

Yes, there's irony in using a cloud-scale model to build the thing that frees you from cloud-scale models. I'll take it.

Why Does Open Innovation Matter?

I don't want my journal entries on someone else's server. That's the whole reason this app exists in this form.

Every journaling app with cloud AI asks you to make the same trade: hand over your most private thoughts so a model you can't see can process them on hardware you don't control. The privacy promise is always a paragraph in the terms of service. I've read enough of those paragraphs to know what they're worth.

Open weights end the trade. Whisper, Qwen, and Gemma run on my device, in my browser. Nothing leaves. And you don't have to take my word for it, which is the part I like best: the privacy screen runs a check that intercepts every network request and shows you the result. Try getting that from a closed API. The most sensitive part of their app is a black box they rent by the token. Mine is code you can read and models you can download yourself.

Three more places the open approach wins, concretely:

It works where journals get written. I take this outside. A closed-API journal dies without signal, which is exactly when you want it. That's not a limitation; it's a design contradiction. Local inference resolves it.

It costs nothing per entry. Metered APIs make you ration the feature. A local model makes it free to use and free to ignore. I reflect on walks, not on budgets.

You can change its mind. Two models on one screen, switch whenever. The model is a file. Not a vendor relationship, not a pricing page.

The closed alternative isn't a worse journal. It's a journal that ships your inner life to infrastructure you don't control. I built the other one.

Prize Categories

  • Overall prize
  • Best Use of Gemma — Gemma 2 2B IT runs locally via WebLLM as a first-class reflection model. Install it from the AI setup screen, and the entry screen uses it.

Hat tip

This build was inspired by apps that take inner life seriously:

Fable - Live a Better Story Through AI Journaling

AI-powered journaling that reveals the epic story your life is already telling

favicon getfableapp.com

Top comments (0)