<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Zaid Kamil</title>
    <description>The latest articles on DEV Community by Zaid Kamil (@sheda3838).</description>
    <link>https://dev.to/sheda3838</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4127464%2Fa783da83-f34e-43f3-a80a-7d5b7649c85c.png</url>
      <title>DEV Community: Zaid Kamil</title>
      <link>https://dev.to/sheda3838</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sheda3838"/>
    <language>en</language>
    <item>
      <title>Before We Scroll: An AI That Gets You Off the Screen and Into the Real World</title>
      <dc:creator>Zaid Kamil</dc:creator>
      <pubDate>Mon, 12 Oct 2026 06:01:55 +0000</pubDate>
      <link>https://dev.to/sheda3838/before-we-scroll-an-ai-that-gets-you-off-the-screen-and-into-the-real-world-2928</link>
      <guid>https://dev.to/sheda3838/before-we-scroll-an-ai-that-gets-you-off-the-screen-and-into-the-real-world-2928</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05"&gt;Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Before We Scroll: I Built an AI That Turns “Just 5 More Minutes” Into Something Real
&lt;/h2&gt;

&lt;p&gt;There is a tiny moment that happens several times every day.&lt;/p&gt;

&lt;p&gt;You have 5 minutes before a game starts.&lt;/p&gt;

&lt;p&gt;15 minutes before you need to leave.&lt;/p&gt;

&lt;p&gt;You are waiting for someone.&lt;/p&gt;

&lt;p&gt;You are standing in a park with friends.&lt;/p&gt;

&lt;p&gt;And almost automatically, the phone comes out.&lt;/p&gt;

&lt;p&gt;Not because there is nothing else to do — but because figuring out &lt;strong&gt;what else to do right now&lt;/strong&gt; takes more effort than opening another feed.&lt;/p&gt;

&lt;p&gt;That was the problem I wanted to solve.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Before We Scroll&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Less scrolling. More doing.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before We Scroll takes whatever context you already have — text, voice, a photo of your surroundings, or a combination of them — and turns that moment into three short, practical real-world missions.&lt;/p&gt;

&lt;p&gt;And after building it, I did the most important test:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I actually took it outside.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Before We Scroll&lt;/strong&gt; is a multimodal AI activity generator designed to turn idle screen time into real-world activity.&lt;/p&gt;

&lt;p&gt;Instead of asking users to fill out a long form, they can simply:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;type what is happening,&lt;/li&gt;
&lt;li&gt;speak naturally,&lt;/li&gt;
&lt;li&gt;take a photo of their surroundings,&lt;/li&gt;
&lt;li&gt;or combine those inputs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application extracts a structured understanding of the situation, including things such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;number of people,&lt;/li&gt;
&lt;li&gt;available time,&lt;/li&gt;
&lt;li&gt;activity goal,&lt;/li&gt;
&lt;li&gt;desired intensity,&lt;/li&gt;
&lt;li&gt;indoor or outdoor setting,&lt;/li&gt;
&lt;li&gt;available space,&lt;/li&gt;
&lt;li&gt;ground surface,&lt;/li&gt;
&lt;li&gt;visible environmental features,&lt;/li&gt;
&lt;li&gt;equipment,&lt;/li&gt;
&lt;li&gt;and safety constraints.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before generating anything, the user gets a &lt;strong&gt;Context Review&lt;/strong&gt; screen where every interpreted detail can be checked and edited.&lt;/p&gt;

&lt;p&gt;Then the system creates &lt;strong&gt;exactly three missions&lt;/strong&gt; tailored to that context.&lt;/p&gt;

&lt;p&gt;Each mission contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a title,&lt;/li&gt;
&lt;li&gt;short description,&lt;/li&gt;
&lt;li&gt;duration,&lt;/li&gt;
&lt;li&gt;intensity,&lt;/li&gt;
&lt;li&gt;player count,&lt;/li&gt;
&lt;li&gt;equipment requirements,&lt;/li&gt;
&lt;li&gt;an explanation of why it fits,&lt;/li&gt;
&lt;li&gt;step-by-step instructions,&lt;/li&gt;
&lt;li&gt;and safety guidance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The user picks one, optionally listens to the mission using ElevenLabs text-to-speech, starts the mission timer, goes and does it, and comes back only when the activity is complete.&lt;/p&gt;

&lt;p&gt;Afterward they can leave feedback and, optionally, share their experience with the public &lt;strong&gt;Real Outventures&lt;/strong&gt; section.&lt;/p&gt;

&lt;p&gt;The complete flow is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Text / Voice / Photo&lt;br&gt;&lt;br&gt;
→ Context Understanding&lt;br&gt;&lt;br&gt;
→ Context Review&lt;br&gt;&lt;br&gt;
→ 3 Missions&lt;br&gt;&lt;br&gt;
→ Choose One&lt;br&gt;&lt;br&gt;
→ Listen&lt;br&gt;&lt;br&gt;
→ Start&lt;br&gt;&lt;br&gt;
→ Get Off the Screen&lt;br&gt;&lt;br&gt;
→ Complete&lt;br&gt;&lt;br&gt;
→ Reflect&lt;br&gt;&lt;br&gt;
→ Share&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The important part is that the AI is not trying to keep the user chatting.&lt;/p&gt;

&lt;p&gt;Its job is to understand the moment quickly enough that the &lt;strong&gt;next interaction happens away from the screen&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Live Application
&lt;/h3&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://before-we-scroll.vercel.app/" rel="noopener noreferrer"&gt;https://before-we-scroll.vercel.app/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Source Code
&lt;/h3&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://github.com/sheda3838/before-we-scroll" rel="noopener noreferrer"&gt;https://github.com/sheda3838/before-we-scroll&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Full Engineering Build Log
&lt;/h3&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://github.com/sheda3838/before-we-scroll/blob/main/BUILD_LOG.md" rel="noopener noreferrer"&gt;BUILD_LOG.md&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The build log contains the complete development journey, including model benchmarks, multimodal testing, timer architecture, voice integration, MongoDB persistence, GridFS storage, and the final product redesign.&lt;/p&gt;


&lt;h2&gt;
  
  
  I Took It Outside
&lt;/h2&gt;

&lt;p&gt;Building an application for the &lt;strong&gt;Touch Grass&lt;/strong&gt; challenge without actually taking it outside felt wrong.&lt;/p&gt;

&lt;p&gt;So instead of stopping once the app deployed successfully, I created &lt;strong&gt;five different real-world test cases&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I intentionally varied the input method and the kind of reasoning required.&lt;/p&gt;

&lt;p&gt;The five tests covered:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Photo + Text — visual context and indirect time reasoning&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Photo + Voice — combining spoken details with visual surroundings&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Photo + Text — environment-aware exploration&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Text Only — complex constraint following&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Voice Only — conversational speech understanding&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I also completed missions and added real feedback rather than only checking whether the API returned JSON.&lt;/p&gt;


&lt;h2&gt;
  
  
  Test 1 — Five Minutes Before Futsal
&lt;/h2&gt;

&lt;p&gt;This became one of my favorite tests.&lt;/p&gt;

&lt;p&gt;I uploaded a real photo taken inside an indoor futsal arena.&lt;/p&gt;

&lt;p&gt;The photo showed the venue and several people, but I deliberately did &lt;strong&gt;not&lt;/strong&gt; tell the AI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how many people were there,&lt;/li&gt;
&lt;li&gt;whether we were indoors,&lt;/li&gt;
&lt;li&gt;what the surface was,&lt;/li&gt;
&lt;li&gt;how large the space was,&lt;/li&gt;
&lt;li&gt;what features surrounded us,&lt;/li&gt;
&lt;li&gt;or what equipment was available.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The only text I gave it was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“We have five minutes left before our game starts. Tell us something active we can do while we wait.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Notice that I did not explicitly say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Create a five-minute mission.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The system had to understand that &lt;strong&gt;five minutes left before the game&lt;/strong&gt; means roughly five minutes of usable activity time.&lt;/p&gt;
&lt;h3&gt;
  
  
  What it understood
&lt;/h3&gt;

&lt;p&gt;The Context Review identified:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;4 people&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;5 available minutes&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;activity goal: &lt;strong&gt;active waiting before a game&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;indoors&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;large space&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;artificial turf&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;indoor sports arena&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;safety netting&lt;/li&gt;
&lt;li&gt;overhead lighting&lt;/li&gt;
&lt;li&gt;metal frame structure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also correctly avoided adding equipment that was not clearly available.&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/q0hf2nktwrkcce2dhzbk.jpeg" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/q0hf2nktwrkcce2dhzbk.jpeg&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/j6xsl2odlglglmvqqk4d.png" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/j6xsl2odlglglmvqqk4d.png&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;That was exactly the sort of multimodal behavior I wanted from the project.&lt;/p&gt;

&lt;p&gt;The image supplied the physical world.&lt;/p&gt;

&lt;p&gt;The sentence supplied the intent and time constraint.&lt;/p&gt;

&lt;p&gt;The AI joined the two.&lt;/p&gt;
&lt;h3&gt;
  
  
  Missions generated
&lt;/h3&gt;

&lt;p&gt;It produced three five-minute ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Netting Geometry Challenge&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Arena Soundscape Mapping&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lighting Shadow Play&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I selected &lt;strong&gt;Lighting Shadow Play&lt;/strong&gt;, which used the arena's overhead lighting and turf to create a quick movement activity.&lt;/p&gt;

&lt;p&gt;What impressed me most was that this was not a generic “do jumping jacks for five minutes” answer.&lt;/p&gt;

&lt;p&gt;It was built from features that were actually visible in the environment.&lt;/p&gt;

&lt;p&gt;My feedback afterward was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“The mission matched our space really well and gave us a fun, active way to use the few minutes we had before the game.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Test 2 — A Backyard, Two Rackets, Seven Minutes
&lt;/h2&gt;

&lt;p&gt;For the second test I changed the input method.&lt;/p&gt;

&lt;p&gt;I uploaded a photo of a grassy residential yard and used &lt;strong&gt;voice input&lt;/strong&gt; instead of typing.&lt;/p&gt;

&lt;p&gt;I spoke naturally:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“My friend and I have about seven minutes to kill before we head out. We’ve got two rackets and a shuttlecock with us — give us something quick and fun to do in this space.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This test divided the information between two sources.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;voice&lt;/strong&gt; provided:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;two people,&lt;/li&gt;
&lt;li&gt;roughly seven minutes,&lt;/li&gt;
&lt;li&gt;two rackets,&lt;/li&gt;
&lt;li&gt;a shuttlecock,&lt;/li&gt;
&lt;li&gt;and the desire for something quick and fun.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;photo&lt;/strong&gt; provided:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the outdoor setting,&lt;/li&gt;
&lt;li&gt;grassy surface,&lt;/li&gt;
&lt;li&gt;available space,&lt;/li&gt;
&lt;li&gt;walls,&lt;/li&gt;
&lt;li&gt;trees,&lt;/li&gt;
&lt;li&gt;gate,&lt;/li&gt;
&lt;li&gt;and surrounding features.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal was to see whether the system would combine both sources rather than treating them separately.&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/g211oyw3ozywuy870npb.jpeg" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/g211oyw3ozywuy870npb.jpeg&lt;/a&gt;)&lt;/p&gt;
&lt;h3&gt;
  
  
  Missions generated
&lt;/h3&gt;

&lt;p&gt;One of the suggestions was:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Gate-to-Tree Rally&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It transformed a normal badminton rally into a small precision challenge using boundaries already present in the yard.&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/32xllzonoecele57cdnk.png" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/32xllzonoecele57cdnk.png&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;I already had a real image showing the activity happening in the same space, which made this one especially satisfying to test.&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/8wcck8c6phnnf319o80a.png" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/8wcck8c6phnnf319o80a.png&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;My feedback:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“The mission matched the space well and made good use of the rackets and shuttlecock we already had. It turned a simple rally into a quick, fun challenge.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Test 3 — Turning a Park Into an Exploration Mission
&lt;/h2&gt;

&lt;p&gt;The third test happened in a much larger outdoor environment.&lt;/p&gt;

&lt;p&gt;The image showed an open grassy historic area with paths, trees and surrounding landmarks.&lt;/p&gt;

&lt;p&gt;This time I supplied:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“I’m here with two kids and we’ve got a football with us. We have about 15 minutes before we need to leave, and we want to do something fun that gets us moving around and exploring this place.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here I wanted to see whether the system would avoid generating just another football drill.&lt;/p&gt;

&lt;p&gt;The word &lt;strong&gt;“exploring”&lt;/strong&gt; mattered.&lt;/p&gt;

&lt;p&gt;The physical environment mattered.&lt;/p&gt;

&lt;p&gt;And the activity needed to remain suitable for a mixed group.&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/dyesa0cvd9jcax369umz.jpeg" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/dyesa0cvd9jcax369umz.jpeg&lt;/a&gt;)&lt;/p&gt;
&lt;h3&gt;
  
  
  Missions generated
&lt;/h3&gt;

&lt;p&gt;The three generated ideas included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cannonball Guardian&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Historic Path Finder&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pass the History&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/icfaldapmc89h2jm0877.png" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/icfaldapmc89h2jm0877.png&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;I chose:&lt;/p&gt;
&lt;h2&gt;
  
  
  The Historic Path Finder
&lt;/h2&gt;

&lt;p&gt;Instead of simply passing the football back and forth, the mission encouraged us to move through the location and use the ball as part of an exploration challenge.&lt;/p&gt;

&lt;p&gt;That was a great example of the AI using the &lt;strong&gt;character of the location&lt;/strong&gt;, rather than treating every grassy area as the same place.&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/3vha6ok3fl15h9jiyqnt.jpeg" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/3vha6ok3fl15h9jiyqnt.jpeg&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;My feedback:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“This mission fit the location really well and made the walk feel more engaging. Using the football while exploring different points around the fort made the activity simple, fun, and easy to follow.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Test 4 — No Image, Just Constraints
&lt;/h2&gt;

&lt;p&gt;For Test 4 I removed vision entirely.&lt;/p&gt;

&lt;p&gt;The input was only text:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“Four of us are stuck inside for about 12 minutes while we wait for dinner. We want something competitive and energetic, but the room isn’t very big, we can’t run, and we don’t have any equipment.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This was deliberately designed to contain several interacting constraints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;four people,&lt;/li&gt;
&lt;li&gt;12 minutes,&lt;/li&gt;
&lt;li&gt;indoors,&lt;/li&gt;
&lt;li&gt;limited space,&lt;/li&gt;
&lt;li&gt;competitive,&lt;/li&gt;
&lt;li&gt;energetic,&lt;/li&gt;
&lt;li&gt;no running,&lt;/li&gt;
&lt;li&gt;no equipment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some of those requirements even pull in opposite directions.&lt;/p&gt;

&lt;p&gt;“Energetic” normally encourages movement.&lt;/p&gt;

&lt;p&gt;“No running” restricts it.&lt;/p&gt;

&lt;p&gt;“Competitive” often introduces equipment.&lt;/p&gt;

&lt;p&gt;“No equipment” removes that option.&lt;/p&gt;

&lt;p&gt;So this test was less about vision and more about whether the mission generator could &lt;strong&gt;respect all of the constraints simultaneously&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/mdq24rg71mjxvyh1xbdo.jpeg" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/mdq24rg71mjxvyh1xbdo.jpeg&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/0yz5rn9k2pbjnolkil55.jpeg" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/0yz5rn9k2pbjnolkil55.jpeg&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The generated activities stayed within the available space and did not suddenly invent balls, cones, cards, or other equipment.&lt;/p&gt;

&lt;p&gt;My feedback:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“The missions followed the constraints really well. They stayed competitive and active without requiring running, extra space, or any equipment.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Test 5 — Talking Like a Normal Person
&lt;/h2&gt;

&lt;p&gt;The last test was &lt;strong&gt;voice only&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;No image.&lt;/p&gt;

&lt;p&gt;No carefully structured sentence.&lt;/p&gt;

&lt;p&gt;I intentionally spoke more like someone would actually speak:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“Okay, so it’s just me and my friend right now. We’ve probably got maybe twenty minutes before we need to head off. We’re both pretty tired, so nothing too intense, but we also don’t want to just sit around. We don’t have anything with us either. Give us something chill but still fun.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This test actually exercises two AI stages.&lt;/p&gt;

&lt;p&gt;First:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ElevenLabs Speech-to-Text&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;has to correctly transcribe casual speech, including words such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“okay”&lt;/li&gt;
&lt;li&gt;“probably”&lt;/li&gt;
&lt;li&gt;“maybe”&lt;/li&gt;
&lt;li&gt;“pretty tired”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then the language model has to find the useful meaning inside that transcript.&lt;/p&gt;

&lt;p&gt;The important context is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;two people,&lt;/li&gt;
&lt;li&gt;around 20 minutes,&lt;/li&gt;
&lt;li&gt;low intensity,&lt;/li&gt;
&lt;li&gt;no equipment,&lt;/li&gt;
&lt;li&gt;something fun,&lt;/li&gt;
&lt;li&gt;environment unspecified.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A good system should also know what &lt;strong&gt;not&lt;/strong&gt; to infer.&lt;/p&gt;

&lt;p&gt;Because I never supplied a photo or location, it should not confidently invent a park, beach, garden or indoor court.&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/xm5fo8r4x1fr2z7fzlux.jpeg" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/xm5fo8r4x1fr2z7fzlux.jpeg&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/43hqytmn0c5peuc6rznx.jpeg" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/43hqytmn0c5peuc6rznx.jpeg&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;My feedback:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“The app understood the casual voice input surprisingly well and suggested activities that matched our limited energy, time, and lack of equipment.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h1&gt;
  
  
  What I Learned From Testing It Outside
&lt;/h1&gt;

&lt;p&gt;The most useful lesson was that multimodal AI becomes much more interesting when each input carries a different part of the truth.&lt;/p&gt;

&lt;p&gt;In the futsal test:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Image&lt;/strong&gt;&lt;br&gt;
→ people + arena + turf + environmental features&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Text&lt;/strong&gt;&lt;br&gt;
→ only five minutes left + desire to stay active&lt;/p&gt;

&lt;p&gt;In the backyard test:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Image&lt;/strong&gt;&lt;br&gt;
→ garden + grass + physical boundaries&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Voice&lt;/strong&gt;&lt;br&gt;
→ two people + seven minutes + rackets + shuttlecock&lt;/p&gt;

&lt;p&gt;The model's job is not simply to “look at a photo.”&lt;/p&gt;

&lt;p&gt;It has to merge different pieces of context into one useful representation.&lt;/p&gt;

&lt;p&gt;Another important result was what happened when information was &lt;strong&gt;missing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Before We Scroll's context schema intentionally supports unknown values.&lt;/p&gt;

&lt;p&gt;If the system does not know something, I prefer:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;null&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;over a confident hallucination.&lt;/p&gt;

&lt;p&gt;The Context Review exists specifically because AI interpretation should remain transparent and correctable.&lt;/p&gt;


&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;The entire project is available here:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sheda3838" rel="noopener noreferrer"&gt;
        sheda3838
      &lt;/a&gt; / &lt;a href="https://github.com/sheda3838/before-we-scroll" rel="noopener noreferrer"&gt;
        before-we-scroll
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/sheda3838/before-we-scroll/public/logo.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fsheda3838%2Fbefore-we-scroll%2FHEAD%2Fpublic%2Flogo.png" alt="Before We Scroll" width="520"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Before We Scroll&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;
  &lt;strong&gt;Less scrolling. More doing.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
  Before We Scroll turns text, voice, and photos of your surroundings into tailored real-world missions designed to get you away from the screen and into the moment
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://before-we-scroll.vercel.app/" rel="nofollow noopener noreferrer"&gt;&lt;strong&gt;Explore the Live Demo →&lt;/strong&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/b283804a59db8759c5fd73dbdbfc9d4727842d46c29cf3870913538f602939d3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4e6578742e6a732d31362d626c61636b3f6c6f676f3d6e6578742e6a73"&gt;&lt;img src="https://camo.githubusercontent.com/b283804a59db8759c5fd73dbdbfc9d4727842d46c29cf3870913538f602939d3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4e6578742e6a732d31362d626c61636b3f6c6f676f3d6e6578742e6a73" alt="Next.js 16"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/60a7485cd52ffda4debf069107d3fa502892166a27794321b79f22a3723e51a5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f52656163742d31392d3631646166623f6c6f676f3d7265616374266c6f676f436f6c6f723d626c61636b"&gt;&lt;img src="https://camo.githubusercontent.com/60a7485cd52ffda4debf069107d3fa502892166a27794321b79f22a3723e51a5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f52656163742d31392d3631646166623f6c6f676f3d7265616374266c6f676f436f6c6f723d626c61636b" alt="React 19"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/97fc638db3dd58f0590d3cc254cd7a8a65369aad17049aba215575dd3ec55dcb/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f547970655363726970742d352d626c75653f6c6f676f3d74797065736372697074"&gt;&lt;img src="https://camo.githubusercontent.com/97fc638db3dd58f0590d3cc254cd7a8a65369aad17049aba215575dd3ec55dcb/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f547970655363726970742d352d626c75653f6c6f676f3d74797065736372697074" alt="TypeScript"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/6410b94c5be8e66c94d8e43a0cb5fe51dedcf87dff2f29492c9c2dbb75c788fe/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5461696c77696e645f4353532d342d3338626466383f6c6f676f3d7461696c77696e64637373"&gt;&lt;img src="https://camo.githubusercontent.com/6410b94c5be8e66c94d8e43a0cb5fe51dedcf87dff2f29492c9c2dbb75c788fe/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5461696c77696e645f4353532d342d3338626466383f6c6f676f3d7461696c77696e64637373" alt="Tailwind CSS 4"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/5ceb85fb959bae8949aa674280104bcb4a70ddcc4201e149349f720c60562b24/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4d6f6e676f44422d3437413234383f6c6f676f3d6d6f6e676f6462266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/5ceb85fb959bae8949aa674280104bcb4a70ddcc4201e149349f720c60562b24/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4d6f6e676f44422d3437413234383f6c6f676f3d6d6f6e676f6462266c6f676f436f6c6f723d7768697465" alt="MongoDB"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/fbb1e93047eb61c5df154145df329bafa29484593aec771b6eec61cebd2b6727/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f476f6f676c655f47656d696e692d332e315f466c6173685f4c6974652d3838364642463f6c6f676f3d676f6f676c65"&gt;&lt;img src="https://camo.githubusercontent.com/fbb1e93047eb61c5df154145df329bafa29484593aec771b6eec61cebd2b6727/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f476f6f676c655f47656d696e692d332e315f466c6173685f4c6974652d3838364642463f6c6f676f3d676f6f676c65" alt="Google Gemini"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/77ee3aee8b349d03c5ae3b02013f729619d997be3fbc9397c494c06ecb9f0e68/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f456c6576656e4c6162732d5354545f2532365f5454532d6f72616e6765"&gt;&lt;img src="https://camo.githubusercontent.com/77ee3aee8b349d03c5ae3b02013f729619d997be3fbc9397c494c06ecb9f0e68/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f456c6576656e4c6162732d5354545f2532365f5454532d6f72616e6765" alt="ElevenLabs"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/787fcd67ab6e7e8815b9d2ad881aeffc89d258871855b118fe5f2abef6863dcc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4465706c6f7965645f6f6e2d56657263656c2d626c61636b3f6c6f676f3d76657263656c"&gt;&lt;img src="https://camo.githubusercontent.com/787fcd67ab6e7e8815b9d2ad881aeffc89d258871855b118fe5f2abef6863dcc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4465706c6f7965645f6f6e2d56657263656c2d626c61636b3f6c6f676f3d76657263656c" alt="Vercel"&gt;&lt;/a&gt;
&lt;/p&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick Links&lt;/h2&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live Production App:&lt;/strong&gt; &lt;a href="https://before-we-scroll.vercel.app/" rel="nofollow noopener noreferrer"&gt;https://before-we-scroll.vercel.app/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/sheda3838/before-we-scroll" rel="noopener noreferrer"&gt;https://github.com/sheda3838/before-we-scroll&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detailed Build Log:&lt;/strong&gt; &lt;a href="https://github.com/sheda3838/before-we-scroll/./BUILD_LOG.md" rel="noopener noreferrer"&gt;BUILD_LOG.md&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Project Overview&lt;/h2&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;The Problem&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;When people have 15 or 30 minutes of free time, they default to scrolling feeds on autopilot. Even when standing in a park, sitting on a balcony, or hanging out in a living room, the phone screen wins by default—not because physical surroundings lack interesting things to do, but because deciding what to do takes effort.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;The Solution&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Before We Scroll&lt;/strong&gt; acts as a catalyst between screen fatigue and real-world engagement. By taking in what you have around you—through typed intent, spoken thoughts, or a quick snapshot of your environment—it extracts a structured understanding…&lt;/p&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/sheda3838/before-we-scroll" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Or directly:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/sheda3838/before-we-scroll" rel="noopener noreferrer"&gt;github.com/sheda3838/before-we-scroll&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The repository also contains a detailed engineering journal:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/sheda3838/before-we-scroll/blob/main/BUILD_LOG.md" rel="noopener noreferrer"&gt;BUILD_LOG.md&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  How I Built It
&lt;/h1&gt;

&lt;p&gt;Before We Scroll is a full-stack &lt;strong&gt;Next.js 16 App Router&lt;/strong&gt; application written in TypeScript.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Next.js 16&lt;/li&gt;
&lt;li&gt;React 19&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;Tailwind CSS 4&lt;/li&gt;
&lt;li&gt;Lucide React&lt;/li&gt;
&lt;li&gt;responsive mobile-first interface&lt;/li&gt;
&lt;li&gt;light and dark themes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  AI
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Google GenAI SDK&lt;/li&gt;
&lt;li&gt;Gemini 3.1 Flash Lite&lt;/li&gt;
&lt;li&gt;Gemma 4 models used during model evaluation and benchmarking&lt;/li&gt;
&lt;li&gt;ElevenLabs Speech-to-Text&lt;/li&gt;
&lt;li&gt;ElevenLabs Text-to-Speech&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Persistence
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;MongoDB&lt;/li&gt;
&lt;li&gt;MongoDB GridFS for optional completion photos&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Deployment
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Vercel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The production app is:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://before-we-scroll.vercel.app/" rel="noopener noreferrer"&gt;before-we-scroll.vercel.app&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  The AI Pipeline
&lt;/h1&gt;

&lt;p&gt;The project uses AI at several distinct stages instead of making one giant prompt do everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Context Extraction
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;POST /api/context/analyze&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Text and/or image input is converted into a structured &lt;code&gt;MissionContext&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The structure includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;people count&lt;/li&gt;
&lt;li&gt;duration&lt;/li&gt;
&lt;li&gt;activity goal&lt;/li&gt;
&lt;li&gt;intensity&lt;/li&gt;
&lt;li&gt;age group&lt;/li&gt;
&lt;li&gt;environment type&lt;/li&gt;
&lt;li&gt;indoor/outdoor&lt;/li&gt;
&lt;li&gt;space size&lt;/li&gt;
&lt;li&gt;surface&lt;/li&gt;
&lt;li&gt;visible features&lt;/li&gt;
&lt;li&gt;obstacles&lt;/li&gt;
&lt;li&gt;available equipment&lt;/li&gt;
&lt;li&gt;constraints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The user can review and edit everything before proceeding.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Mission Generation
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;POST /api/mission/generate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The confirmed context becomes the source of truth.&lt;/p&gt;

&lt;p&gt;A single AI request returns exactly &lt;strong&gt;three complete mission objects&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Each contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;title&lt;/li&gt;
&lt;li&gt;description&lt;/li&gt;
&lt;li&gt;duration&lt;/li&gt;
&lt;li&gt;intensity&lt;/li&gt;
&lt;li&gt;players&lt;/li&gt;
&lt;li&gt;required equipment&lt;/li&gt;
&lt;li&gt;why it fits&lt;/li&gt;
&lt;li&gt;steps&lt;/li&gt;
&lt;li&gt;safety notes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No second AI call is necessary when a user selects a mission.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Voice Input
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;POST /api/transcribe&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The browser records audio using &lt;code&gt;MediaRecorder&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The temporary audio blob is sent server-side to ElevenLabs Speech-to-Text.&lt;/p&gt;

&lt;p&gt;The transcript is placed back into the normal input flow.&lt;/p&gt;

&lt;p&gt;Audio is not permanently stored.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Mission Narration
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;POST /api/tts&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;ElevenLabs Text-to-Speech generates mission narration.&lt;/p&gt;

&lt;p&gt;Before the mission starts, users can listen to the complete briefing.&lt;/p&gt;

&lt;p&gt;During the active mission, the app can read only the actionable steps and safety information.&lt;/p&gt;

&lt;p&gt;Audio is cached temporarily in the browser so replaying does not repeatedly call the API.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. The Timer
&lt;/h2&gt;

&lt;p&gt;One thing I deliberately avoided was a timer based only on decrementing React state.&lt;/p&gt;

&lt;p&gt;Instead the mission stores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;startedAt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;expectedEndAt&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remaining time is calculated from the current timestamp.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;refreshing the page does not reset the mission,&lt;/li&gt;
&lt;li&gt;switching tabs does not desynchronize it,&lt;/li&gt;
&lt;li&gt;and background browser throttling does not destroy the countdown.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. Feedback and Real Outventures
&lt;/h2&gt;

&lt;p&gt;After completion, users can submit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a 1–5 rating,&lt;/li&gt;
&lt;li&gt;whether the activity matched their context,&lt;/li&gt;
&lt;li&gt;instruction accuracy,&lt;/li&gt;
&lt;li&gt;difficulty,&lt;/li&gt;
&lt;li&gt;an optional comment,&lt;/li&gt;
&lt;li&gt;and an optional completion photo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Completion records are persisted to MongoDB.&lt;/p&gt;

&lt;p&gt;Images are stored using &lt;strong&gt;GridFS&lt;/strong&gt;, rather than being embedded as huge base64 strings inside normal documents.&lt;/p&gt;

&lt;p&gt;Public sharing is controlled separately for feedback and photos.&lt;/p&gt;

&lt;p&gt;The public endpoint exposes only a sanitized DTO containing the fields needed by the &lt;strong&gt;Real Outventures&lt;/strong&gt; feed.&lt;/p&gt;

&lt;p&gt;Session IDs, private context and other internal information are not returned.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why I Benchmarked the Models
&lt;/h1&gt;

&lt;p&gt;I originally expected to use Gemma much more heavily throughout the application.&lt;/p&gt;

&lt;p&gt;Instead of choosing a model based on reputation alone, I benchmarked it.&lt;/p&gt;

&lt;p&gt;For context extraction I tested:&lt;/p&gt;

&lt;h3&gt;
  
  
  Gemma 4 26B A4B
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;average latency: approximately &lt;strong&gt;30.35 seconds&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;median: approximately &lt;strong&gt;28.77 seconds&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;strong structured extraction quality&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Gemma 4 31B
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;average latency: approximately &lt;strong&gt;71.06 seconds&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;median: approximately &lt;strong&gt;71.52 seconds&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;no meaningful accuracy improvement over the smaller variant&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Gemini 3.1 Flash Lite
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;average latency: approximately &lt;strong&gt;2.88 seconds&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;median: approximately &lt;strong&gt;1.12 seconds&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;100% successful responses in the controlled test&lt;/li&gt;
&lt;li&gt;strong schema adherence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also separately benchmarked mission-generation quality.&lt;/p&gt;

&lt;p&gt;The final production path uses &lt;strong&gt;Gemini 3.1 Flash Lite&lt;/strong&gt; for the interactive context and mission-generation workflows because the latency difference dramatically changed the usability of the product.&lt;/p&gt;

&lt;p&gt;Gemma remained extremely valuable during development because it gave me an open-weight reference point against which I could evaluate speed, structured output quality and creative mission generation.&lt;/p&gt;

&lt;p&gt;The detailed benchmark methodology is available in the build log:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/sheda3838/before-we-scroll/blob/main/BUILD_LOG.md" rel="noopener noreferrer"&gt;Model benchmarking and architecture decisions&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h1&gt;

&lt;p&gt;This project changed significantly because I could experiment rather than treating one model as a black box that simply had to be accepted.&lt;/p&gt;

&lt;p&gt;Working with open-weight models such as Gemma gave me a meaningful architectural baseline.&lt;/p&gt;

&lt;p&gt;I could ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How much quality do I actually gain from a larger model?&lt;/li&gt;
&lt;li&gt;Is the latency appropriate for an interactive product?&lt;/li&gt;
&lt;li&gt;Which stages truly need creative reasoning?&lt;/li&gt;
&lt;li&gt;Which stages are primarily structured extraction?&lt;/li&gt;
&lt;li&gt;Could the mission layer eventually be self-hosted or swapped without redesigning the complete application?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The answer was not “one model should do everything.”&lt;/p&gt;

&lt;p&gt;The architecture became better because models could be evaluated as components.&lt;/p&gt;

&lt;p&gt;The same principle applies to the rest of the project.&lt;/p&gt;

&lt;p&gt;MongoDB gives me control over the application's data model.&lt;/p&gt;

&lt;p&gt;GridFS gives me direct binary persistence without tying the MVP to another storage provider.&lt;/p&gt;

&lt;p&gt;The application code itself is publicly available so the architecture, experiments and trade-offs can be inspected rather than hidden behind a demo.&lt;/p&gt;

&lt;p&gt;To me, that is the useful part of open innovation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;being able to understand, compare, replace and improve the pieces instead of treating the technology as magic.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;The project uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ElevenLabs&lt;/strong&gt; — Speech-to-Text input and Text-to-Speech mission narration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MongoDB / GridFS&lt;/strong&gt; — completion persistence and optional photo storage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google AI / Gemma&lt;/strong&gt; — open-weight model evaluation and benchmarking during development&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Final Result
&lt;/h1&gt;

&lt;p&gt;Before We Scroll started with a very simple question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What if the moment before another scroll could become the moment you actually did something?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now the application can:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;listen to you,&lt;br&gt;&lt;br&gt;
look at your surroundings,&lt;br&gt;&lt;br&gt;
understand your constraints,&lt;br&gt;&lt;br&gt;
create something realistic to do,&lt;br&gt;&lt;br&gt;
read the instructions aloud,&lt;br&gt;&lt;br&gt;
start a timer,&lt;br&gt;&lt;br&gt;
and then get out of your way.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The most rewarding part of this challenge was not seeing the build pass.&lt;/p&gt;

&lt;p&gt;It was taking the application outside and seeing AI suggestions turn into actual movement, games, exploration and time spent with other people.&lt;/p&gt;

&lt;p&gt;That feels much closer to what I want AI to do:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;not always give us another reason to stay on a screen, but sometimes give us a good reason to leave it.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Try Before We Scroll
&lt;/h3&gt;

&lt;p&gt;🌐 &lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://before-we-scroll.vercel.app/" rel="noopener noreferrer"&gt;https://before-we-scroll.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💻 &lt;strong&gt;Code:&lt;/strong&gt; &lt;a href="https://github.com/sheda3838/before-we-scroll" rel="noopener noreferrer"&gt;https://github.com/sheda3838/before-we-scroll&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📖 &lt;strong&gt;Build Log:&lt;/strong&gt; &lt;a href="https://github.com/sheda3838/before-we-scroll/blob/main/BUILD_LOG.md" rel="noopener noreferrer"&gt;BUILD_LOG.md&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Echo Shelf 2.0: Turning Saved Knowledge Into a Living Second Brain</title>
      <dc:creator>Zaid Kamil</dc:creator>
      <pubDate>Mon, 05 Oct 2026 06:25:10 +0000</pubDate>
      <link>https://dev.to/sheda3838/echo-shelf-20-turning-saved-knowledge-into-a-living-second-brain-2d2k</link>
      <guid>https://dev.to/sheda3838/echo-shelf-20-turning-saved-knowledge-into-a-living-second-brain-2d2k</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01"&gt;Hacktoberfest Weekend Challenge: Build for a Friend&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;We save useful knowledge every day.&lt;/p&gt;

&lt;p&gt;An interesting article gets bookmarked. A useful YouTube video gets added to a playlist. A GitHub repository gets starred. A PDF gets downloaded. An idea gets written into a note.&lt;/p&gt;

&lt;p&gt;And then, most of it disappears into the digital pile.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;Echo Shelf 2.0&lt;/strong&gt;, an intelligent personal knowledge vault, for a friend who, like many of us, constantly saves useful articles, YouTube videos, GitHub repositories, documents, images, and notes—but rarely gets meaningful value from them again.&lt;/p&gt;

&lt;p&gt;The problem wasn't saving information.&lt;/p&gt;

&lt;p&gt;The real problem was &lt;strong&gt;finding it again, understanding how different saved resources connect, and remembering it when it becomes relevant.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That became the foundation of Echo Shelf 2.0:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Capture → Connect → Resurface&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead of building another bookmark manager, I wanted to create a &lt;strong&gt;living second brain&lt;/strong&gt; that understands what you save, discovers relationships between your knowledge, and brings old information back when it becomes useful again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Capture
&lt;/h3&gt;

&lt;p&gt;Save knowledge from different sources and let Echo Shelf understand what was actually saved.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect
&lt;/h3&gt;

&lt;p&gt;Discover meaningful relationships between resources that may have been saved days or weeks apart.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resurface
&lt;/h3&gt;

&lt;p&gt;Bring old knowledge back when something happening now makes it relevant again.&lt;/p&gt;

&lt;p&gt;Imagine saving an article about a technology, business strategy, research topic, or idea today.&lt;/p&gt;

&lt;p&gt;Weeks later, something related happens in the world.&lt;/p&gt;

&lt;p&gt;Instead of expecting you to remember that old bookmark, &lt;strong&gt;Echo Shelf can make that connection for you.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What Can Echo Shelf Save?
&lt;/h2&gt;

&lt;p&gt;Echo Shelf supports &lt;strong&gt;eight content types&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📰 &lt;strong&gt;Articles&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;🎥 &lt;strong&gt;YouTube videos&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;GitHub/GitLab repositories&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;🔗 &lt;strong&gt;Generic URLs&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;🖼️ &lt;strong&gt;Images&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;📄 &lt;strong&gt;Documents&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;📝 &lt;strong&gt;Notes&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;🧩 &lt;strong&gt;Multi-source "Other" entries&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A multi-source entry can combine things such as a personal note, several reference URLs, documents, and images into a single knowledge asset.&lt;/p&gt;

&lt;p&gt;But I didn't want the AI to blindly guess what a URL or document contained.&lt;/p&gt;

&lt;p&gt;That led to one of the most important architectural decisions in the project.&lt;/p&gt;




&lt;h2&gt;
  
  
  Smart Capture: Ground the AI Before Asking It to Think
&lt;/h2&gt;

&lt;p&gt;A simple implementation could have looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;URL → AI → "Tell me what this is"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I deliberately avoided that.&lt;/p&gt;

&lt;p&gt;Instead, Echo Shelf follows a &lt;strong&gt;source-grounded pipeline&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Input
    ↓
Source-Specific Extraction
    ↓
Normalized Context
    ↓
Gemma
    ↓
Structured Metadata
    ↓
User Review
    ↓
Persistence
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key principle is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Extraction first. AI reasoning second.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Different sources therefore have different extraction paths.&lt;/p&gt;

&lt;h3&gt;
  
  
  🌐 Articles and Web Pages
&lt;/h3&gt;

&lt;p&gt;Web pages are fetched server-side and processed using &lt;strong&gt;Mozilla Readability + JSDOM&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This extracts the meaningful readable content while removing much of the surrounding navigation, advertising, and page clutter.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎥 YouTube Videos
&lt;/h3&gt;

&lt;p&gt;YouTube URLs are resolved using the &lt;strong&gt;YouTube Data API v3&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Echo Shelf can retrieve grounded metadata such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Title&lt;/li&gt;
&lt;li&gt;Description&lt;/li&gt;
&lt;li&gt;Channel&lt;/li&gt;
&lt;li&gt;Publication information&lt;/li&gt;
&lt;li&gt;Duration&lt;/li&gt;
&lt;li&gt;Thumbnail&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gemma therefore reasons over actual video metadata rather than trying to infer the contents from a URL.&lt;/p&gt;

&lt;h3&gt;
  
  
  💻 GitHub and GitLab Repositories
&lt;/h3&gt;

&lt;p&gt;Repository URLs are processed using the relevant repository APIs.&lt;/p&gt;

&lt;p&gt;Echo Shelf gathers repository metadata and README content before passing normalized context to Gemma.&lt;/p&gt;

&lt;h3&gt;
  
  
  📄 Documents
&lt;/h3&gt;

&lt;p&gt;PDF and supported Office documents are parsed into textual context before AI processing.&lt;/p&gt;

&lt;p&gt;The extracted information is normalized and treated as untrusted source content.&lt;/p&gt;

&lt;h3&gt;
  
  
  🖼️ Images
&lt;/h3&gt;

&lt;p&gt;Images are handled using &lt;strong&gt;Gemma's multimodal capabilities&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This allows visual knowledge such as screenshots, diagrams, charts, and infographics to become part of the user's knowledge library.&lt;/p&gt;

&lt;h3&gt;
  
  
  📝 Notes
&lt;/h3&gt;

&lt;p&gt;Notes already contain user-provided source content, so they can move directly into the normalization and intelligence pipeline.&lt;/p&gt;

&lt;p&gt;The result is that Gemma receives &lt;strong&gt;grounded information&lt;/strong&gt; rather than being expected to invent the contents of an inaccessible resource.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gemma Is the Intelligence Layer
&lt;/h2&gt;

&lt;p&gt;Echo Shelf 2.0 uses:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gemma 4 26B — &lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;through Google's Gemini Developer API.&lt;/p&gt;

&lt;p&gt;I didn't want Gemma to exist as a chatbot sitting beside the application.&lt;/p&gt;

&lt;p&gt;Instead, I wanted the model to become part of the application's &lt;strong&gt;reasoning architecture&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Gemma powers four major intelligence layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Smart Capture
      ↓
Smart Connections
      ↓
Knowledge Clusters
      ↓
Contextual Rediscovery
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each layer builds on the previous one.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✨ Smart Capture
&lt;/h2&gt;

&lt;p&gt;After Echo Shelf extracts a source, Gemma analyzes the normalized context and generates useful structured information such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Title&lt;/li&gt;
&lt;li&gt;Description&lt;/li&gt;
&lt;li&gt;Tags&lt;/li&gt;
&lt;li&gt;Relevant metadata&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The generated information is &lt;strong&gt;not blindly persisted&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The user can review and edit the generated metadata before saving the item.&lt;/p&gt;

&lt;p&gt;I also deliberately kept duplicate detection outside the AI layer.&lt;/p&gt;

&lt;p&gt;Echo Shelf uses deterministic mechanisms such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Canonical URL normalization&lt;/li&gt;
&lt;li&gt;SHA-256 content fingerprints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates an important separation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;AI handles semantic understanding. Deterministic software handles exact identity.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🔎 Potential Connections
&lt;/h2&gt;

&lt;p&gt;Even before an item is saved, Echo Shelf can look for possible relationships with existing knowledge.&lt;/p&gt;

&lt;p&gt;However, I didn't want every operation to require an expensive AI call.&lt;/p&gt;

&lt;p&gt;So &lt;strong&gt;Potential Connections are deterministic&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Echo Shelf compares information such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tags&lt;/li&gt;
&lt;li&gt;Titles&lt;/li&gt;
&lt;li&gt;Keywords&lt;/li&gt;
&lt;li&gt;Descriptions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;to cheaply shortlist potentially related resources.&lt;/p&gt;

&lt;p&gt;This provides immediate feedback while reserving Gemma for the deeper semantic reasoning that actually benefits from AI.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔗 Smart Connections
&lt;/h2&gt;

&lt;p&gt;After an item has been saved, the user can run &lt;strong&gt;Check Connections&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is where Gemma performs deeper semantic reasoning.&lt;/p&gt;

&lt;p&gt;The process has two stages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 1 — Deterministic Candidate Selection
&lt;/h3&gt;

&lt;p&gt;Echo Shelf searches the authenticated user's library and creates a small shortlist of promising candidates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 2 — Gemma Semantic Analysis
&lt;/h3&gt;

&lt;p&gt;Only those candidates are passed to Gemma for semantic analysis.&lt;/p&gt;

&lt;p&gt;Gemma can classify relationships such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;prerequisite&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;extends&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;complementary&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;conceptual-overlap&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;practical-application&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;contrast&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;alternative-approach&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;implementation-detail&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The relationship also includes a strength and an explanation.&lt;/p&gt;

&lt;p&gt;The result is that the user's library gradually becomes an &lt;strong&gt;interconnected knowledge graph&lt;/strong&gt; rather than a flat collection of bookmarks.&lt;/p&gt;

&lt;p&gt;Gemma can also reject candidates when apparent keyword similarity does not represent a meaningful conceptual relationship.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 Knowledge Clusters
&lt;/h2&gt;

&lt;p&gt;Individual connections are useful, but I wanted Echo Shelf to answer a bigger question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What larger subjects am I actually building knowledge around?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's where &lt;strong&gt;Knowledge Clusters&lt;/strong&gt; come in.&lt;/p&gt;

&lt;p&gt;Echo Shelf creates lightweight representations of the user's saved items using information such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Item ID&lt;/li&gt;
&lt;li&gt;Title&lt;/li&gt;
&lt;li&gt;Description&lt;/li&gt;
&lt;li&gt;Tags&lt;/li&gt;
&lt;li&gt;Content type&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gemma then looks for meaningful conceptual groups.&lt;/p&gt;

&lt;p&gt;A generated cluster can contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A thematic title&lt;/li&gt;
&lt;li&gt;A summary&lt;/li&gt;
&lt;li&gt;Related saved items&lt;/li&gt;
&lt;li&gt;Semantic tags&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The system intentionally avoids forcing every item into a cluster.&lt;/p&gt;

&lt;p&gt;If something doesn't meaningfully belong anywhere, it can remain ungrouped.&lt;/p&gt;

&lt;p&gt;This prevents the feature from becoming a simple AI-generated folder system.&lt;/p&gt;

&lt;p&gt;Instead, the goal is to identify &lt;strong&gt;real conceptual patterns across the user's knowledge&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ When AI Reasoning Took Longer Than Expected
&lt;/h2&gt;

&lt;p&gt;Knowledge Clusters also created one of the most interesting engineering problems during development.&lt;/p&gt;

&lt;p&gt;During testing, cluster generation appeared to simply stop working.&lt;/p&gt;

&lt;p&gt;The request would run for a long time and eventually fail.&lt;/p&gt;

&lt;p&gt;After investigating the actual model response behavior, I found that Gemma could spend a significant portion of the generation budget on internal reasoning before producing the final structured response.&lt;/p&gt;

&lt;p&gt;Earlier output limits could therefore terminate generation before the useful JSON was returned.&lt;/p&gt;

&lt;p&gt;I had to account for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thought-token separation&lt;/li&gt;
&lt;li&gt;Structured JSON responses&lt;/li&gt;
&lt;li&gt;Output limits&lt;/li&gt;
&lt;li&gt;Longer inference times&lt;/li&gt;
&lt;li&gt;Serverless execution limits&lt;/li&gt;
&lt;li&gt;Validation of generated IDs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another production blocker appeared because complex clustering operations could take roughly &lt;strong&gt;45–55 seconds&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The final solution included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Increasing the Gemma timeout&lt;/li&gt;
&lt;li&gt;Using structured JSON response mode&lt;/li&gt;
&lt;li&gt;Limiting the candidate set&lt;/li&gt;
&lt;li&gt;Trimming descriptions before inference&lt;/li&gt;
&lt;li&gt;Allowing longer execution for the clustering route&lt;/li&gt;
&lt;li&gt;Validating generated item IDs before persistence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After the changes, Knowledge Cluster generation successfully completed during browser testing.&lt;/p&gt;

&lt;p&gt;This was an important lesson from the project:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Integrating AI isn't just about getting a successful model response. You also have to engineer around reasoning time, token budgets, latency, structured output, failure recovery, and the execution environment around the model.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🌍 Contextual Rediscovery
&lt;/h2&gt;

&lt;p&gt;This became my favorite part of Echo Shelf.&lt;/p&gt;

&lt;p&gt;Saving and organizing information is useful.&lt;/p&gt;

&lt;p&gt;But I wanted Echo Shelf to do something more proactive:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tell me when something I already know becomes relevant again.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Contextual Rediscovery starts with the user's Knowledge Clusters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Knowledge Clusters
        ↓
High-Signal Topics
        ↓
GNews
        ↓
Current Articles
        ↓
Gemma Relevance Analysis
        ↓
Old Knowledge Resurfaced
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Echo Shelf derives compact topics from the user's clusters and queries &lt;strong&gt;GNews&lt;/strong&gt; for current developments.&lt;/p&gt;

&lt;p&gt;Gemma then compares those developments against the user's existing knowledge.&lt;/p&gt;

&lt;p&gt;The central question becomes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What is happening now that makes something I saved before relevant again?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Only meaningful matches are surfaced.&lt;/p&gt;

&lt;p&gt;A Rediscovery result can connect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📰 A current article&lt;/li&gt;
&lt;li&gt;📚 Previously saved knowledge&lt;/li&gt;
&lt;li&gt;🧠 A relevant Knowledge Cluster&lt;/li&gt;
&lt;li&gt;💡 An explanation of why the connection matters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This completes the original idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Capture → Connect → Resurface&lt;/strong&gt;
&lt;/h3&gt;
&lt;/blockquote&gt;

&lt;p&gt;The shelf isn't just storing information anymore.&lt;/p&gt;

&lt;p&gt;It is helping decide &lt;strong&gt;when that information matters again&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🐛 Debugging Rediscovery
&lt;/h2&gt;

&lt;p&gt;Rediscovery produced another interesting real-world problem.&lt;/p&gt;

&lt;p&gt;The GNews API key was valid and direct requests worked, but running Rediscovery across multiple topics sometimes resulted in failures.&lt;/p&gt;

&lt;p&gt;The problem turned out to be &lt;strong&gt;rate limiting&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Multiple searches were being sent too quickly, causing &lt;code&gt;HTTP 429&lt;/code&gt; responses.&lt;/p&gt;

&lt;p&gt;Some generated search queries were also too specific and returned little useful information.&lt;/p&gt;

&lt;p&gt;I changed the system to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pace GNews requests&lt;/li&gt;
&lt;li&gt;Prefer shorter, high-signal thematic queries&lt;/li&gt;
&lt;li&gt;Apply explicit request timeouts&lt;/li&gt;
&lt;li&gt;Handle provider errors more precisely&lt;/li&gt;
&lt;li&gt;Preserve previous valid Rediscovery results when a refresh fails&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After those changes, Echo Shelf successfully retrieved current news and connected it to previously saved knowledge.&lt;/p&gt;

&lt;p&gt;That was the point where the &lt;strong&gt;Resurface&lt;/strong&gt; part of the project really came alive.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔐 Security Was Part of the Architecture
&lt;/h2&gt;

&lt;p&gt;Echo Shelf processes arbitrary URLs, documents, AI-generated output, and private user knowledge.&lt;/p&gt;

&lt;p&gt;Because of that, security couldn't simply be added at the end.&lt;/p&gt;

&lt;h3&gt;
  
  
  Server-Verified Identity
&lt;/h3&gt;

&lt;p&gt;Authentication is handled using &lt;strong&gt;Supabase Auth&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Every protected server operation derives the user's identity from the verified session.&lt;/p&gt;

&lt;p&gt;The application does &lt;strong&gt;not&lt;/strong&gt; trust an arbitrary &lt;code&gt;userId&lt;/code&gt; supplied by the browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  MongoDB Tenant Isolation
&lt;/h3&gt;

&lt;p&gt;Every user-owned MongoDB record is associated with a user.&lt;/p&gt;

&lt;p&gt;Reads, updates, deletes, AI candidate selection, connections, clusters, and rediscovery operations are scoped to the authenticated owner.&lt;/p&gt;

&lt;p&gt;Cross-user resources are treated as unavailable rather than revealing whether another user's record exists.&lt;/p&gt;

&lt;h3&gt;
  
  
  SSRF Protection
&lt;/h3&gt;

&lt;p&gt;Fetching arbitrary URLs server-side introduces &lt;strong&gt;Server-Side Request Forgery (SSRF)&lt;/strong&gt; risk.&lt;/p&gt;

&lt;p&gt;The extraction layer therefore protects against unsafe targets including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Private network ranges&lt;/li&gt;
&lt;li&gt;Loopback addresses&lt;/li&gt;
&lt;li&gt;Link-local and metadata endpoints&lt;/li&gt;
&lt;li&gt;Unsafe protocols&lt;/li&gt;
&lt;li&gt;Redirects toward internal addresses&lt;/li&gt;
&lt;li&gt;Unsafe DNS resolutions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Prompt Injection Boundaries
&lt;/h3&gt;

&lt;p&gt;Extracted webpages and documents are treated as &lt;strong&gt;untrusted data&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Their contents are separated from model instructions so text such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ignore all previous instructions...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is treated as part of the source material rather than a trusted instruction.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Output Validation
&lt;/h3&gt;

&lt;p&gt;AI-generated output is also treated as untrusted.&lt;/p&gt;

&lt;p&gt;Generated IDs, relationships, strengths, and other structured values are validated before they can affect persisted application data.&lt;/p&gt;

&lt;p&gt;For me, this became another important principle:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Model output is another trust boundary.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;🚀 &lt;strong&gt;Live Application:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://echo-shelf-2.vercel.app/" rel="noopener noreferrer"&gt;https://echo-shelf-2.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The deployed application supports the complete workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Authentication
      ↓
Smart Capture
      ↓
Personal Library
      ↓
Smart Connections
      ↓
Knowledge Clusters
      ↓
Contextual Rediscovery
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;💻 &lt;strong&gt;GitHub Repository:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/sheda3838/echo-shelf-2" rel="noopener noreferrer"&gt;https://github.com/sheda3838/echo-shelf-2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The repository contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complete application source&lt;/li&gt;
&lt;li&gt;Architecture documentation&lt;/li&gt;
&lt;li&gt;Automated tests&lt;/li&gt;
&lt;li&gt;Security tests&lt;/li&gt;
&lt;li&gt;Project README&lt;/li&gt;
&lt;li&gt;Detailed &lt;code&gt;BUILD_LOG.md&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The build log documents not only what worked, but also the architectural decisions, bugs, failed approaches, security hardening, production blockers, and fixes encountered throughout development.&lt;/p&gt;


&lt;h2&gt;
  
  
  ⚙️ Tech Stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Framework&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Next.js 16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Frontend&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;React 19 + TypeScript + Tailwind CSS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Gemma 4 26B (&lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AI Access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Google Gemini Developer API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Database&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MongoDB Atlas + Mongoose&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Authentication&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Supabase Auth&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Current News&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GNews API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Video Metadata&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;YouTube Data API v3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Web Extraction&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mozilla Readability + JSDOM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deployment&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Vercel&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  🧪 Testing It
&lt;/h2&gt;

&lt;p&gt;I built automated tests around the areas where failures would matter most, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;User isolation&lt;/li&gt;
&lt;li&gt;Duplicate detection&lt;/li&gt;
&lt;li&gt;Smart Capture&lt;/li&gt;
&lt;li&gt;Smart Connections&lt;/li&gt;
&lt;li&gt;Knowledge Clusters&lt;/li&gt;
&lt;li&gt;Contextual Rediscovery&lt;/li&gt;
&lt;li&gt;Security boundaries&lt;/li&gt;
&lt;li&gt;Document processing&lt;/li&gt;
&lt;li&gt;Image processing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before deployment, the project also passed its core quality gates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TypeScript        → PASS
ESLint            → PASS
Production Build  → PASS
Smart Connections → PASS
Knowledge Clusters → PASS
Rediscovery       → PASS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also performed browser testing of the actual intelligence workflow rather than relying entirely on mocked responses.&lt;/p&gt;




&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;Echo Shelf 2.0 was built as a fresh project for the &lt;strong&gt;Hacktoberfest Weekend Challenge&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The development process was iterative:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Idea
 ↓
Secure Application Foundation
 ↓
Authentication + User Isolation
 ↓
Source Extraction
 ↓
Smart Capture
 ↓
Duplicate Prevention
 ↓
Potential Connections
 ↓
Smart Connections
 ↓
Knowledge Clusters
 ↓
Contextual Rediscovery
 ↓
Adversarial + Security Testing
 ↓
UI/UX Refinement
 ↓
Production Debugging
 ↓
Deployment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One principle stayed consistent throughout the project:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Use deterministic software when the answer should be deterministic. Use Gemma when semantic reasoning genuinely adds value.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That means things such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Authorization&lt;/li&gt;
&lt;li&gt;Duplicate detection&lt;/li&gt;
&lt;li&gt;Tenant isolation&lt;/li&gt;
&lt;li&gt;Candidate filtering&lt;/li&gt;
&lt;li&gt;URL security&lt;/li&gt;
&lt;li&gt;Persistence&lt;/li&gt;
&lt;li&gt;Validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;remain conventional deterministic software.&lt;/p&gt;

&lt;p&gt;Gemma handles the parts that genuinely benefit from semantic intelligence.&lt;/p&gt;

&lt;p&gt;That separation made Echo Shelf much easier to reason about, test, secure, and debug.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;The most interesting part of building Echo Shelf wasn't simply adding an AI API.&lt;/p&gt;

&lt;p&gt;It was designing a system around an &lt;strong&gt;open-weight model&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Gemma isn't a decorative chatbot bolted onto the side of Echo Shelf.&lt;/p&gt;

&lt;p&gt;It is responsible for the semantic intelligence connecting the product:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Capture → Semantic Connections → Knowledge Organization → Contextual Rediscovery&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An open model ecosystem makes it possible to think beyond a single opaque endpoint.&lt;/p&gt;

&lt;p&gt;The intelligence layer can evolve with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Different model versions&lt;/li&gt;
&lt;li&gt;Different inference environments&lt;/li&gt;
&lt;li&gt;Deployment strategies&lt;/li&gt;
&lt;li&gt;Performance optimizations&lt;/li&gt;
&lt;li&gt;Community improvements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;while the deterministic architecture surrounding it can remain stable.&lt;/p&gt;

&lt;p&gt;Open innovation also encouraged me to think carefully about what AI &lt;strong&gt;shouldn't&lt;/strong&gt; do.&lt;/p&gt;

&lt;p&gt;I didn't use Gemma for authentication.&lt;/p&gt;

&lt;p&gt;I didn't use it to determine whether two URLs are identical.&lt;/p&gt;

&lt;p&gt;I didn't let it decide whether a user owns a database record.&lt;/p&gt;

&lt;p&gt;I didn't let generated IDs enter the database without validation.&lt;/p&gt;

&lt;p&gt;Instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deterministic Engineering
          +
Open-Weight Intelligence
          =
A More Reliable AI-Native Product
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For me, that's what makes open AI exciting.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The model becomes something developers can build around, experiment with, optimize, and learn from—not simply a black box behind a chat interface.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;I used &lt;strong&gt;DevRelay&lt;/strong&gt; during the Hacktoberfest development workflow while building Echo Shelf 2.0.&lt;/p&gt;

&lt;p&gt;My development process included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architecture design&lt;/li&gt;
&lt;li&gt;Implementation&lt;/li&gt;
&lt;li&gt;AI integration&lt;/li&gt;
&lt;li&gt;Adversarial QA&lt;/li&gt;
&lt;li&gt;Security hardening&lt;/li&gt;
&lt;li&gt;Browser verification&lt;/li&gt;
&lt;li&gt;Production debugging&lt;/li&gt;
&lt;li&gt;Deployment preparation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full engineering journey is also documented publicly in the repository's build log:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/sheda3838/echo-shelf-2/blob/main/BUILD_LOG.md" rel="noopener noreferrer"&gt;View the Echo Shelf 2.0 BUILD_LOG&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🟢 Best Use of Gemma
&lt;/h3&gt;

&lt;p&gt;I'm entering &lt;strong&gt;Best Use of Gemma&lt;/strong&gt; because Gemma is the central semantic intelligence layer of Echo Shelf 2.0.&lt;/p&gt;

&lt;p&gt;Gemma powers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✨ Smart Capture&lt;/li&gt;
&lt;li&gt;🖼️ Multimodal image understanding&lt;/li&gt;
&lt;li&gt;🔗 Smart Connections&lt;/li&gt;
&lt;li&gt;🧠 Knowledge Clusters&lt;/li&gt;
&lt;li&gt;🌍 Contextual Rediscovery&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application is deliberately designed &lt;strong&gt;around Gemma's semantic reasoning capabilities&lt;/strong&gt; rather than using the model as a standalone chatbot.&lt;/p&gt;

&lt;p&gt;Without that reasoning layer, Echo Shelf would largely be another storage application.&lt;/p&gt;

&lt;p&gt;Gemma is what turns the shelf into an intelligent knowledge system.&lt;/p&gt;

&lt;h3&gt;
  
  
  🍃 Best Use of MongoDB Atlas
&lt;/h3&gt;

&lt;p&gt;I'm also entering &lt;strong&gt;Best Use of MongoDB Atlas&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;MongoDB Atlas serves as Echo Shelf's production persistence layer for the user's knowledge system, including saved assets and the structures built around them.&lt;/p&gt;

&lt;p&gt;The document model fits naturally with the different shapes of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Articles&lt;/li&gt;
&lt;li&gt;Videos&lt;/li&gt;
&lt;li&gt;Repositories&lt;/li&gt;
&lt;li&gt;Documents&lt;/li&gt;
&lt;li&gt;Notes&lt;/li&gt;
&lt;li&gt;Metadata&lt;/li&gt;
&lt;li&gt;Connections&lt;/li&gt;
&lt;li&gt;Knowledge Clusters&lt;/li&gt;
&lt;li&gt;Rediscovery results&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every user-owned record is tenant-scoped, and ownership is derived from server-verified authentication.&lt;/p&gt;

&lt;p&gt;This lets MongoDB Atlas act as the persistent foundation beneath Echo Shelf's AI intelligence layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Echo Shelf 2.0 started with a simple frustration:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We save far more knowledge than we ever use again.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I didn't want to solve that by creating another folder system.&lt;/p&gt;

&lt;p&gt;I wanted the saved knowledge itself to become more useful.&lt;/p&gt;

&lt;p&gt;Something that understands what you captured.&lt;/p&gt;

&lt;p&gt;Something that notices when two ideas connect.&lt;/p&gt;

&lt;p&gt;Something that recognizes the larger themes you're learning about.&lt;/p&gt;

&lt;p&gt;And most importantly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Something that knows when an old piece of knowledge matters again.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's &lt;strong&gt;Echo Shelf 2.0&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Capture it. Connect it. Resurface it.&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;🚀 &lt;strong&gt;Live Demo:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://echo-shelf-2.vercel.app/" rel="noopener noreferrer"&gt;https://echo-shelf-2.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💻 &lt;strong&gt;Source Code:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/sheda3838/echo-shelf-2" rel="noopener noreferrer"&gt;https://github.com/sheda3838/echo-shelf-2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Built for the Hacktoberfest 2026 Weekend Challenge: Build for a Friend.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>Echo Shelf: An AI Knowledge Lake That Connects What You Save to What Matters Now</title>
      <dc:creator>Zaid Kamil</dc:creator>
      <pubDate>Sun, 04 Oct 2026 22:30:38 +0000</pubDate>
      <link>https://dev.to/sheda3838/echo-shelf-an-ai-knowledge-lake-that-connects-what-you-save-to-what-matters-now-330k</link>
      <guid>https://dev.to/sheda3838/echo-shelf-an-ai-knowledge-lake-that-connects-what-you-save-to-what-matters-now-330k</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/sanity-2026-09-16"&gt;Sanity Challenge, Path Two: Vibe-Code Something Strange&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I built &lt;strong&gt;Echo Shelf&lt;/strong&gt;, an AI-assisted personal knowledge lake designed around one problem I kept running into:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I save useful articles, videos, repositories, screenshots, documents, and notes — but most of them disappear into a bookmarking graveyard and I rarely return to them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Echo Shelf turns that passive collection into an active knowledge system.&lt;/p&gt;

&lt;p&gt;The core idea is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Capture → Connect → Resurface&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of only storing links, Echo Shelf:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;captures knowledge from multiple source types&lt;/li&gt;
&lt;li&gt;extracts useful context from each source&lt;/li&gt;
&lt;li&gt;generates structured metadata with AI&lt;/li&gt;
&lt;li&gt;finds meaningful relationships between saved items&lt;/li&gt;
&lt;li&gt;groups related knowledge into thematic clusters&lt;/li&gt;
&lt;li&gt;connects current news back to things I saved before&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application supports eight content types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Articles&lt;/li&gt;
&lt;li&gt;Videos&lt;/li&gt;
&lt;li&gt;Repositories&lt;/li&gt;
&lt;li&gt;URLs&lt;/li&gt;
&lt;li&gt;Images&lt;/li&gt;
&lt;li&gt;Documents&lt;/li&gt;
&lt;li&gt;Notes&lt;/li&gt;
&lt;li&gt;Other resources&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Smart Capture
&lt;/h3&gt;

&lt;p&gt;Smart Capture analyzes the actual source before generating metadata.&lt;/p&gt;

&lt;p&gt;Different sources use different extraction pipelines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Articles and URLs → Mozilla Readability + &lt;code&gt;jsdom&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;GitHub/GitLab repositories → provider APIs + README content&lt;/li&gt;
&lt;li&gt;YouTube videos → YouTube Data API metadata&lt;/li&gt;
&lt;li&gt;PDF/DOCX/PPTX/XLSX documents → format-specific parsers&lt;/li&gt;
&lt;li&gt;Images → Groq Vision using &lt;code&gt;qwen/qwen3.8-27b&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Notes → direct text context&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The extracted context is then sent through Groq for editable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;title&lt;/li&gt;
&lt;li&gt;description&lt;/li&gt;
&lt;li&gt;tags&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The user can always review and edit the AI output before saving.&lt;/p&gt;

&lt;h3&gt;
  
  
  Smart Connections
&lt;/h3&gt;

&lt;p&gt;After an item is saved, Echo Shelf can discover relationships between it and existing knowledge.&lt;/p&gt;

&lt;p&gt;I intentionally split this into two stages.&lt;/p&gt;

&lt;p&gt;First, a deterministic metadata shortlist compares:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tags&lt;/li&gt;
&lt;li&gt;title keywords&lt;/li&gt;
&lt;li&gt;description keywords&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only the strongest candidates are sent to the LLM.&lt;/p&gt;

&lt;p&gt;Then &lt;code&gt;openai/gpt-oss-120b&lt;/code&gt; evaluates whether the relationship is genuinely useful and returns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;relationship type&lt;/li&gt;
&lt;li&gt;strength&lt;/li&gt;
&lt;li&gt;explanation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This also means the AI is allowed to reject superficial keyword matches instead of forcing a connection.&lt;/p&gt;

&lt;h3&gt;
  
  
  Knowledge Clusters
&lt;/h3&gt;

&lt;p&gt;Echo Shelf can analyze lightweight metadata across the user's library and discover broader themes.&lt;/p&gt;

&lt;p&gt;For the final demonstration library, it successfully discovered themes such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retrieval-Augmented Generation &amp;amp; Vector Search&lt;/li&gt;
&lt;li&gt;Next.js Server Actions&lt;/li&gt;
&lt;li&gt;Docker &amp;amp; Kubernetes Networking&lt;/li&gt;
&lt;li&gt;Developer Productivity &amp;amp; Deep Work&lt;/li&gt;
&lt;li&gt;Ergonomics &amp;amp; Workplace Health&lt;/li&gt;
&lt;li&gt;Sleep Hygiene &amp;amp; Recovery&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An item can belong to more than one cluster when that relationship is genuinely useful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Contextual Rediscovery
&lt;/h3&gt;

&lt;p&gt;This is the feature that completes the original idea.&lt;/p&gt;

&lt;p&gt;Echo Shelf asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What is happening now that makes something I saved before relevant again?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Knowledge Cluster metadata is converted into compact news queries and sent to the GNews API.&lt;/p&gt;

&lt;p&gt;Recent articles are then compared against saved knowledge using Groq.&lt;/p&gt;

&lt;p&gt;Only meaningful strong or moderate matches are retained.&lt;/p&gt;

&lt;p&gt;Each result explains:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this matters to your shelf&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;and links the current news article back to the related saved item and Knowledge Cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other details
&lt;/h3&gt;

&lt;p&gt;Echo Shelf also includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;exact duplicate detection using canonical URLs and SHA-256 fingerprints&lt;/li&gt;
&lt;li&gt;email/password authentication&lt;/li&gt;
&lt;li&gt;Google OAuth&lt;/li&gt;
&lt;li&gt;GitHub OAuth&lt;/li&gt;
&lt;li&gt;SSR cookie sessions with Supabase&lt;/li&gt;
&lt;li&gt;server-enforced per-user ownership&lt;/li&gt;
&lt;li&gt;embedded Sanity Studio&lt;/li&gt;
&lt;li&gt;responsive branded UI&lt;/li&gt;
&lt;li&gt;loading and pending states for asynchronous actions&lt;/li&gt;
&lt;li&gt;duplicate-click prevention&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The final application is a custom Next.js interface built on top of the Sanity Content Lake rather than a traditional CMS frontend.&lt;/p&gt;




&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Live Application
&lt;/h3&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://echo-shelf-three.vercel.app/" rel="noopener noreferrer"&gt;https://echo-shelf-three.vercel.app/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Demo Account
&lt;/h3&gt;

&lt;p&gt;The account below is pre-populated with a multi-domain knowledge library so the full experience can be explored immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Email:&lt;/strong&gt; &lt;code&gt;echoshelf@gmail.com&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Password:&lt;/strong&gt; &lt;code&gt;password&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Recommended Testing Flow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Sign in using the demo account.&lt;/li&gt;
&lt;li&gt;Browse the Library and its mixed content types.&lt;/li&gt;
&lt;li&gt;Open saved items and inspect their Smart Connections.&lt;/li&gt;
&lt;li&gt;Open &lt;strong&gt;Clusters&lt;/strong&gt; to explore AI-discovered knowledge themes.&lt;/li&gt;
&lt;li&gt;Open &lt;strong&gt;Rediscover&lt;/strong&gt; to see current developments connected back to saved knowledge.&lt;/li&gt;
&lt;li&gt;Try &lt;strong&gt;Add Item&lt;/strong&gt; to test Smart Capture yourself.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Screenshots
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Library / Personal Knowledge Lake&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbvyojdbjm0k3z3n9qisu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbvyojdbjm0k3z3n9qisu.png" alt="Echo Shelf library showing a mixed personal knowledge collection with search, filters, and saved item cards" width="799" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Smart Capture&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmqst4fx4oqs2c771hb20.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmqst4fx4oqs2c771hb20.png" alt="Echo Shelf Smart Capture page for adding and enriching new knowledge items" width="799" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Knowledge Clusters&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fssl3r26prj0pwga8vgfy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fssl3r26prj0pwga8vgfy.png" alt="Echo Shelf Knowledge Clusters page showing AI-generated themes across saved items" width="799" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contextual Rediscovery&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fliu3sdmdml1qav94gxch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fliu3sdmdml1qav94gxch.png" alt="Echo Shelf Rediscover page showing recent news articles matched with previously saved knowledge, including relevance explanations and links back to related shelf items" width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authentication&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjm6tvs7hfpg26ywzjgcx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjm6tvs7hfpg26ywzjgcx.png" alt="Echo Shelf authentication page showing email sign-in fields and social login options for Google and GitHub" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;Source code:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://github.com/sheda3838/echo-shelf" rel="noopener noreferrer"&gt;https://github.com/sheda3838/echo-shelf&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The repository also contains:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://github.com/sheda3838/echo-shelf/blob/main/BUILD_LOG.md" rel="noopener noreferrer"&gt;BUILD_LOG.md&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I kept the build log throughout development instead of reconstructing the process at the end.&lt;/p&gt;

&lt;p&gt;It records the decisions, failed approaches, manual tests, architectural changes, debugging sessions, and production fixes that shaped the final application.&lt;/p&gt;




&lt;h2&gt;
  
  
  My Build Process
&lt;/h2&gt;

&lt;p&gt;I built Echo Shelf using an &lt;strong&gt;AI-native development workflow with Antigravity IDE&lt;/strong&gt;, but I did not treat generated code as automatically correct.&lt;/p&gt;

&lt;p&gt;My workflow was generally:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;define a small milestone → prompt the IDE → inspect the implementation → run automated checks → manually test real flows → document what failed → refine&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The most useful prompts were the ones with very narrow constraints.&lt;/p&gt;

&lt;p&gt;Instead of asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Build an AI knowledge app"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I broke Echo Shelf into individual systems such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;define the Sanity schema&lt;/li&gt;
&lt;li&gt;create the dynamic Add Item flow&lt;/li&gt;
&lt;li&gt;implement one source extractor at a time&lt;/li&gt;
&lt;li&gt;build deterministic candidate shortlisting&lt;/li&gt;
&lt;li&gt;add AI relationship validation&lt;/li&gt;
&lt;li&gt;introduce first-class Knowledge Cluster documents&lt;/li&gt;
&lt;li&gt;build Rediscovery around persisted cluster metadata&lt;/li&gt;
&lt;li&gt;introduce authenticated per-user ownership&lt;/li&gt;
&lt;li&gt;harden production behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Where the model got things wrong
&lt;/h3&gt;

&lt;p&gt;There were several cases where the first generated approach worked in theory but failed against real usage.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. OCR was the wrong approach for general images
&lt;/h4&gt;

&lt;p&gt;My first Image Smart Capture implementation used Tesseract.js OCR.&lt;/p&gt;

&lt;p&gt;It worked for screenshots containing lots of text.&lt;/p&gt;

&lt;p&gt;Then I tested it with a normal photo.&lt;/p&gt;

&lt;p&gt;The OCR produced meaningless fragments, and the text model generated metadata about the OCR noise instead of describing the image.&lt;/p&gt;

&lt;p&gt;That changed the architecture completely.&lt;/p&gt;

&lt;p&gt;I replaced:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Image → OCR → text model&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;with:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Image → Groq Vision → structured metadata&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;using &lt;code&gt;qwen/qwen3.8-27b&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That immediately made photos, diagrams, screenshots, and mixed visual content much more useful.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Document extraction passed tests but broke in the real browser flow
&lt;/h4&gt;

&lt;p&gt;The document parser initially looked correct in automated testing.&lt;/p&gt;

&lt;p&gt;Manual testing exposed several framework-level issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pdf-parse&lt;/code&gt; package entry behavior during Next.js bundling&lt;/li&gt;
&lt;li&gt;Server Action body limits for uploaded files&lt;/li&gt;
&lt;li&gt;extraction failures being incorrectly reported as AI failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those were fixed individually instead of hiding them behind a generic error.&lt;/p&gt;

&lt;p&gt;This was one of the biggest reminders during the project that passing static checks is not the same as testing an actual product flow.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Production Smart Capture failed after deployment
&lt;/h4&gt;

&lt;p&gt;After deploying to Vercel, Article Smart Capture suddenly returned HTTP 500 even though the local production build succeeded.&lt;/p&gt;

&lt;p&gt;Vercel logs revealed an ESM/CommonJS incompatibility inside the deployed &lt;code&gt;jsdom&lt;/code&gt; dependency chain.&lt;/p&gt;

&lt;p&gt;The failure happened before the requested article was even fetched.&lt;/p&gt;

&lt;p&gt;Instead of rewriting Smart Capture, I traced the runtime dependency problem and pinned &lt;code&gt;jsdom&lt;/code&gt; to a compatible version while keeping the Readability architecture unchanged.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Knowledge Clusters became unstable with realistic demo data
&lt;/h4&gt;

&lt;p&gt;The small test library worked.&lt;/p&gt;

&lt;p&gt;The final demonstration library contained &lt;strong&gt;41 saved items&lt;/strong&gt;, and suddenly cluster generation became inconsistent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sometimes 4 clusters&lt;/li&gt;
&lt;li&gt;sometimes 2&lt;/li&gt;
&lt;li&gt;sometimes a generic error&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I built a non-persisting diagnostic runner and repeated the same generation multiple times.&lt;/p&gt;

&lt;p&gt;The actual problem was not Sanity or cluster validation.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;openai/gpt-oss-120b&lt;/code&gt; was spending too much of its completion budget on reasoning, causing Groq's JSON output to be truncated before it could form a valid document.&lt;/p&gt;

&lt;p&gt;I fixed this by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;truncating descriptions sent to clustering&lt;/li&gt;
&lt;li&gt;limiting tags&lt;/li&gt;
&lt;li&gt;removing redundant metadata&lt;/li&gt;
&lt;li&gt;using compact JSON&lt;/li&gt;
&lt;li&gt;explicitly controlling completion tokens&lt;/li&gt;
&lt;li&gt;reducing reasoning effort&lt;/li&gt;
&lt;li&gt;limiting the result to a maximum of six meaningful clusters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After the change, repeated runs consistently generated complete, valid clusters.&lt;/p&gt;

&lt;p&gt;The only later failures were API quota limits rather than malformed cluster output.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prompts that worked best
&lt;/h3&gt;

&lt;p&gt;The prompts that produced the strongest results were usually explicit about what &lt;strong&gt;not&lt;/strong&gt; to change.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Keep the current Sanity schema and persistence behavior. Diagnose why clustering fails before changing the algorithm. Run repeated dry-run generations without modifying stored data and report the exact failure mechanism.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Replace only the image-understanding layer. Preserve Smart Capture form state, manual metadata, stale-response protection, and the existing save flow.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those constraints kept the AI from solving one problem by accidentally rewriting an unrelated part of the product.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sanity became more than storage
&lt;/h3&gt;

&lt;p&gt;The project started with the idea that Sanity would hold saved items.&lt;/p&gt;

&lt;p&gt;It eventually became the structural backbone of the application.&lt;/p&gt;

&lt;p&gt;The Content Lake stores not only knowledge assets, but relationships between them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;users own saved items&lt;/li&gt;
&lt;li&gt;saved items reference connected saved items&lt;/li&gt;
&lt;li&gt;Knowledge Clusters reference multiple saved items&lt;/li&gt;
&lt;li&gt;saved items can participate in multiple clusters&lt;/li&gt;
&lt;li&gt;Rediscovery results reference both saved items and clusters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GROQ then powers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;library filtering&lt;/li&gt;
&lt;li&gt;item lookup&lt;/li&gt;
&lt;li&gt;duplicate detection&lt;/li&gt;
&lt;li&gt;candidate shortlisting&lt;/li&gt;
&lt;li&gt;cluster expansion&lt;/li&gt;
&lt;li&gt;Rediscovery loading&lt;/li&gt;
&lt;li&gt;per-user ownership filtering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This relational structure is what allowed the later AI features to build on one another.&lt;/p&gt;

&lt;p&gt;Smart Connections would be much less useful without structured item references.&lt;/p&gt;

&lt;p&gt;Rediscovery would be much less useful without first-class Knowledge Clusters.&lt;/p&gt;

&lt;p&gt;That was the most important architectural lesson from this build.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sanity Project Details
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sanity Project ID:&lt;/strong&gt; &lt;code&gt;jcon1mtg&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dataset:&lt;/strong&gt; &lt;code&gt;production&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Echo Shelf uses Sanity as a structured Content Lake with four primary document types.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;savedItem&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Represents an individual knowledge asset.&lt;/p&gt;

&lt;p&gt;It stores structured fields such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;title&lt;/li&gt;
&lt;li&gt;description&lt;/li&gt;
&lt;li&gt;content type&lt;/li&gt;
&lt;li&gt;source URL/text/file&lt;/li&gt;
&lt;li&gt;image asset&lt;/li&gt;
&lt;li&gt;tags&lt;/li&gt;
&lt;li&gt;saved timestamp&lt;/li&gt;
&lt;li&gt;favorite state&lt;/li&gt;
&lt;li&gt;canonical source fingerprint&lt;/li&gt;
&lt;li&gt;owner reference&lt;/li&gt;
&lt;li&gt;Smart Connection references&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;knowledgeCluster&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Represents an AI-discovered conceptual theme.&lt;/p&gt;

&lt;p&gt;It stores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;title&lt;/li&gt;
&lt;li&gt;slug&lt;/li&gt;
&lt;li&gt;summary&lt;/li&gt;
&lt;li&gt;tags&lt;/li&gt;
&lt;li&gt;generated timestamp&lt;/li&gt;
&lt;li&gt;references to constituent &lt;code&gt;savedItem&lt;/code&gt; documents&lt;/li&gt;
&lt;li&gt;owner reference&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cluster membership is many-to-many, so a saved item can participate in more than one theme.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;rediscoveryResult&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Represents a connection between current news and previously saved knowledge.&lt;/p&gt;

&lt;p&gt;It stores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;news article metadata&lt;/li&gt;
&lt;li&gt;relevance&lt;/li&gt;
&lt;li&gt;connection type&lt;/li&gt;
&lt;li&gt;explanation&lt;/li&gt;
&lt;li&gt;saved-item reference&lt;/li&gt;
&lt;li&gt;Knowledge Cluster reference&lt;/li&gt;
&lt;li&gt;owner reference&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;user&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Echo Shelf authentication is handled by Supabase.&lt;/p&gt;

&lt;p&gt;Sanity stores only a privacy-safe user projection containing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deterministic opaque user document ID&lt;/li&gt;
&lt;li&gt;display name&lt;/li&gt;
&lt;li&gt;optional avatar&lt;/li&gt;
&lt;li&gt;creation timestamp&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Raw Supabase user IDs, passwords, authentication tokens, and user emails are not stored in the Sanity user document.&lt;/p&gt;

&lt;h3&gt;
  
  
  Embedded Studio
&lt;/h3&gt;

&lt;p&gt;Sanity Studio is embedded directly into the application at:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/studio&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The user-facing product remains a fully custom Next.js interface, while Studio provides direct inspection of the underlying structured content.&lt;/p&gt;




&lt;h2&gt;
  
  
  Agent Session
&lt;/h2&gt;

&lt;p&gt;I did not include a public Agent Session for this submission.&lt;/p&gt;

&lt;p&gt;Instead, I maintained a detailed chronological build record throughout development:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://github.com/sheda3838/echo-shelf/blob/main/BUILD_LOG.md" rel="noopener noreferrer"&gt;https://github.com/sheda3838/echo-shelf/blob/main/BUILD_LOG.md&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It includes successful prompts, failed approaches, architectural pivots, debugging discoveries, testing notes, and production fixes.&lt;/p&gt;




&lt;p&gt;Thanks for checking out &lt;strong&gt;Echo Shelf&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The project started as an attempt to make saved links easier to revisit.&lt;/p&gt;

&lt;p&gt;It ended up becoming a system where previously saved knowledge can explain its relationships, organize itself, and reappear when something happening today makes it useful again.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>sanitychallenge</category>
      <category>sanity</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
