This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass
What I Built
I built ExploBook around a question I wanted book discovery to ask: what if the story you read could inspire something you experience in the real world?
ExploBook doesn't just recommend books. It turns reading into a reason to step outside. Discover your next story, reflect on what you've read, and embark on real-world quests inspired by your reading journey.
Read a story. Live the adventure. Touch grass.
I made ExploBook for readers who want more meaningful reading habits and for anyone looking for a reason to explore beyond their screens. A recommendation is only the first step. The book starts the adventure; the real world completes it.
My goal is to make the screen the shortest part of the experience. AI helps readers discover a catalogue book, prepare an expedition connected to its themes, and make sense of field notes after the reader returns. I didn't want to build a chatbot whose conversation is the destination. The intended destination is outside.
The reading-to-exploration journey
- Reader DNA: Readers choose genres, goals, reading difficulty, session length, and exploration preferences. These saved preferences form the starting point for personalization.
- Book discovery: ExploBook retrieves actual books from its MongoDB catalogue. Ollama embeddings and Atlas Vector Search can surface semantically related candidates; Gemma can provide a grounded explanation for a candidate.
- Focused reading: A reader starts a session and can track time and pages. ExploBook records a focused reading state; it does not include the full text of every recommended book.
- Reading reflection: Readers save takeaways, an optional quote or passage, a mood rating, and an optional word they noticed. The word is recorded in the reflection rather than managed as a separate vocabulary-learning system.
- Expedition generation: A registered Mastra workflow combines a catalogue book and reader context with Gemma-generated instructions for an offline expedition. Supported expedition types include observation, wandering, nature, discovery, historical, literary, and mystery.
- Out into the world: Grass Mode encourages readers to put the phone away and follow a low-screen-interaction quest. Location is optional; when permission is granted and SerpApi is configured, the expedition can include a nearby place such as a park, library, bookstore, or landmark.
- Optional voice briefing: When ElevenLabs is configured, the expedition can be introduced with a generated audio briefing before the reader steps away.
- Return and reflect: Readers mark their return and write field notes, observations, and surprises. The app records these actions but does not use GPS to verify that a quest was completed.
- Progression: A Mastra completion workflow can ask Gemma to analyze the field reflection and suggest bounded Reader DNA changes. TypeScript application logic calculates XP and levels, assigns Orb rarity, creates the Orb, and persists the outcome.
- The next adventure: The Reading Trail brings reading sessions and expeditions together. Saved reader preferences can inform later recommendations.
The AI features depend on a reachable local Ollama instance. If model inference is unavailable or its output cannot be used, some services return deterministic fallback content; that fallback should not be mistaken for Gemma-generated content. Atlas, Clerk, and optional integrations also require network access and configuration.
More Details Of My Project :)
Demo
Code
GitHub repository: kachamsiddarth/ExploBook
The repository contains the web app, Express API, shared TypeScript schemas, and project documentation. The root README has local setup instructions, model requirements, and the current environment variable names.
How I Built It
I built ExploBook as a pnpm workspace with a Next.js 15 and React 19 frontend, styled with Tailwind CSS, and a Node.js/Express API written in TypeScript. Clerk provides web and API authentication. MongoDB Atlas stores the catalogue, user profiles, reading sessions, expeditions, Orbs, and optional voice cache entries.
The frontend calls the Express API. Protected endpoints use the authenticated Clerk identity to load or update only that reader's data. The recommendation, expedition-generation, and expedition-completion workflows are registered on the API's Mastra instance and executed through Mastra's workflow runner.
Recommendation workflow
For a recommendation, POST /api/v1/recommendations (or the public GET /api/v1/recommendations/public route) calls the registered book-recommendation-workflow through Mastra's createRun() and start(). For signed-in requests, the route loads the reader's stored preferences. The recommendation orchestrator asks Ollama's nomic-embed-text model for a query embedding through Ollama's /api/embeddings endpoint, then searches for candidate books.
When the Atlas index is available, the repository sends a $vectorSearch aggregation against books.embedding using the vector_index index, configured for 768-dimensional cosine similarity. The search returns catalogue documents, not free-form titles from the model. If Atlas Vector Search is not available, the repository can compare stored embeddings with cosine similarity in application code; if no usable vectors are found, it can query the catalogue with database filters.
For each candidate, gemma.service.ts sends the book's title, authors, genres, themes, and descriptionβplus reader context when presentβto Ollama's /api/generate endpoint with gemma3:4b-it-q4_K_M. It asks for structured explanation fields: why the book may fit, why it could prompt the reader to step outside, and a suggested atmosphere. The service parses those fields and marks an offline template as fallback_offline when inference fails or the response is malformed. The response's book identity and metadata remain those of the retrieved catalogue document.
Expedition and reflection workflows
POST /api/v1/expeditions/generate invokes the registered expedition-generation-workflow in mastra.ts. Its Mastra step loads the selected book and reader profile from MongoDB. The frontend can request a one-time browser location; if permission is granted and SERPAPI_KEY is configured, serpapi.service.ts calls SerpApi's Google Maps search with an expedition-type-specific query, such as parks for nature quests or libraries for literary quests. The service normalizes the search results, and the workflow attaches the first returned candidate to the expedition. Without coordinates, a configured key, or returned places, the quest proceeds without a named destination.
expedition.service.ts sends Gemma the book metadata and expedition context and prompts it to return a structured mission: a title, supported expedition type, duration, objective, instructions, and book connection. Its prompt explicitly asks for phone-away activities and rules out trespassing, dangerous stunts, and hazardous terrain. The service parses and checks the returned structure; if inference or parsing fails, it creates a deterministic book-themed observation/walk concept instead. The workflow saves the resulting expedition in MongoDB.
After the reader returns, POST /api/v1/expeditions/:id/reflection starts the registered expedition-completion-workflow. reflection.service.ts sends Gemma the saved expedition and book details plus the reader's submitted notes, observations, and surprises. It can return thematic resonance, curiosity signals, key observations, bounded Reader DNA affinity suggestions, and Orb title/theme ideas. The reflection service restricts which DNA fields can change and clamps the suggested deltas. If the model is unavailable or its response is unusable, a deterministic reflection-analysis fallback is used.
The model does not award points or write database records itself. The same completion workflow uses TypeScript application logic to calculate XP and level progression, choose Orb rarity and color, create an Orb record, update the expedition, and persist XP/outdoor-time totals and any accepted DNA delta.
ElevenLabs is a separate optional integration, called through POST /api/v1/expeditions/:id/voice and implemented in elevenlabs.service.ts. It builds a short script from the saved expedition's title, objective, up to four instructions, duration, and book connection, sends it to ElevenLabs text-to-speech using the configured voice and model, and caches the MP3 response in MongoDB's voiceGenerations collection. It introduces an already-generated expedition; it does not create the quest. The voice request requires ELEVENLABS_API_KEY.
The API includes conditional Sentry SDK initialization, but although a capture helper is present, there are no active call sites in the current source. I do not count Sentry as an implemented partner-facing product workflow.
Reader
β
βΌ
Next.js + React βββββββΊ Clerk Authentication
β
β HTTP / JSON
βΌ
Express API
β
βΌ
Mastra Workflows
β
ββββββΊ Book Recommendations
β ββββββΊ Gemma 3 4B IT (Ollama)
β ββββββΊ Embeddings (nomic-embed-text)
β ββββββΊ MongoDB Atlas Vector Search
β
ββββββΊ Expedition Generation & Completion
ββββββΊ Gemma 3 4B IT (Ollama)
ββββββΊ MongoDB Atlas
ββββββΊ SerpApi (optional: real-world places)
ββββββΊ ElevenLabs (optional: audio briefings)
Expedition Completed
β
βΌ
Reflection β XP + Levels + Orbs
β
βΌ
Reader DNA Evolves
β
βΌ
Next Personalized Book Recommendation
This division keeps the model in a supporting role: it generates and interprets language within application-provided context, while TypeScript and the repositories own request validation, identity checks, persistence, progression rules, and the expedition safety prompt. Model output is not treated as proof of a real-world action.
Why Does Open Innovation Matter?
ExploBook uses the open-weight Gemma 3 4B IT model through Ollama for recommendation explanations, expedition concepts, and expedition-reflection analysis. During development, the model can run on the machine hosting Ollama instead of sending generation requests to a closed hosted language-model API. I can inspect and adjust the prompts, choose the model and runtime configuration, and see how the workflow uses the returned output.
Mastra's open-source workflow framework also makes the application orchestration inspectable: recommendation retrieval, expedition generation, and expedition completion are explicit registered workflows rather than an opaque chat loop.
That control has trade-offs. Local inference needs suitable hardware and can be slower or unavailable; some flows then use fallback behavior. The whole application is not offline: authentication and persistent data use Clerk and MongoDB Atlas, and nearby places and voice briefings use network services when configured.
The open-weight model is not the destination of this project. It is the engine that helps turn a digital reading experience into a real-world activity. AI helps prepare and personalize the experience; the intended outcome is the reader stepping away from the device.
My Agent Session
I used an AI coding agent during development to help investigate reported API issues, inspect implementation details, and prepare project documentation..
Prize Categories
-
Best Use of Gemma β category availability to confirm:
gemma.service.ts,expedition.service.ts, andreflection.service.tscall the configured Gemma model through Ollama to explain retrieved catalogue books, turn a book's themes into constrained quest instructions, and interpret the reader's expedition notes. -
Best Use of Mastra β category availability to confirm:
mastra.tsregistersbook-recommendation-workflow,expedition-generation-workflow, andexpedition-completion-workflow; recommendation and expedition route handlers invoke them with Mastra's workflow runner rather than bypassing orchestration. -
Best Use of MongoDB Atlas β category availability to confirm: The repositories persist books, profiles, sessions, expeditions, Orbs, and voice cache entries.
book.repository.tsruns$vectorSearchagainst thevector_indexindex on 768-dimensionalbooks.embeddingvectors when that Atlas index is available. -
Best Use of SerpApi β category availability to confirm:
serpapi.service.tsuses browser-granted one-time coordinates and the server-sideSERPAPI_KEYto search Google Maps for places matched to the quest type, normalize place names, addresses, coordinates, and map links, and return candidates for the workflow to store with the expedition. This enrichment is optional; it is not required to generate a generic quest. -
Best Use of ElevenLabs β category availability to confirm:
elevenlabs.service.ts, exposed atPOST /api/v1/expeditions/:id/voice, turns the saved quest's objective and instructions into an MP3 briefing using the configured ElevenLabs voice/model and caches the audio in MongoDB. It is a pre-departure briefing, not a conversational assistant or quest generator.





Top comments (0)