DayBook: A private AI journal that learns my friend habits, patterns, and help him improve, powered by Gemma
This is a submission for the Hacktoberfest Weekend Challenge: Build for a Friend This is a team submission Teammate - @piyushnextgen What We Built Daybook began with a simple problem: a friend of ours who was already journaling, but most of the time, the entries just stayed there. He could write about a stressful day, a productive week, a bad habit, or something that kept coming up, but noticing those patterns across dozens of entries was almost impossible manually. So we built Daybook for him. Daybook is a private AI journal that reads your entries locally and helps surface patterns in your habits, mood, routines, and thoughts over time. Instead of just storing what you write, it helps you understand what keeps showing up. The important part is where this happens. Your journal never needs to leave your device. Daybook uses a local LLM, so the AI can work with your personal entries without sending them to a cloud AI service. We wanted to build something that was genuinely useful to one person, while also answering a question we kept coming back to: Can AI be helpful with something as personal as journaling without requiring you to give away your data? Daybook is our attempt at an answer. Demo DayBook UI Demo Note: Local AI features are not available in the deployed demo because DayBook runs AI locally using Ollama. The backend requires a running Ollama instance on port 11434. Video Demo Code greenbugx / Daybook A private AI journal that learns your habits, finds patterns, and helps you improve, powered by a local LLM with your data staying on-device. A local-first AI journal that learns your habits, finds recurring patterns, and helps you reflect on what you could improve Everything happens on your own machine. Your writing never leaves your computer, and the AI that reads it runs locally through Ollama, so there is no account to create, no key to paste, and no company holding a copy of your thoughts. Table of Contents Screenshots What DayBook Does Requirements AI Model Installation Running DayBook How the Project Works Project Structure Database How AI Answers Questions Journal Images Session and Ownership State That Lives Only in Memory Frontend Details Backend Details API Reference Data on Disk Development Privacy Troubleshooting License Screenshots Home Journal Spread Analytics Goals Calendar Library What DayBook Does DayBook is built around a few simple habits that turn into something useful over time. Write a page a day. Each date has one journal entry with a topic… View on GitHub How We Built It We wanted Daybook to be useful with genuinely personal data, which made the usual “send it to an AI API” approach feel wrong for this project. So we built it local-first from the beginning. At the core is Gemma 3 4B, an open-weight model running locally through Ollama. There is no OpenAI API, Gemini API, or hosted AI service sitting between the journal and the model. The whole stack lives on the user’s machine: flowchart LR U[“You, in a browser”] —>|“localhost:5173”| V[“Vite dev server”] V —>|“React app”| U V —>|“proxies /api to 3001”| B[“Fastify backend”] B —>|“SQL, WAL mode”| D[(“SQLite
data/daybook.db”)] B —>|“local HTTP”| O[“Ollama”] O —> G[“Gemma 3 4B”] The frontend is built with React 19 and TypeScript, while the local backend handles application logic and communication with Ollama. Journal data and personal memories are stored locally using SQLite. That separation was intentional. The application can use an LLM for things like identifying recurring habits, finding patterns across entries, and pointing out areas for reflection, while the actual data stays on the same machine. When a user asks Daybook to analyze their journal, the request stays within that local stack: Journal → Backend → Ollama → Gemma → Analysis → Daybook That’s what allows Daybook to look for recurring habits, patterns, wins, struggles, and areas for improvement without requiring a cloud AI API. To run Daybook, we only need three local processes: React + TypeScript for the interface Local backend for application logic Ollama + Gemma 3 4B for AI analysis No API key required What Daybook Can Actually Do Daily entries with topic, mood, weather, location, and a rich text editor Goals tied to a date, so you can see what you meant to do next to what you wrote about A reflection chat where you ask in plain language and get an answer grounded in your actual entries Per entry observations the AI generates after you save Memory suggestions you approve or dismiss, so nothing is remembered without your say so A streak that counts unbroken days honestly One image per entry, stored as a real file on your disk Saved quotes collected in a Library A profile built through onboarding that shapes how reflections are written The AI is grounded, not creative This was the part we spent the most time on. A journal AI that invents things is worse than useless, because you cannot trust what it tells you about your own life. The system prompt carries 18 explicit rules. The model is told that its only source of truth is the context handed to it, that it must never invent entries, dates, goals, or statistics, that it must separate a one time observation from a recurring pattern, and that it must say plainly when there is not enough evidence. It is also told to avoid diagnosing anything about mental or physical health, and to respect a thingsToAvoidAssuming list the user fills in during onboarding. Eight reflection intents decide how the model reads the context: Intent Looks for RECURRING_PATTERNS The same thing showing up again MOOD_EMOTIONAL Mood and emotional tone STRUGGLES What keeps getting in the way WINS_PROGRESS Wins, progress, momentum GOALS Goal follow through HABITS_ROUTINES Routines and timing CHANGE_OVER_TIME How things shifted over time SELF_UNDERSTANDING What Daybook knows about you Questions that never reach the model We route every question before it costs anything. If a question can be answered from the database, Daybook answers it with SQL and skips the model entirely. Ask how many entries you have written, or what your goals are, and you get an exact answer instantly. Only questions that genuinely need interpretation go to Gemma. flowchart TD Q[“Your question”] —> ROUTE[“classifyAiIntent”] ROUTE —>|“quote”| DQ[“Return today’s quote”] ROUTE —>|“streak”| DS[“Return the streak”] ROUTE —>|“goals”| DG[“Read goals from SQL”] ROUTE —>|“journal”| DJ[“Read entries from SQL”] ROUTE —>|“reflection, or anything else”| LLM[“Ask Gemma”] LLM —> INTENT[“classifyReflectionIntent”] INTENT —> CTX[“buildAiContext
entries, goals, profile,
stats, memories, observations”] CTX —> PROMPT[“buildAiSystemPrompt
18 grounding rules plus context”] PROMPT —> RUN[“Ollama generates the answer”] RUN —> OUT[“Answer with its intent label”] This keeps answers exact where exactness matters, and spends model time only where interpretation is actually needed. The streak is not AI The streak is plain arithmetic over your entry dates. It converts dates to day numbers, ignores the future, returns zero unless you wrote today, then counts backwards while days are unbroken. If you skip a day, it ends there. No model, no guessing, no being generous with dates. High-Level System Architecture flowchart TB subgraph USER[“User Machine - 100% Local”] BROWSER[“Browser
localhost:5173”] subgraph FRONTEND[“Frontend - React 19 + TS + Vite + Tailwind 4”] APP[“App.tsx
Routing and shared state”] VIEWS[“Views
InteractiveBook / JournalBook
Calendar / Goals / Library
AnalyticsAI / Settings / Onboarding”] APICLIENT[“lib/api.ts
Typed fetch wrapper for /api/”] end subgraph BACKEND[“Backend - Fastify :3001”] ROUTES[“REST API
users / journals / goals
quotes / memories / ai/”] ZOD[“Zod Validation”] CONTEXT[“buildAiContext()
entries + goals + memories + profile”] AILOGIC[“Intent routing and
grounded prompt building”] end subgraph DATA[“Data Layer”] DRIZZLE[“Drizzle ORM”] SQLITE[“SQLite
better-sqlite3
data/daybook.db
WAL + foreign keys ON”] FILES[“data/media/
format json, temp 0.4”] GEMMA[“Gemma 3:4b”] end end BROWSER —> APP —> VIEWS —> APICLIENT APICLIENT — “/api/* via Vite proxy” —> ROUTES ROUTES —> ZOD —> DRIZZLE —> SQLITE ROUTES —> CONTEXT —> AILOGIC —> OLLAMA_SDK —> GEMMA ROUTES —> FILES Using an open-weight model also meant we weren’t locked into one AI provider. The model can be changed, experimented with, or eventually customized without redesigning the entire product around a proprietary API. For a journal, where the data can be deeply personal, local inference isn’t just a technical choice. It is part of the product itself. Data model Twelve tables, with foreign keys turned on so deleting an entry cleans up its goals, media rows, and observations in one step. erDiagram users ||—o| user_profiles : has users ||—o{ local_sessions : opens users ||—o{ journal_entries : writes journal_entries ||—o{ journal_goals : contains journal_entries ||—o| journal_media : illustrated_by journal_entries ||—o{ journal_observations : analysed_by journal_entries ||—o{ memories : may_seed quotes ||—o{ saved_quotes : saved_as Details we are proud of Ownership is decided on the server, every time. No endpoint accepts a user id, an entry id, or a file path from the client. Each request resolves the active local session, finds that user’s entry for the requested date, then works only with the media and goals hanging off it. Images are safe by construction. Files are named with a server generated UUID, so your original filename never reaches the filesystem. Every path is built from your user id and the date you asked for, and any path resolving outside the media folder is refused. We tested a ../../../../etc/passwd payload and it landed on a UUID filename inside the media root like any other upload. A photo failure never costs you your writing. The journal text is saved first. If the image fails afterwards, your text stays saved, your preview stays visible, and you get a clear error instead of a false success. Date changes cannot leak content. Opening a date fires four requests in parallel, each carrying an AbortController. Switch to October 5 while October 4 is still loading and the stale reply is discarded, so October 4 can never appear on October 5. Tech Stack Layer Technology Port / Location Frontend React 19, TypeScript, Vite 8, Tailwind CSS 4, shadcn/ui, Lucide :5173 · src/ Backend Fastify 5, Zod 4, Drizzle ORM, tsx :3001 · server/src/index.ts Database better-sqlite3, Drizzle Kit data/daybook.db AI Ollama, Gemma 3 4B, Ollama npm package :11434 Development pnpm, Ollama Local Running Daybook Ollama → Backend (:3001) → Frontend (:5173) ↓ Gemma 3 4B ollama serve ollama pull gemma3:4b cd server pnpm dev # In another terminal pnpm dev Requires Node.js 26 or newer, pnpm, and Ollama. Why Does Open Innovation Matter? For Daybook, open innovation wasn’t just about using a different AI model. It changed what we were comfortable building in the first place. A journal is full of things you probably wouldn’t want sitting on someone else’s servers. Thoughts, bad days, habits, goals, personal memories. We wanted Daybook to actually analyze that information without making the user choose between useful AI and privacy. Using an open-weight model like Gemma 3 4B made that possible. Using Gemma 3 4B through Ollama gave us a way to do that. The model runs locally, so in our setup, the journal and its AI analysis can stay on the user’s machine without requiring a third-party AI API or API key. And that’s where open models became more interesting to us than just being a cheaper alternative. We can run the model locally through Ollama, keep the journal and its analysis on the user’s machine, and build around the model without depending on a third-party AI API or API key. It also gives us something a closed API doesn’t: control. We have control over what runs, where it runs, and how we build around it. We can experiment with different models, swap them out, run the system offline, and eventually customize the model for the kind of reflection Daybook needs. For us, that control matters because of the kind of data we’re working with. It’s that we could build an AI product around data we don’t want to send anywhere in the first place. For us, that’s the real promise of open innovation: it lets developers decide where AI runs, what it sees, and how the system is built around it. That’s what it meant for Daybook. Friend Review “I already used to journal, but most of the time I would write something and never really come back to it. Daybook made me notice patterns I hadn’t noticed myself. What I liked most was that it didn’t feel like I had to give my journal to some online AI just to get those insights. Knowing that it runs locally made me much more comfortable putting personal things into it. I also liked seeing the recurring habits and the things I was doing well, not just problems. It made the journal feel less like a place where I dump my thoughts and more like something I can actually learn from.” — Rahul Sharma, The friend we built Daybook for. My Agent Session DayBook: Making the Beautiful UI for people’s journal You Implement the FIRST-TIME PERSONAL ONBOARDING UI for DayBook. The goal is to create a beautiful, calm, journal-like onboarding experience when an existing local user has onboardingCompleted === false. The onboarding should collect personal information DayBook will later use to personalize journal analysis and AI responses. Follow the existing DayBook theme (calm, personal, warm, minimal, editorial, journal-inspired). Agent Created OnboardingView.tsx with a 7-step calm, editorial questionnaire reflecting DayBook’s visual identity: - Steps for current focus, personal bio, habits/motivators, known struggles, ideal day, reflection style (Gentle, Balanced, Direct), and things to avoid assuming. - Integrated seamlessly with FirstRunRegistration and InteractiveBook flow so first-time users see it prior to opening the journal spread. - Data structured for profile update with zero local storage hacks or database schema alterations. ▸ write_to_file DayBook/src/components/OnboardingView.tsx Input DayBook/src/components/OnboardingView.tsx Output File created with editorial onboarding component and responsive steps. You Some fix in Journal: the Bold, Italic, and Underline tool is not working properly. Check it out and fix it. Agent Investigated the contenteditable formatting mechanism in OpenJournalSpread.tsx: - Added proper selection restoration and inline style dispatching (journal-style-sync). - Ensured bold, italic, and underline commands toggle reliably across selected ranges and update toolbar highlight states. ▸ replace_file_content DayBook/src/components/OpenJournalSpread.tsx Input DayBook/src/components/OpenJournalSpread.tsx Output Updated selection formatting listeners and toolbar synchronization. You The GOALS and Observations ‘Daybook noticed’ overlaps when Daybook noticed has many things to show. Can you fix that, make both of them cleanly scrollable and not overlapping each other? Agent Updated the left page layout in OpenJournalSpread.tsx: - Configured Today’s Goals and DayBook Noticed containers with flex-1 min-h-0 overflow-hidden and inner overflow-y-auto scrollbar-none. - Added subtle section dividing borders and bounded max heights so neither section pushes or overlaps the other. ▸ replace_file_content DayBook/src/components/OpenJournalSpread.tsx Input DayBook/src/components/OpenJournalSpread.tsx Output Layout converted to independent scrollable containers. You Collapse this mood selections to a drop down selection, so goals and Daybook Noticed gets good space. Agent Collapsed the 14-button mood selection grid into an inline dropdown menu in OpenJournalSpread.tsx: - Added dropdown trigger displaying the active mood emoji, title, and chevron. - Implemented floating popover menu with 2-column layout and click-outside dismissal. - Freed up vertical space, providing ample room for Goals and DayBook Noticed. ▸ replace_file_content DayBook/src/components/OpenJournalSpread.tsx Input DayBook/src/components/OpenJournalSpread.tsx Output Mood selector transformed to compact dropdown picker. 8 of 8 messages DayBook: Core Backend Architecture, Local AI Reflections, and Persistence You Review the DayBook codebase and implement the next persistence phase: Journal Goals. The goals need a dedicated SQLite table with foreign keys to journal entries, REST endpoints for CRUD operations, and full UI integration. Agent Implemented Journal Goals persistence end-to-end: - Created journal_goals schema in Drizzle ORM with foreign key cascades to journal_entries. - Added REST API routes for listing, creating, toggling completion, and deleting goals. - Integrated goals state and optimistic UI updates into the journal view. ▸ edit_file server/src/db/schema.ts Input server/src/db/schema.ts Output Added journal_goals table with foreign key relationship. You Implement real journal streak calculation in DayBook. Streaks should be computed from actual journal entry dates in SQLite without relying on client-side mocks. Agent Implemented SQLite-backed consecutive streak counting: - Added date normalization and consecutive day algorithm spanning back from today or yesterday. - Created GET /api/journal/streak endpoint returning current and longest streak. - Updated UI header badge to display live database streak count. ▸ edit_file server/src/index.ts Input server/src/index.ts Output Added streak computation logic and API route. You Implement DayBook core local AI reflection system. It must run locally using Ollama, ground reflections in SQLite journal context, and provide thoughtful journal insights without leaking user data. Agent Integrated local AI reflection engine: - Connected to Ollama local instance running Gemma. - Implemented deterministic retrieval of recent entries, mood trends, and active goals to construct the reflection prompt context. - Added streaming reflection generation with fallback handling. ▸ edit_file server/src/ai/engine.ts Input server/src/ai/engine.ts Output Created local LLM reflection pipeline. You Implement smart AI queries and deterministic data retrieval. Factual queries (like goal counts, mood history, dates) should be answered directly from SQLite, while reflective prompts use the local LLM. Agent Built hybrid query router: - Intent classification routes factual questions directly to SQL aggregations. - Reflective and emotional questions are enriched with retrieved SQLite context and passed to the local LLM. - Drastically reduced LLM latency and eliminated hallucinations for historical journal facts. ▸ edit_file server/src/ai/router.ts Input server/src/ai/router.ts Output Implemented intent routing between SQL queries and LLM generation. You Implement DayBook Quote System and Persistent Library: daily quotes, quote catalog, and SQLite-backed saving/unsaving of favorite quotes. Agent Created persistent Quote & Library system: - Added quotes and saved_quotes tables in SQLite. - Built deterministic daily quote selection based on date hashing. - Added endpoints for favoriting quotes and browsing saved quotes in the Library view. ▸ edit_file server/src/db/schema.ts Input server/src/db/schema.ts Output Added quotes and saved_quotes tables with migration. You Implement per-entry AI observations (DayBook Noticed). When an entry is written, the system should generate concise categorized observations (patterns, achievements, emotions). Agent Implemented Per-Entry AI Observations (DayBook Noticed): - Added journal_observations schema with observation types (habit, emotion, milestone). - Extracted structured observations upon saving journal entries. - Rendered categorized observation tags in the left page margin of the journal spread. ▸ edit_file server/src/index.ts Input server/src/index.ts Output Added observation generation and schema linkage. You Implement AI Memory Suggestion with explicit user confirmation. DayBook should detect long-term facts or habits from reflections, propose them to the user, and only persist them to user memory upon approval. Agent Implemented AI Memory Suggestions with human-in-the-loop confirmation: - Added suggested_memories table with status tracking (pending, confirmed, dismissed). - Built memory suggestion extraction prompted from recent journal reflections. - Provided confirmation controls in the UI so users retain complete authority over stored memories. ▸ edit_file server/src/db/schema.ts Input server/src/db/schema.ts Output Added suggested_memories and confirmed_memories tables. You Implement deep personalization, context-aware AI reflections, and the knowledge endpoint showing what DayBook knows about the user. Agent Implemented Deep Personalization & Knowledge Surface: - Added GET /api/ai/knowledge endpoint aggregating profile facts, confirmed memories, recurring themes, and reflection preferences. - Dynamically tuned AI reflection tone according to user style (Gentle, Balanced, Direct). - Ensured all personalization remains strictly local on device. ▸ edit_file server/src/ai/knowledge.ts Input server/src/ai/knowledge.ts Output Aggregated user knowledge model for personalized prompting. 16 of 16 messages Prize Categories Gemma - Daybook uses Gemma 3 4B as its core AI model, running locally through Ollama to analyze journal entries while keeping personal data on-device. Render - Used to deploy the parts of Daybook that need to be accessible beyond the local development environment. GitHub - Used for open-source development, CI/CD, collaboration, version control, and sharing Daybook’s code with the community.