DEV Community

Cover image for I built a private offline journaling tool for my group of friends. Powered by Local Gemma
Sara Aniceto
Sara Aniceto

Posted on

I built a private offline journaling tool for my group of friends. Powered by Local Gemma

Hacktoberfest Weekend Challenge: Build for a Friend Submission 🤝

This is a submission for the Hacktoberfest Weekend Challenge: Build for a Friend

What I Built

Within — private journaling with local AI

My friends and I are trying to spend less time mindlessly scrolling through social media. We noticed how easily scrolling can become a way to avoid sitting with our feelings, so we encourage each other to write about what we are experiencing.

But writing by hand does not work for everyone. Some friends told me they often turn to ChatGPT to vent about their feelings. I wanted to give them a digital place to journal, with a little help when they cannot find the words or untangle a feeling on their own.

That is why I built Within: a quiet journaling space with gentle reflection questions and mood-based writing prompts, powered by a model running on the user's own computer.

For me, a more ethical approach meant making privacy a concrete design choice: journal entries stay in the browser, and AI requests go to local Ollama rather than a cloud AI service. Within does not upload entries for model training or train a model on them.

The goal is to support the writing habit we are building together, with a place to pause and pay attention to ourselves.

Within offers:

  • A distraction-free writing page.
  • Reflection questions based on an entry.
  • Short writing prompts for anxious, grateful, reflective, or bored moods.
  • History saved in the browser, with no account required.
  • A local-model selector and connection help.

After a successful save, the writing field clears for the next entry. “Write about this” replaces the previous text with the selected prompt. The app remains usable for writing and saving when AI is unavailable.

This is a writing aid, not therapy or professional support.

Demo

Write Ideas History
Writing page with reflection questions Mood-based writing prompts Saved journal entries

Try Within on Render

To try the AI, open the site on a computer running Ollama. The site is the interface; the model runs on that same computer.

  1. Install Ollama.
  2. Download a local model with ollama pull gemma3:1b.
  3. Allow https://within-offline-journal.onrender.com in OLLAMA_ORIGINS and restart Ollama.
  4. Allow local network access if your browser asks, then click Reconnect.

The README includes instructions for macOS, Windows, and Linux. On macOS/Linux, with any existing Ollama server stopped, you can run:

OLLAMA_ORIGINS="https://within-offline-journal.onrender.com" OLLAMA_NO_CLOUD=1 ollama serve
Enter fullscreen mode Exit fullscreen mode

The site also opens on mobile for writing and history. The current AI integration is for the same computer: localhost on a phone refers to that phone, not a laptop.

After the app shell is cached and the model is installed, the design supports offline use while local Ollama remains running. Saved entries belong to that browser and site origin; browser storage is not a backup.

Code

Source code on GitHub

Within — My Offline Journal

Within — private journaling with local AI

A private journaling PWA with AI provided by Ollama on the same computer Plain HTML, CSS and JavaScript, with no build step or cloud AI backend Entries stay in this browser's localStorage. Reflection questions and mood prompts are sent directly to http://localhost:11434/api/generate, never through Render.

Features

Write freely and generate reflection questions, find a writing prompt for your mood, and revisit entries saved in your browser.

Write Ideas History
Writing page with reflection questions Mood-based writing prompts Saved journal entries

Setup

  1. Install Ollama on the computer where you open the app.
  2. Download a model once in your terminal: ollama pull gemma3:1b.
  3. Keep Ollama running. Configure the allowed site origin below.
  4. Open the app and click Reconnect. Choose an installed local model.

The browser never downloads model weights, MediaPipe or WASM. The service worker caches only HTML, CSS, JavaScript, the manifest and icons. Legacy vendor files are unused. On upgrade, old journal shell/model…

The application code is MIT-licensed. Gemma models have their own usage terms.

How I Built It

Within uses plain HTML, CSS, and JavaScript. There is no framework or build step. A service worker caches the small application shell, and localStorage holds journal history.

For AI, I use Google's open-weight Gemma models through Ollama, with gemma3:1b as the preferred installed model. Reflection questions and mood prompts are the core AI features.

The first approach used MediaPipe and WebGPU inside the browser. That meant large model downloads and dependence on browser GPU support. During development, I changed the architecture: Ollama now handles inference, while the browser sends a simple request:

const response = await fetch("http://localhost:11434/api/generate", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    model: activeModelName,
    prompt,
    stream: false,
    options: { num_predict: 512, temperature: 0.8 }
  })
});
Enter fullscreen mode Exit fullscreen mode

Render hosts the static interface. It does not run the model or receive the journal text through the AI request.

The app lists installed models through /api/tags, remembers the selection, excludes recognized cloud-model entries, and reports connection failures. For local-only use, the setup instructions also disable Ollama cloud features.

Two practical lessons stood out:

An updated deployment can still look old. After the migration, the app still displayed “Downloading model.” We found that the usual script URL returned old code while a versioned URL returned the new client. Versioned asset URLs and a new service-worker cache addressed that.

A running local server can still reject the browser. Ollama answered a direct request, but a request carrying the Render origin returned HTTP 403. The configured environment variable had not reached the running server. Restarting with the explicit allowed origin fixed the connection.

Four automated tests cover local model discovery and selection, non-streaming requests, failure handling, and service-worker cache cleanup. The local connection was also verified manually. Most of my initial agent interaction happened in Antigravity; I continued the Ollama migration and refinements in Codex.

A useful troubleshooting reference was Fix CORS before you blame the SDK, which emphasizes checking the server's allowed origin and preflight response.

Why Does Open Innovation Matter?

The reason for using an open-weight model comes directly from the people I built this for. My friends wanted help reflecting on their feelings, and I wanted that help to be available without requiring them to send their writing to a cloud AI service.

For this project, open innovation made local inference and control over the model practical.

I could use an open-weight model on my own computer, choose among installed models, inspect the application's request flow, and change the architecture when browser inference became cumbersome.

A cloud-only API would require sending the writing off the device for inference and keeping an internet connection. With a downloaded local Gemma model, the AI can work without that dependency. The model download still requires internet initially, and inference still depends on the computer's resources.

The tradeoff is setup: users need Ollama and a model installed. I chose to make that requirement visible instead of presenting the AI as something that works on every device automatically.

The aim is a small, understandable tool that gives the writer control over where their words go.

My Agent Session

The project began in Antigravity and continued in Codex. These sessions show the initial browser-inference approach and the later move to local Ollama. Earlier descriptions of WebGPU and phone-based AI refer to the previous architecture, not the current demo.

Antigravity — initial build

Building Within — an offline journaling PWA with local Gemma AI (Hacktoberfest 2026)
You

What hackathons can I enter this month?

Agent

Here are the hackathons you can enter in October 2026: Global Hack Week: Hacktoberfest (Oct 9–15), Hacktoberfest Open-Source AI Challenges on DEV (weekly sprints), and several MLH Member Hackathons. I listed events with dates, locations, and registration links.

You

I am ready to start with the Hacktoberfest Weekend Challenge

Agent

The challenge prompt is 'Build for a Friend' — ship something with open-source AI at its core that explains why open matters. I proposed building an Offline Journal PWA for a friend who wants a morning-pages reflection tool, powered by Gemma running entirely in the browser. We outlined the architecture: Write tab with reflection questions, Ideas tab with mood prompts, History tab with local storage, and a graceful degradation path for devices without WebGPU.

You

You are helping a beginner developer finish a small open-source project for the Hacktoberfest 'Build for a Friend' challenge: 'Offline Journal', a private journaling PWA. START by reading AGENT_INSTRUCTIONS.md. The UI is already done (index.html + style.css). Use plain JavaScript (ES modules), no frameworks. Work in small steps: (a) app.js with storage + UI wiring, (b) ai.js with MediaPipe + Gemma fallback, (c) service worker + manifest + icons, (d) README + LICENSE.

Agent

Step (a) complete! Created app.js with: localStorage persistence, safety checks for crisis keywords with helpline resources, simulated AI for testing, history rendering, and all UI event wiring. The app works end-to-end with placeholder AI so you can test the full UX without model files.

You

Please configure a placeholder URL constant at the top of ai.js pointing to a public Hugging Face model URL. Self-host all @mediapipe/tasks-genai JS and WASM files in vendor/tasks-genai/.

Agent

Step (b) complete! Created ai.js with: self-hosted MediaPipe engine in vendor/tasks-genai/ (zero CDN requests), model download with progress tracking and Cache API persistence, Gemma 3n E2B → Gemma 3 1B automatic fallback, and prompt engineering for reflection questions and mood-based writing prompts.

You

We shall proceed

Agent

Step (c) complete! The app is now a PWA: created manifest.webmanifest, generated 192px and 512px icons, built sw.js with Cache-First strategy for the application shell, and added service worker registration to app.js. The app is installable and works 100% offline after first visit.

You

This being a PWA, how will I use it on the phone?

Agent

Explained how PWAs work on both iPhone (Safari → Share → Add to Home Screen) and Android (Chrome install banner). Once added to home screen, the app opens in standalone mode without browser chrome. After the first visit downloads the model, subsequent launches work in complete Airplane Mode. Also explained the iOS Safari 7-day storage policy and how adding to Home Screen prevents data loss.

You

de fato no meu Galaxy M31 is saying this browser does not support WebGPU

Agent

Great news — the graceful degradation works perfectly! The Galaxy M31 (Exynos 9611, Mali-G72) doesn't have WebGPU enabled by default in Chrome. The app correctly detected this and showed the fallback message while keeping journaling fully functional. Explained how to optionally enable WebGPU via chrome://flags if wanted.

You

Proceed (to step d: README + LICENSE)

Agent

Step (d) complete! Created MIT LICENSE and comprehensive README.md with: project story ('Build for a Friend'), architecture overview, local dev and Render deployment instructions, iOS Safari storage note, and full testing checklist.

You

I have Gemma installed via Ollama on my laptop. Is there a possibility that we use it to test the app on this machine?

Agent

Found gemma3:1b (815 MB) and gemma4:e2b (4.6 GB) installed via Ollama. Explained the difference between Ollama's GGUF format (runs as local server) and MediaPipe's .bin format (runs in-browser on phones). Proposed a dual-mode architecture: local Ollama for laptop development, MediaPipe for standalone phone usage.

You

(User rewrote ai.js) Switched from dual-mode (MediaPipe + Ollama) to pure local Ollama client. Removed all browser model downloads, Cache API, and MediaPipe imports. Added model selector dropdown, reconnect button, cloud model filtering, and detailed error messages with setup help.

Agent

Reviewed the rewritten ai.js and index.html changes. The app now connects exclusively to a local Ollama instance, with a model selector dropdown, reconnect button, and inline setup/CORS help panel. Generated a commit message summarizing all changes.

You

Commit the changes

Agent

Staged all changes (excluding .DS_Store files) and committed as: 'refactor: switch AI engine from MediaPipe WebGPU to local Ollama client' with 7 files changed, 285 insertions, 242 deletions.

You

Please clean the text input after we save the entry or when we click on 'Write about this'

Agent

Provided two diffs for app.js: (1) Clear textarea and reset currentQuestions after saving an entry, (2) Replace textarea content with just the writing prompt (instead of prepending to existing text) when clicking 'Write about this'. Both changes give the user a fresh start each time.

You

export this conversation

Codex — Ollama migration and debugging

This session contains selected, chronological excerpts from our conversation, rather than a complete raw transcript. It covers the migration, stale deployment cache, the Ollama origin rejection, connection recovery, and interface refinements.

Within in Codex: Ollama Migration, Cache and CORS Debugging, and UI Refinements
You

Gostaria de transformar a sua aplicação para se conectar ao Ollama rodando diretamente no computador do usuário.

Agent

A integração atual já tenta usar Ollama, mas ainda bloqueia navegadores sem WebGPU e baixa os modelos como alternativa. Vou remover essa dependência e incluir seleção de modelo e reconexão.

You

Eu fiz o push pro github, e ele atualizou no render mas ainda está exibindo uma mensagem de Downloding model

Agent

Confirmei que o Render entrega o código novo quando uso uma URL diferente, mas a URL habitual de ai.js ainda devolve a versão antiga. Há arquivos antigos sendo servidos por cache. Vou versionar as URLs dos scripts para que o navegador solicite a versão nova após o deploy.

You

Cannot reach Ollama at localhost:11434. Start Ollama on this computer, allow this site in OLLAMA_ORIGINS, and allow local network access in your browser. You can still write and save your entries.

Apareceu essa mensagem

Agent

Essa mensagem indica que a versão nova está funcionando, mas o navegador não conseguiu acessar o Ollama.

You

Estou abrindo no computador, fiz a execução no terminal, atualizei a página cliquei em reconnect mas não funcionou segue a mesma mensagem.

Agent

Identifiquei a causa: o Ollama está ativo e o modelo está instalado, mas ele rejeita o site do Render com 403 Forbidden.

A variável OLLAMA_ORIGINS está correta no macOS, porém o servidor em execução ainda não está usando essa configuração. Atualizar a página não reinicia o Ollama.

You

Agora deu certo, mas gostaria de estilizar essa parte de cima onde escolhemos o local model e tem a ajuda com as configurações do ollama pois não está ornando com o site

Agent

Os controles agora ficam em um cartão translúcido, com seletor e botão alinhados e a ajuda recolhida abaixo. A prévia local já conectou ao Ollama e os quatro testes passaram; estou conferindo o acabamento visual.

You

Please clean the text input after we save the entry or when we click on "Write about this"

Agent

Done. After saving, the writing field and reflection questions are cleared. “Write about this” now replaces the previous text with the selected prompt.

If saving fails, your text stays intact. Syntax checks passed.

Prize Categories

  • Best Use of Gemma: Gemma provides the local reflection questions and writing prompts.
  • Best Use of Render: Render hosts the deployed static PWA.

AI disclosure: I used Antigravity and Codex during development, and AI assistance to prepare this submission. I am reviewing the draft before publishing.

Top comments (0)