<?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: Aditya Kumar</title>
    <description>The latest articles on DEV Community by Aditya Kumar (@adityakumar2358).</description>
    <link>https://dev.to/adityakumar2358</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%2F4152822%2F9a5cf499-275d-4935-b473-c7ce914c5856.png</url>
      <title>DEV Community: Aditya Kumar</title>
      <link>https://dev.to/adityakumar2358</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/adityakumar2358"/>
    <language>en</language>
    <item>
      <title>Make your commits more valuable by gardening digitaly on Moss Garden it's Built for laze devs like me who frequently pushes code instead of spamming to make the contribution graph look more greener instead grow your own garden and proudly own it</title>
      <dc:creator>Aditya Kumar</dc:creator>
      <pubDate>Mon, 26 Oct 2026 06:29:58 +0000</pubDate>
      <link>https://dev.to/adityakumar2358/make-your-commits-more-valuable-by-gardening-digitaly-on-moss-garden-its-built-for-laze-devs-like-1115</link>
      <guid>https://dev.to/adityakumar2358/make-your-commits-more-valuable-by-gardening-digitaly-on-moss-garden-its-built-for-laze-devs-like-1115</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/adityakumar2358/slow-and-steady-a-little-lazy-i-built-a-garden-that-grows-from-small-commits-1i9" class="crayons-story__hidden-navigation-link"&gt;Slow and steady, a little lazy: I built a garden that grows from small commits&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/adityakumar2358/slow-and-steady-a-little-lazy-i-built-a-garden-that-grows-from-small-commits-1i9" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady Submission 🦥&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/adityakumar2358" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F4152822%2F9a5cf499-275d-4935-b473-c7ce914c5856.png" alt="adityakumar2358 profile" class="crayons-avatar__image" width="460" height="460"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/adityakumar2358" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Aditya Kumar
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Aditya Kumar
                
                
              
              &lt;div id="story-author-preview-content-4904961" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/adityakumar2358" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F4152822%2F9a5cf499-275d-4935-b473-c7ce914c5856.png" class="crayons-avatar__image" alt="" width="460" height="460"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Aditya Kumar&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/adityakumar2358/slow-and-steady-a-little-lazy-i-built-a-garden-that-grows-from-small-commits-1i9" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Oct 23&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/adityakumar2358/slow-and-steady-a-little-lazy-i-built-a-garden-that-grows-from-small-commits-1i9" id="article-link-4904961"&gt;
          Slow and steady, a little lazy: I built a garden that grows from small commits
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/hf26challenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;hf26challenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/adityakumar2358/slow-and-steady-a-little-lazy-i-built-a-garden-that-grows-from-small-commits-1i9" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;11&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/adityakumar2358/slow-and-steady-a-little-lazy-i-built-a-garden-that-grows-from-small-commits-1i9#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            12 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>git</category>
      <category>productivity</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>Slow and steady, a little lazy: I built a garden that grows from small commits</title>
      <dc:creator>Aditya Kumar</dc:creator>
      <pubDate>Fri, 23 Oct 2026 11:30:26 +0000</pubDate>
      <link>https://dev.to/adityakumar2358/slow-and-steady-a-little-lazy-i-built-a-garden-that-grows-from-small-commits-1i9</link>
      <guid>https://dev.to/adityakumar2358/slow-and-steady-a-little-lazy-i-built-a-garden-that-grows-from-small-commits-1i9</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19"&gt;Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I kept coming back to one question: why does a tool that is supposed to celebrate software development make people feel guilty for not developing software every single day?&lt;/p&gt;

&lt;p&gt;A contribution graph is useful. It gives you a visual history of your work. But the moment you start protecting the green squares instead of enjoying the work behind them, the incentive has quietly changed. You start optimizing for activity rather than consistency, and consistency rather than well-being.&lt;/p&gt;

&lt;p&gt;I wanted to build something that rewarded the behaviour I actually wanted to encourage: returning to a project, making a little progress, and being comfortable walking away when life gets busy.&lt;/p&gt;

&lt;p&gt;That led to three rules I treated as product requirements, not optional features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Progress must be permanent.&lt;/strong&gt; XP is lifetime progress. A quiet week must never erase what someone has earned.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency must beat intensity.&lt;/strong&gt; The game should make several small sessions more rewarding than compressing all your activity into one night.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rest must not require permission.&lt;/strong&gt; There should be no streak to save, no deadline to beat, and no punishment waiting when someone returns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These rules shaped the game mechanics, the backend, the AI integration, and even the way the application handles deployment failures. If a model is unavailable, the garden should still grow. If someone disappears for a month, their garden should still be there.&lt;/p&gt;

&lt;p&gt;Moss Garden is my attempt to make a developer productivity tool that doesn't turn productivity into another source of pressure.&lt;/p&gt;

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

&lt;p&gt;It is 11:52 PM. You are tired, the bug can wait until morning, but a small green square on your contribution graph is about to turn grey. So you push a typo fix you do not care about, just to keep the streak alive.&lt;/p&gt;

&lt;p&gt;Most developers know that feeling. A tool meant to celebrate your work quietly turns every missed day into a small loss. I wanted the opposite: something that is glad when you show up, and does not punish you when you don't.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Moss Garden&lt;/strong&gt;, a slow-productivity game for developers. You sign in with GitHub, pick the repositories that count, and every small commit you author grows a hand-drawn garden of moss, ferns, flowers and a young maple.&lt;/p&gt;

&lt;p&gt;The garden keeps everything it grows. XP never goes down, there are no streaks to protect, and nothing resets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The laziness it rewards:&lt;/strong&gt; showing up a little, on a few days, and ignoring the rest.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each commit is worth less the more you push in one day (1x, 0.5x, 0.25x, then 0.1x), and daily XP caps at 40. Ten commits at midnight are worth barely more than three.&lt;/li&gt;
&lt;li&gt;Four cared-for days in one week earn a one-time steady-week bonus that a single all-nighter cannot.&lt;/li&gt;
&lt;li&gt;Take a week off and vitality only settles to a floor. Plants never wilt. Come back after a month and it is all still there, waiting, with a "Came back" badge to say welcome home.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anyone who has felt a contribution graph turn a missed day into a loss gets to be a little lazier here. After sign-in there is nothing to log. A nightly sync does the remembering, and an optional AI gardener writes you a short journal each week about what grew.&lt;/p&gt;

&lt;p&gt;The idea is simple: your garden should reflect the work you have done, not the days you failed to show up.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://moss-garden-api.onrender.com/" rel="noopener noreferrer"&gt;https://moss-garden-api.onrender.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You do not need to sign in. Press &lt;strong&gt;Explore a demo garden&lt;/strong&gt; on the home page and wander around.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffekiq76r8okgegap47qz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffekiq76r8okgegap47qz.gif" alt="Animated explainer of Moss Garden: sign in with GitHub, grow the garden one small commit at a time, watch plants mature, and collect badges. Nothing resets after a break." width="720" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few corners of the garden:&lt;/p&gt;

&lt;p&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%2Fdw2ylxh9qln5g8r9fvoa.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%2Fdw2ylxh9qln5g8r9fvoa.png" alt="Moss Garden screenshot 1" width="799" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&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%2Fq3swg4yb0z7y0n3okgkb.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%2Fq3swg4yb0z7y0n3okgkb.png" alt="Moss Garden screenshot 2" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&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%2F9ap846secmd7mk60zs9r.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%2F9ap846secmd7mk60zs9r.png" alt="Moss Garden screenshot 3" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&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%2Fray910dki6w4ou7v4cpe.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%2Fray910dki6w4ou7v4cpe.png" alt="Moss Garden screenshot 4" width="799" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&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%2F0alg6vryn0oaozlszyfj.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%2F0alg6vryn0oaozlszyfj.png" alt="Moss Garden screenshot 5" width="799" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&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%2Fd1tgj78mskb1j707kko1.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%2Fd1tgj78mskb1j707kko1.png" alt="Moss Garden screenshot 6" width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&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/ADITYA-KUMAR-2358" rel="noopener noreferrer"&gt;
        ADITYA-KUMAR-2358
      &lt;/a&gt; / &lt;a href="https://github.com/ADITYA-KUMAR-2358/Moss-Garden" rel="noopener noreferrer"&gt;
        Moss-Garden
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A cozy garden that grows from your GitHub commits. Small, steady commits earn XP, plants, badges and seasons; all-nighters wither it, and missed days never reset it. Commit quality, plant names and a weekly journal come from Gemma 4, an open-weight model. 
    &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 href="https://moss-garden-api.onrender.com" rel="nofollow noopener noreferrer"&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%2FADITYA-KUMAR-2358%2FMoss-Garden%2FHEAD%2Ffrontend%2Fpublic%2Frepocard.png" alt="Moss Garden. Small commits. Slow growth. A garden that remembers. A slow-productivity game that turns your GitHub activity into a persistent garden." width="100%"&gt;
  &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://moss-garden-api.onrender.com" rel="nofollow noopener noreferrer"&gt;&lt;strong&gt;Live site&lt;/strong&gt;&lt;/a&gt; ·
  &lt;a href="https://github.com/ADITYA-KUMAR-2358/Moss-Garden/docs/PRD.md" rel="noopener noreferrer"&gt;Product&lt;/a&gt; ·
  &lt;a href="https://github.com/ADITYA-KUMAR-2358/Moss-Garden/docs/02-GAME-DESIGN.md" rel="noopener noreferrer"&gt;Game rules&lt;/a&gt; ·
  &lt;a href="https://github.com/ADITYA-KUMAR-2358/Moss-Garden/docs/ARCHITECTURE.md" rel="noopener noreferrer"&gt;Architecture&lt;/a&gt; ·
  &lt;a href="https://github.com/ADITYA-KUMAR-2358/Moss-Garden/docs/DESIGN.md" rel="noopener noreferrer"&gt;Design system&lt;/a&gt; ·
  &lt;a href="https://github.com/ADITYA-KUMAR-2358/Moss-Garden/docs/DEPLOYMENT.md" rel="noopener noreferrer"&gt;Deploy&lt;/a&gt; ·
  &lt;a href="https://github.com/ADITYA-KUMAR-2358/Moss-Garden/AGENTS.md" rel="noopener noreferrer"&gt;For coding agents&lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Moss Garden&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;A slow-productivity game for developers.&lt;/strong&gt; Sign in with GitHub, pick the repositories that count, and every small commit you author grows a hand-drawn garden of moss, ferns, flowers and a young maple. The garden keeps everything it grows. There are no streaks to protect, no countdowns and nothing to lose.&lt;/p&gt;

&lt;p&gt;Built for the DEV Hacktoberfest challenge &lt;em&gt;"Slow and Steady: build something with open-weight models or open-source AI that rewards laziness."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/ADITYA-KUMAR-2358/Moss-Garden/frontend/public/moss-garden-explainer.gif"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2FADITYA-KUMAR-2358%2FMoss-Garden%2FHEAD%2Ffrontend%2Fpublic%2Fmoss-garden-explainer.gif" alt="Moss Garden explainer: a garden grows one small commit at a time, plants and badges are collected, and nothing resets after a break." width="100%"&gt;&lt;/a&gt;
&lt;/p&gt;

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

&lt;p&gt;Contribution graphs and streak counters reward intensity. A missed day feels like a loss, a 2 a.m. push feels like a win, and the first broken streak is often the last day someone shows up. Moss Garden flips that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Steady beats loud.&lt;/strong&gt; Each commit is worth less the more you push in one day, and daily XP is capped…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ADITYA-KUMAR-2358/Moss-Garden" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;

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

&lt;p&gt;The rule I set myself: &lt;strong&gt;the garden has to be trustworthy first, and clever second.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open-weight model: Gemma 4 through Backboard.&lt;/strong&gt; &lt;code&gt;google/gemma-4-26b-a4b-it&lt;/code&gt; names new plants and writes the weekly journal, the little touches that make a garden feel like yours.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is opt-in. It is off for every player until they switch it on, and off on the server until a request budget is set.&lt;/li&gt;
&lt;li&gt;It only sees garden counts, the season and plant species. It never sees code, repository names or commit messages.&lt;/li&gt;
&lt;li&gt;Model output is treated as untrusted. It is parsed against a strict schema, and a failed call falls back to plain rule-based text instead of lowering anyone's score.&lt;/li&gt;
&lt;li&gt;A daily request budget keeps calls within a small credit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The game itself is deliberately not AI.&lt;/strong&gt; XP, levels, vitality, plant growth and badges live in a pure Python rules engine with 409 pytest cases. A game people trust needs rules that behave the same every time, so the model only adds words and names. It never decides what you earned.&lt;/p&gt;

&lt;h3&gt;
  
  
  How the garden actually works
&lt;/h3&gt;

&lt;p&gt;The important engineering decision was to keep the rules deterministic. A garden should not award different XP because a language model had a different answer on Tuesday.&lt;/p&gt;

&lt;p&gt;The flow is deliberately simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Connect GitHub.&lt;/strong&gt; The player signs in and selects the repositories they want Moss Garden to consider.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Synchronize activity.&lt;/strong&gt; A scheduled backend job fetches eligible commit activity, so the player doesn't have to manually record anything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apply the rules.&lt;/strong&gt; The Python game engine calculates XP, levels, vitality, plant growth and badges from the activity and the game's rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persist the result.&lt;/strong&gt; The backend stores the garden's state so the experience can continue across sessions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Present the garden.&lt;/strong&gt; The React frontend turns that state into a visual space with growing plants, seasonal changes, earned badges and a weekly journal.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;GitHub is the source of activity, the rules engine is the authority on progress, and the frontend is how that progress becomes something you can see.&lt;/p&gt;

&lt;p&gt;The frontend doesn't need to understand how XP is calculated, and the model doesn't need access to the database or the player's source code. Each layer has a narrower job, which makes the system easier to test and reason about.&lt;/p&gt;

&lt;h3&gt;
  
  
  The mechanics behind slow productivity
&lt;/h3&gt;

&lt;p&gt;The rules are deliberately biased toward distributed effort rather than raw volume.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Player behaviour&lt;/th&gt;
&lt;th&gt;Game response&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;First eligible commit of the day&lt;/td&gt;
&lt;td&gt;Full XP weight&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Second commit on the same day&lt;/td&gt;
&lt;td&gt;Half XP weight&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Third commit on the same day&lt;/td&gt;
&lt;td&gt;Quarter XP weight&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Further commits that day&lt;/td&gt;
&lt;td&gt;Diminishing returns, down to 0.1x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Daily progress&lt;/td&gt;
&lt;td&gt;Capped at 40 XP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Activity across four days in a week&lt;/td&gt;
&lt;td&gt;One-time steady-week bonus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A quiet week&lt;/td&gt;
&lt;td&gt;Vitality settles to a floor; earned progress stays&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The numbers are not meant to measure the quality of someone's code. They are a game mechanic designed to make a particular habit feel rewarding: show up, make progress, and leave when you're done.&lt;/p&gt;

&lt;p&gt;The cap also prevents a large burst of activity from dominating the garden. A developer who makes a few small commits across several days can still earn the steady-week bonus that a single all-nighter cannot.&lt;/p&gt;

&lt;p&gt;The distinction I care about most is this: &lt;strong&gt;the game can slow down without taking anything away.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The technology stack
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Stack:&lt;/strong&gt; React 19 + Vite on the front, FastAPI + SQLAlchemy 2 + Alembic on the back, PostgreSQL in production and SQLite locally. The art is layered illustration, with light and dark themes and &lt;code&gt;prefers-reduced-motion&lt;/code&gt; respected everywhere, because a calm game should be calm for everyone.&lt;/p&gt;

&lt;p&gt;Each part has a specific responsibility:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;React 19 + Vite&lt;/td&gt;
&lt;td&gt;Renders the garden, handles interactions and presents the player's progress&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FastAPI&lt;/td&gt;
&lt;td&gt;Exposes the application API and coordinates backend operations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQLAlchemy 2 + Alembic&lt;/td&gt;
&lt;td&gt;Handles database access and schema migrations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;Persists production data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQLite&lt;/td&gt;
&lt;td&gt;Simplifies local development&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python rules engine&lt;/td&gt;
&lt;td&gt;Calculates XP, levels, vitality, plant growth and badges&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backboard + Gemma 4&lt;/td&gt;
&lt;td&gt;Generates optional plant names and weekly journal entries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Actions&lt;/td&gt;
&lt;td&gt;Handles keep-alive and scheduled synchronization workflows&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The stack is not just a list of technologies. Each part has a boundary, and those boundaries are important to keeping the experience predictable.&lt;/p&gt;

&lt;p&gt;I also kept a &lt;code&gt;docs/&lt;/code&gt; directory alongside &lt;code&gt;AGENTS.md&lt;/code&gt;. The repository documents the product requirements, game rules, architecture, design system and implementation decisions.&lt;/p&gt;

&lt;p&gt;That documentation serves two audiences: a developer opening the repository for the first time, and a coding agent that needs to understand the existing constraints before changing anything.&lt;/p&gt;

&lt;p&gt;The goal is that someone should be able to pick up Moss Garden without relying on a conversation with the person who built it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deployment on Render
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Render:&lt;/strong&gt; &lt;code&gt;render.yaml&lt;/code&gt; creates a free Docker web service and a free Postgres database. The container runs migrations, then starts the server. Free-tier limits shaped the design, and I leaned into them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A free web service sleeps, so a &lt;strong&gt;GitHub Actions&lt;/strong&gt; keep-alive workflow pings it.&lt;/li&gt;
&lt;li&gt;Render cron jobs are not free, so a second &lt;strong&gt;GitHub Actions&lt;/strong&gt; workflow calls &lt;code&gt;POST /api/jobs/nightly&lt;/code&gt; with a bearer secret for the nightly sync.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This keeps the scheduling logic separate from the application process. The nightly sync can run independently, without requiring someone to open the website.&lt;/p&gt;

&lt;p&gt;The free hosting tier still comes with trade-offs, including cold starts and resource limits. The workflows help work around those constraints, but they do not eliminate every hosting limitation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sound and accessibility
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;ElevenLabs:&lt;/strong&gt; the soft sound effects and ambience were generated with ElevenLabs once and shipped as static files, so there are no runtime calls and no key in production. Sound is off by default, never autoplays, and every sound has something on screen too. The journal can be read aloud with the browser's speech. An ElevenLabs narration client is written but not switched on yet.&lt;/p&gt;

&lt;p&gt;I wanted the sensory details to support the experience without demanding attention. Sound should be an invitation, not something the user has to fight to disable.&lt;/p&gt;

&lt;p&gt;The same principle applies to motion. The garden uses layered illustrations, light and dark themes, and respects &lt;code&gt;prefers-reduced-motion&lt;/code&gt;. A slow-productivity tool should not force everyone into the same visual experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the Idea, Not Just the Interface
&lt;/h2&gt;

&lt;p&gt;A garden can look convincing while quietly breaking the promise behind it. The difficult cases aren't whether a flower renders or whether a button responds. They're whether the rules remain fair when activity is irregular, synchronization happens more than once, or the AI feature is unavailable.&lt;/p&gt;

&lt;p&gt;I built the rules engine separately so that its behaviour could be tested without relying on a live GitHub account, a running frontend or a language model.&lt;/p&gt;

&lt;p&gt;The backend test suite contains 409 pytest cases. The core rules are particularly important because they determine whether the experience remains consistent over time.&lt;/p&gt;

&lt;p&gt;Some of the behaviours worth testing are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Diminishing returns:&lt;/strong&gt; additional commits on the same day must receive the intended lower XP weights.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The daily cap:&lt;/strong&gt; repeated activity must not push daily XP beyond the defined limit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The steady-week bonus:&lt;/strong&gt; the bonus depends on activity across distinct days, not simply a large number of commits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permanent progress:&lt;/strong&gt; inactivity must never subtract lifetime XP or remove established plants.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plant progression:&lt;/strong&gt; growth and unlocks must follow the rules rather than the wording generated by the AI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI failure:&lt;/strong&gt; an unsuccessful model request must not change game state or prevent the rule-based fallback from working.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the kinds of invariants that make the experience trustworthy. A visual regression is easy to notice; a subtle scoring bug can go unnoticed while quietly undermining the entire idea.&lt;/p&gt;

&lt;p&gt;The tests are not proof that every real-world GitHub edge case has been covered. They are a way to make the core rules explicit, repeatable and safer to change as the project evolves.&lt;/p&gt;

&lt;p&gt;For me, this is also where the project became more than a frontend experiment. The illustration makes the garden inviting, but the rules and their tests are what make it fair.&lt;/p&gt;

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

&lt;p&gt;Moss Garden reads your commit history, which is personal. Open weights made three things possible that a closed API would not:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Trust you can inspect.&lt;/strong&gt; The code is public, the rules are documented, and the model is an open-weight Gemma 4 with a permissive licence. The model only receives counts and species, and because the weights are open, anyone could run it locally so nothing leaves their machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A promise that outlives a vendor.&lt;/strong&gt; The game promises that nothing resets. That promise should not depend on a hosted model version being deprecated. The garden works with the AI fully off, and the model is a swappable setting behind one Backboard key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost control on a small budget.&lt;/strong&gt; Running a capable open model through one key, with a request budget, made an always-gentle feature affordable for a solo project.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There is also an important distinction between an open-weight model and a fully local deployment. Moss Garden currently uses Gemma 4 through Backboard. The model's open weights provide another path for future deployments, but the current hosted integration is not the same as running inference locally.&lt;/p&gt;

&lt;p&gt;That distinction matters because privacy should be explained through the actual data flow, not simply through the name of the model.&lt;/p&gt;

&lt;p&gt;The application needs GitHub activity to grow the garden. The optional AI gardener receives a deliberately narrower set of information: garden counts, the season and plant species. It does not receive source code, repository names or commit messages.&lt;/p&gt;

&lt;p&gt;The AI is there to add personality, not to become the authority over the user's progress.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lazy Payoff
&lt;/h2&gt;

&lt;p&gt;The saved effort is attention, not hours. There is no logging, no habit to maintain and no streak to defend. You sign in once, commit as you normally would, and open the garden when you feel like it.&lt;/p&gt;

&lt;p&gt;Close the laptop at 11:52 PM. Take the weekend. Take the month. When you come back, the moss will still be there, a little greener than you left it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Can't Do Yet
&lt;/h2&gt;

&lt;p&gt;Moss Garden is a working project, not a claim that productivity has been solved. There are a few limitations worth being honest about.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It measures activity, not engineering quality.&lt;/strong&gt; A commit is a signal that work happened, not proof that the work was valuable. The game cannot reliably judge the difficulty, impact or craftsmanship of a change, and it shouldn't pretend to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Synchronization is not instantaneous.&lt;/strong&gt; Activity is collected through the scheduled synchronization workflow. A newly pushed commit may not appear in the garden immediately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The free hosting tier has trade-offs.&lt;/strong&gt; Render's free web service can sleep when idle, and the database has its own free-tier constraints. The keep-alive and nightly-sync workflows help with availability and scheduling, but they don't eliminate every hosting limitation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The AI gardener depends on configuration and availability.&lt;/strong&gt; Gemma 4 is optional. If the feature is disabled, its request budget is unavailable, or a request fails, the application must fall back to ordinary rule-based text rather than making the game dependent on the model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The deployed AI integration is hosted.&lt;/strong&gt; Gemma 4 is an open-weight model, but the deployed application calls it through Backboard. Running the model locally would require a suitable local inference integration; open weights alone don't make the current hosted implementation local.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The garden is a model of progress, not a replacement for your workflow.&lt;/strong&gt; It doesn't manage tasks, review pull requests or tell you what to build next. Its job is to give your existing development activity a gentler visual home.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These limitations are part of the design conversation, not reasons to abandon the idea. I would rather ship a small, understandable system with clear boundaries than claim that a garden can measure everything that matters about software development.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Render:&lt;/strong&gt; free Docker web service and Postgres from a single &lt;code&gt;render.yaml&lt;/code&gt;, with GitHub Actions covering keep-alive and the nightly sync around free-tier limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backboard:&lt;/strong&gt; Gemma 4 runs through a single Backboard API key, with a request budget and a rules-based fallback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ElevenLabs:&lt;/strong&gt; the game's sound effects and ambience were generated with ElevenLabs and shipped as static assets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemma:&lt;/strong&gt; Gemma 4 names the plants and writes the journal, and the whole app works without it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Copilot:&lt;/strong&gt; Copilot was my pair programmer while building Moss Garden, and github workflows are created by the Github Copilot too&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;I'd love to keep improving Moss Garden without losing the principle that made me build it in the first place.&lt;/p&gt;

&lt;p&gt;The most important thing is to keep the experience dependable: preserve the garden, make synchronization predictable, keep the game rules testable, and ensure the optional AI remains optional.&lt;/p&gt;

&lt;p&gt;There is room to expand the garden's visual language, improve the onboarding experience, and make the local-model path more practical. But I don't want to add features simply because a productivity app is expected to have them.&lt;/p&gt;

&lt;p&gt;Every addition should answer one question: does this make the garden more welcoming, more useful or more trustworthy?&lt;/p&gt;

&lt;p&gt;If the answer is no, it probably doesn't belong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Come Wander Around
&lt;/h2&gt;

&lt;p&gt;If you try Moss Garden, I'd love to hear what the experience feels like after a few days, especially if you take a break and return to it later.&lt;/p&gt;

&lt;p&gt;Does a garden that remembers your progress feel different from a graph that counts your days? Which parts would make you want to come back, and which parts feel unnecessary?&lt;/p&gt;

&lt;p&gt;You can explore the demo without signing in, inspect the implementation, and follow the rules in the repository:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://moss-garden-api.onrender.com/" rel="noopener noreferrer"&gt;Explore the live demo&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/ADITYA-KUMAR-2358/Moss-Garden" rel="noopener noreferrer"&gt;Read the source code on GitHub&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The project is open source, and feedback, bug reports and thoughtful contributions are welcome.&lt;/p&gt;

&lt;p&gt;I'd like Moss Garden to be the kind of tool that makes you happy to return, not one that makes you afraid to leave.&lt;/p&gt;

&lt;p&gt;Built solo, slowly and steadily, by &lt;a href="https://github.com/ADITYA-KUMAR-2358" rel="noopener noreferrer"&gt;Aditya Kumar&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>What If Your Local Kirana Store Could Predict Tomorrow's Demand? Meet DukaanDost</title>
      <dc:creator>Aditya Kumar</dc:creator>
      <pubDate>Wed, 14 Oct 2026 11:52:24 +0000</pubDate>
      <link>https://dev.to/adityakumar2358/what-if-your-local-kirana-store-could-predict-tomorrows-demand-meet-dukaandost-1olc</link>
      <guid>https://dev.to/adityakumar2358/what-if-your-local-kirana-store-could-predict-tomorrows-demand-meet-dukaandost-1olc</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⭐ If this is useful to a shop near you, star the repo: &lt;a href="https://github.com/ADITYA-KUMAR-2358/Dukaan-Dost" rel="noopener noreferrer"&gt;DukaanDost&lt;/a&gt;. It helps the next counter find it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Who I built it for
&lt;/h2&gt;

&lt;p&gt;Sharma Kirana is the shop next door. The owner already had a billing export, and he still ordered by feel.&lt;/p&gt;

&lt;p&gt;A quiet week might mean nobody wants the item. It might also mean the shelf was empty. A festival week can look like a spike that will not come back. Packs arrive in fixed sizes, and a bad buy ties up cash a small counter does not have.&lt;/p&gt;

&lt;p&gt;I built DukaanDost for that counter. Kam andaaza. Sahi stock. Behtar dukaan. Less guessing. The right stock. A better shop.&lt;/p&gt;

&lt;p&gt;He used it. He read the forecast against his sales and the festivals coming up, and he restocked candles and oils, because the prediction put those items in demand.&lt;/p&gt;

&lt;p&gt;Other people building for the same counter ran into the same facts. A forecast that looks fine for a product family falls apart at the SKU, which is the only level a shopkeeper buys at (&lt;a href="https://dev.to/cobuildx-ai/why-your-demand-forecast-is-wrong-at-the-sku-level-1iog"&gt;Why Your Demand Forecast Is Wrong at the SKU Level&lt;/a&gt;). A kirana that runs out of milk on Sunday is a stockout, not a demand of zero (&lt;a href="https://dev.to/lasyapriya_putti/my-friends-kirana-store-runs-out-of-milk-every-sunday-so-i-gave-it-a-voice-3c4k"&gt;My friend's kirana store runs out of milk every Sunday&lt;/a&gt;). And TabPFN plus Gemma can sit behind a small shop's own history, as in &lt;a href="https://dev.to/jyotir07/secondo-an-offline-baking-planner-for-my-friends-cafe-built-on-gemma-and-tabpfn-517g"&gt;SECONDO&lt;/a&gt;, without the screen pretending a fallback was the model.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem it solves for him
&lt;/h2&gt;

&lt;p&gt;His bills already knew what sold. They did not tell him what to buy next, in which pack size, or whether a quiet stretch was a stockout. DukaanDost turns that file into a quantity he can check before the next purchase.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;DukaanDost takes a billing CSV and writes item-level demand, a reorder quantity, and a short explanation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Forecasts are built per product from lagged sales, rolling pace, and the calendar.&lt;/li&gt;
&lt;li&gt;Restock is lead-time demand plus safety stock, rounded to pack size.&lt;/li&gt;
&lt;li&gt;A stockout is not treated as proof that nobody wants the item.&lt;/li&gt;
&lt;li&gt;You can compare weeks. The app does not invent a festival uplift.&lt;/li&gt;
&lt;li&gt;Bad dates, blank products, and duplicate files are listed with row numbers.&lt;/li&gt;
&lt;li&gt;Explanations are English or Hinglish. If Gemma does not answer, a template says so.&lt;/li&gt;
&lt;li&gt;If TabPFN cannot run, the screen names the baseline. It does not call that baseline TabPFN.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Forecasts are estimates, not a promise of tomorrow's sales. The public sample file uses the same shop name and is marked fictional, so a visitor does not confuse that demo with his bills. The candle and oil restock came from his own sales.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in it
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;What you can do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sample&lt;/td&gt;
&lt;td&gt;Open a labelled sample kirana that stays separate from your own shop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Import&lt;/td&gt;
&lt;td&gt;Preview a CSV, map columns, and see row errors before anything is saved&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inventory&lt;/td&gt;
&lt;td&gt;Update stock, with an audit row for receipts and adjustments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Forecast&lt;/td&gt;
&lt;td&gt;One series per product, or a clear note when the history is too thin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Restock&lt;/td&gt;
&lt;td&gt;Reorder point, pack size, slow-moving flag, stockout flag&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Words&lt;/td&gt;
&lt;td&gt;English or Hinglish. Gemma through the Google endpoint when a key is set and the words still match the numbers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Export&lt;/td&gt;
&lt;td&gt;Inventory, forecasts, recommendations, import quality, and evaluation as CSV&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Privacy&lt;/td&gt;
&lt;td&gt;SQLite when no Supabase key is set. The hosted demo stores shop rows in Supabase and says so&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;The public site is &lt;a href="https://dukaandost-web.onrender.com" rel="noopener noreferrer"&gt;https://dukaandost-web.onrender.com&lt;/a&gt;. The API is &lt;a href="https://dukaandost-api.onrender.com" rel="noopener noreferrer"&gt;https://dukaandost-api.onrender.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A free Render service sleeps. The shop page can sit on a loading block until &lt;code&gt;/health&lt;/code&gt; answers. Use the sample shop on that demo. Anything you import there is stored in the hosted Supabase project, not on your computer.&lt;/p&gt;

&lt;p&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%2Fta8ekkk2pec3furmr9r2.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%2Fta8ekkk2pec3furmr9r2.png" alt="DukaanDost dashboard for the sample kirana, with a label marking the data as fictional" width="799" height="385"&gt;&lt;/a&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%2F738t4d9nmtkc0gap4f7f.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%2F738t4d9nmtkc0gap4f7f.png" alt="CSV import preview with column mapping and a list of bad rows with row numbers" width="800" height="382"&gt;&lt;/a&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%2Fl7dz10fh7qgmu7vos2dl.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%2Fl7dz10fh7qgmu7vos2dl.png" alt="Item-level demand forecast for one product, with the name of the model that produced it" width="800" height="383"&gt;&lt;/a&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%2F1o5p3slih3hne0dzpkoe.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%2F1o5p3slih3hne0dzpkoe.png" alt="Restock recommendations table with reorder point, pack size, slow-moving and stockout flags" width="799" height="389"&gt;&lt;/a&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%2Fpi5974v32rbbk6m6y7j2.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%2Fpi5974v32rbbk6m6y7j2.png" alt="Inventory screen for updating stock, with an audit row for each receipt or adjustment" width="800" height="388"&gt;&lt;/a&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%2F1y4yjx5ne0vo6rlamodv.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%2F1y4yjx5ne0vo6rlamodv.png" alt="Plain-language explanation of a recommendation in Hinglish, showing whether Gemma or the template wrote it" width="800" height="388"&gt;&lt;/a&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%2Fdqrjk7fxl4frt7m36f4d.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%2Fdqrjk7fxl4frt7m36f4d.png" alt="Export options for inventory, forecasts, recommendations and import quality as CSV" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  DukaanDost
&lt;/h2&gt;

&lt;p&gt;Kam andaaza. Sahi stock. Behtar dukaan.&lt;/p&gt;

&lt;p&gt;DukaanDost turns a small shop's billing CSV into stock advice the owner can check. TabPFN forecasts demand through the Prior Labs API when &lt;code&gt;TABPFN_API_KEY&lt;/code&gt; is set. Gemma explains the numbers in plain language when &lt;code&gt;LLM_API_KEY&lt;/code&gt; is set and the reply still matches the math. If either one is absent, the shop still gets a named baseline and a template that says so.&lt;/p&gt;

&lt;p&gt;It is built for one real counter: Sharma Kirana, next door. He restocked candles and oils from the forecast.&lt;/p&gt;

&lt;p&gt;Built by Aditya Kumar (@ADITYA-KUMAR-2358) for the DEV Hacktoberfest challenge, Side Hustle.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/ADITYA-KUMAR-2358/Dukaan-Dost" rel="noopener noreferrer"&gt;https://github.com/ADITYA-KUMAR-2358/Dukaan-Dost&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The application code is MIT. TabPFN is called through the Prior Labs API. This repository does not ship model weights.&lt;/p&gt;
&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;TabPFN reads the billing table when an API key is set. Gemma writes the explanation when its own key is set. Neither one is allowed to wear the other's name. On the hosted check I ran, the forecast path used a named baseline, and the explanation came back as the template. The status screen can say Gemma is configured while a particular reply is still the template. The screen has to say which one it was.&lt;/p&gt;

&lt;p&gt;TabPFN comes in through &lt;code&gt;tabpfn-client&lt;/code&gt;. An empty &lt;code&gt;TABPFN_API_KEY&lt;/code&gt; stays on a named baseline: seasonal naive, Croston, or a moving average. There is no weight download in this deploy.&lt;/p&gt;

&lt;p&gt;Gemma is optional, through Google's OpenAI-compatible endpoint (&lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt; by default). Leave &lt;code&gt;LLM_API_KEY&lt;/code&gt; empty and the template is used. The reply is kept only when it still matches the calculated numbers.&lt;/p&gt;

&lt;p&gt;The hosted shop data goes through the Supabase Data API. &lt;code&gt;SUPABASE_DB_URL&lt;/code&gt; can stay empty. The backend credential is &lt;code&gt;SUPABASE_SECRET_KEY&lt;/code&gt;. The publishable key is public, and the schema does not grant it access to the shop tables. Run &lt;code&gt;backend/app/db/supabase_schema.sql&lt;/code&gt; in the Supabase SQL editor after the secret key is in the environment. With both the URL and the key empty, the API uses a local SQLite file.&lt;/p&gt;
&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+--------------------------------------+
| BROWSER                              |
| React 19, Vite, TypeScript           |
| Tailwind v4, GSAP                    |
| Render static site                   |
+--------------------------------------+
                 |
                 |  CSV, then JSON
                 v
+--------------------------------------+
| FastAPI on Render                    |
| pandas                               |
| Supabase Data API, or SQLite         |
+--------------------------------------+
        |                    |
        v                    v
   Prior Labs           Gemma via Google
   TabPFN API           or an English /
   or a named           Hinglish template
   baseline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;Choice&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;React 19, Vite, TypeScript, Tailwind v4, GSAP&lt;/td&gt;
&lt;td&gt;A shop page that stays readable, with a few deliberate motions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;FastAPI, pandas, Supabase Data API or SQLite&lt;/td&gt;
&lt;td&gt;Hosted shop rows in Supabase. A local file when those keys are empty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Forecast&lt;/td&gt;
&lt;td&gt;TabPFN through the Prior Labs API, then a named baseline&lt;/td&gt;
&lt;td&gt;Tabular history is what a billing CSV already is&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Words&lt;/td&gt;
&lt;td&gt;Gemma 4 through the Google endpoint&lt;/td&gt;
&lt;td&gt;Optional. Empty API key keeps the template&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Honesty&lt;/td&gt;
&lt;td&gt;Model id stored with the run&lt;/td&gt;
&lt;td&gt;A fallback is never labelled TabPFN&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  From a billing file to an order
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; Owner exports a billing CSV
        |
        v
 Preview, map columns, list bad rows
        |
        v
 Features: lags, rolling pace, calendar
        |
        v
 TabPFN API ---- no key or the call fails ----&amp;gt; seasonal naive,
        |                                         Croston, or
        |                                         moving average
        v
 Reorder quantity, rounded to pack size
        |
        v
 Gemma explains the numbers
        |   no key, or the reply drifts
        v
 English or Hinglish template, and it says so
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Things I had to get right
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Naming the model that actually ran. If TabPFN cannot run, the baseline keeps its own name.&lt;/li&gt;
&lt;li&gt;Keeping his shop separate from the sample. The demo file is fictional on purpose.&lt;/li&gt;
&lt;li&gt;Not inventing a festival uplift. He can compare weeks. The app does not add a festival percentage he cannot see.&lt;/li&gt;
&lt;li&gt;Not treating a stockout as "nobody wants this."&lt;/li&gt;
&lt;li&gt;Checking Gemma. If the sentence does not match the calculated numbers, the template is what he reads.&lt;/li&gt;
&lt;li&gt;Keeping the publishable Supabase key out of the write path. That key is meant to be public.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  What was hard
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The Render install. &lt;code&gt;realtime&lt;/code&gt;, which ships with the Supabase client, needs Pydantic 2.11.7 or newer. Pydantic 2.14 needs &lt;code&gt;typing-extensions&lt;/code&gt; 4.16, and &lt;code&gt;tabpfn-client&lt;/code&gt; 0.2.7 only allows 4.15. The pins that install together are &lt;code&gt;pydantic==2.13.5&lt;/code&gt; and &lt;code&gt;typing-extensions==4.15.0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A public key that could write every shop table. The first schema granted that to &lt;code&gt;anon&lt;/code&gt;. The backend now looks for &lt;code&gt;SUPABASE_SECRET_KEY&lt;/code&gt;, and the schema file revokes the public grants. The SQL still has to be run in the Supabase editor after the secret key is saved.&lt;/li&gt;
&lt;li&gt;Thin history. Some items do not have enough days for a fit. Those rows need a clear note, not a confident number.&lt;/li&gt;
&lt;li&gt;A quiet Gemma. With no API key, or when a call does not come back clean, the template has to be good enough to order from, and it has to admit Gemma was not used.&lt;/li&gt;
&lt;li&gt;A sleeping host. The static site can be up while the free API is still waking. The shop page waits on &lt;code&gt;/health&lt;/code&gt; instead of showing an empty shop as if the data were gone.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  What I'd do next
&lt;/h3&gt;

&lt;p&gt;A printed order list he can take to the wholesaler, and Hindi on the rest of the screen so the whole shop, not only the explanation, can be read in the language he uses at the counter.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Sharma Kirana's bills are a private record. What sold last Tuesday should not have to leave the shop before he can decide what to buy.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Control.&lt;/strong&gt; With no Supabase key, the forecast and the SQLite file stay on the shop computer. On the hosted demo, shop rows live in Supabase. Gemma is off until &lt;code&gt;LLM_API_KEY&lt;/code&gt; is set, and then only the calculated facts are sent, not the raw CSV. TabPFN, when its key is set, sends the feature table to Prior Labs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swappability.&lt;/strong&gt; TabPFN can be turned off. Gemma's model name is a setting. The baseline and the template still answer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost.&lt;/strong&gt; An empty key spends nothing. Gemma uses the limits in &lt;code&gt;.env&lt;/code&gt; (&lt;code&gt;LLM_MAX_RPM&lt;/code&gt;, &lt;code&gt;LLM_MAX_PER_DAY&lt;/code&gt;, &lt;code&gt;SUBMIT_LIMIT&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tunability.&lt;/strong&gt; The rule that mattered most was faithfulness: show the number you calculated, and name the model that produced it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A closed forecast that fails and still comes back wearing the vendor's name is worse than a baseline with its own name. The screen has to say which one ran.&lt;/p&gt;
&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;


&lt;div class="ltag-agent-session"&gt;
  &lt;div class="agent-session-header"&gt;
    
    &lt;span class="agent-session-tool-icon-badge" title="Gemini CLI"&gt;
&lt;/span&gt;
    &lt;span class="agent-session-title"&gt;DukaanDost: Supabase on Render, and the Pydantic pin that installs&lt;/span&gt;
  &lt;/div&gt;

  &lt;div class="agent-session-scroll"&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;The API does not stay up. Supabase is reachable, and the shop tables are still missing until the schema SQL is run. That schema lets the publishable key read and write every shop table. A secret key should be the backend credential. SUPABASE_DB_URL and BACKEND_URL are empty. The local shop in SQLite is not in Supabase.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div&gt;
                  &lt;div class="agent-session-text agent-session-text-collapse"&gt;
                    &lt;p&gt;The ten shop tables already answered on the Data API, and the local API health check returned ok. SUPABASE_DB_URL stays empty because the app uses the Data API, not a Postgres password. BACKEND_URL stays empty because the guessed Render hosts returned no-server, and a keep-alive ping against a dead host would fail every 10 minutes. SUPABASE_SECRET_KEY was added as a server-only setting. The schema SQL now drops the public api_access policy and revokes anon and authenticated grants. That SQL could not be applied from here: the Supabase SQL editor requires a sign-in. Until the secret key is pasted and that SQL is run, the API still falls back to the publishable key. The SQLite file had a sample shop and an empty local shop named My shop. My shop was copied. The sample rows were already in Supabase, so the duplicate sample was removed. The shop already open in the app stayed the active shop.&lt;/p&gt;

                  &lt;/div&gt;
                  Show more
                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-copysqliteshop"&gt;copy_sqlite_shop&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Read the local SQLite file and insert missing shop rows through the Data API.&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Read the local SQLite file and insert missing shop rows through the Data API.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;My shop copied. Duplicate sample removed. Active shop left unchanged.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Commit and push the project.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;The CI workflow went up first, then the app, frontend, sample CSV, and Render blueprint. .env and the local database were not committed. GitHub renamed the pushed branch to main.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;The Render build failed. realtime 2.7.0 needs pydantic&amp;gt;=2.11.7, and requirements.txt pinned pydantic==2.10.4.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Pydantic 2.14.1 satisfies realtime, but it needs typing-extensions&amp;gt;=4.16.0, and tabpfn-client 0.2.7 only allows typing-extensions&amp;lt;=4.15.0. The pins that install together are pydantic==2.13.5 and typing-extensions==4.15.0. A dry-run resolved, and the 16 backend tests passed. That commit was fast-forwarded onto main.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-pipdryrun"&gt;pip_dry_run&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;pip install --dry-run -r backend/requirements.txt&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;pip install --dry-run -r backend/requirements.txt&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Would install pydantic 2.13.5, pydantic-core 2.46.5, and typing-extensions 4.15.0. Resolution succeeded.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;The static site is built, but nothing is being shown at the public web URL.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;The home page was serving the built marketing page, with the stylesheet and script loading. The shop view at /app showed loading blocks until the API answered. /health on the API returned 200, and /api/status returned the active shop with an access-control-allow-origin for the static site. After that response, the overview heading was the shop name. A free Render instance can sit on those loading blocks while it wakes.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class="agent-session-footer"&gt;
    &lt;span class="agent-session-meta"&gt;
        8 of 8 messages
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  My First User
&lt;/h2&gt;

&lt;p&gt;He is the owner of Sharma Kirana, the shop next door. He used DukaanDost on his own sales. The forecast, read with those sales and the festivals coming up, put candles and oils in demand, and he restocked them.&lt;/p&gt;

&lt;p&gt;He has not paid. I built it for his counter. The result so far is stock on the shelf, not a guess from memory.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of TabPFN:&lt;/strong&gt; TabPFN forecasts item-level demand from a billing CSV when &lt;code&gt;TABPFN_API_KEY&lt;/code&gt; is set. If the call cannot run, the baseline keeps its own name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma:&lt;/strong&gt; Gemma explains those numbers in English or Hinglish, and only when the words still match the math. No API key, or a reply that does not match, means the template.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you know a shop that still orders by feel, start with their last billing file. And if this is useful, please ⭐ star &lt;a href="https://github.com/ADITYA-KUMAR-2358/Dukaan-Dost" rel="noopener noreferrer"&gt;DukaanDost on GitHub&lt;/a&gt;. Thank you for reading. ❤️&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
    </item>
    <item>
      <title>Walkworth: Walk it. Say it. Keep it. A spoken trek journal on local open-source AI</title>
      <dc:creator>Aditya Kumar</dc:creator>
      <pubDate>Sat, 10 Oct 2026 09:53:49 +0000</pubDate>
      <link>https://dev.to/adityakumar2358/walkworth-walk-it-say-it-keep-it-a-spoken-trek-journal-on-local-open-source-ai-3jp4</link>
      <guid>https://dev.to/adityakumar2358/walkworth-walk-it-say-it-keep-it-a-spoken-trek-journal-on-local-open-source-ai-3jp4</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;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Walkworth is a trek journal you speak instead of type. Before a walk you open the app once on Wi-Fi so it caches. On the trail you put the phone in your pocket, and when something is worth keeping you tap once, say it out loud, and tap again. "Langurs on the wall near the gate, three of them, totally unbothered." That's a whole entry. The phone buzzes when it starts and stops listening, so you never have to look at it.&lt;/p&gt;

&lt;p&gt;Back home, your laptop turns the voice notes, photos and GPS track into a journal. There's a cover with your route drawn on it, chapters in time order, your own words set large as quotes, and photos pinned to where you took them. You can print it, publish it, or paste it into a DEV post like this one.&lt;/p&gt;

&lt;p&gt;I wanted the screen to be the shortest part of the day. On the trail the whole interface is one button. It's for people who walk a lot and can't remember any of it by Monday, and for anyone who'd like a record of a walk without spending the walk on their phone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo and live link
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://walkworth.onrender.com" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;walkworth.onrender.com&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/FKQgP3mr19E" width="710" height="399"&gt;
  &lt;/iframe&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%2F2lovs3ecpujz3l163siz.png" alt="Walkworth demo screenshot 1" width="800" height="418"&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%2Fcy5w1cu9durmtd2brewz.png" alt="Walkworth demo screenshot 2" width="800" height="417"&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%2Fi1qnalsdtkevykov1dnz.png" alt="Walkworth demo screenshot 3" width="799" height="395"&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%2Fsimp6qsqpuo3zzpmdj19.png" alt="Walkworth demo screenshot 4" width="800" height="250"&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%2Fm8rf02wbt7bwmrlpu2el.png" alt="Walkworth demo screenshot 5" width="800" height="379"&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%2F6dma3iqnphsek31pp634.png" alt="Walkworth demo screenshot 6" width="800" height="358"&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&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/ADITYA-KUMAR-2358" rel="noopener noreferrer"&gt;
        ADITYA-KUMAR-2358
      &lt;/a&gt; / &lt;a href="https://github.com/ADITYA-KUMAR-2358/WalkWorth" rel="noopener noreferrer"&gt;
        WalkWorth
      &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;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Walkworth&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Walk it. Say it. Keep it.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A spoken trek journal. You talk while you walk and your phone stays in your pocket. Each voice note and photo uploads as you go (or waits on the phone until you're back in range). Then Gemma writes the journal around your own words, and every line it adds cites the notes it came from. A line that cites nothing is dropped before the journal is made.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How it works&lt;/h2&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start a walk.&lt;/strong&gt; One big button: tap, talk, tap. The phone buzzes when it listens, and each note gets a GPS fix.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It uploads as you go.&lt;/strong&gt; Notes and photos are kept in the browser until the server has them, so a dropped signal or a closed tab loses nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make the journal.&lt;/strong&gt; A Temporal workflow transcribes (ElevenLabs Scribe), lines notes up with the GPX track, picks out what you saw, captions photos…&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ADITYA-KUMAR-2358/WalkWorth" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


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

&lt;p&gt;The phone only records. Everything smart happens on the laptop afterwards, and I made that split on purpose. Fort trails around Pune often have no signal, and I didn't want a trek journal that needs a network or burns battery running models in my pocket.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On the phone.&lt;/strong&gt; A PWA built with Vite and TypeScript. A service worker handles offline caching, MediaRecorder does the audio, each note grabs one GPS fix, and IndexedDB stores it all. For the continuous route I use OpenTracks, an open-source Android tracker, because browsers pause GPS when the screen locks. The PWA also counts how long the screen was on, which is where the screen-time number comes from.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On the laptop.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;whisper.cpp&lt;/strong&gt; (the &lt;code&gt;small&lt;/code&gt; model) transcribes every clip. It copes with Hindi, Marathi and English in the same sentence, which is how I talk anyway.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemma 3 through Ollama&lt;/strong&gt; does the rest: it pulls structured observations out of each transcript, captions the photos, and writes the short connecting lines. I run &lt;code&gt;gemma3:4b&lt;/code&gt; by default and &lt;code&gt;gemma3:12b&lt;/code&gt; when the machine allows. The model name is one line in &lt;code&gt;walkworth.config.toml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Temporal&lt;/strong&gt; runs the pipeline as a single workflow: import, transcribe, align, extract, caption, compose. Each step is a durable activity with retries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FastAPI and SQLite&lt;/strong&gt; hold the data. No cloud database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Render&lt;/strong&gt; hosts one thing, the finished journal as a static site.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The one rule I'm strict about.&lt;/strong&gt; The journal can't lie. Every sentence the model writes has to carry the ids of the notes it came from, and a sentence with no source gets dropped before it renders. Your quotes always appear word for word. So the model can arrange and trim, but it can't invent a sighting you didn't make. I'd rather lose a nice sentence than print a fake langur.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What went wrong.&lt;/strong&gt; I started OpenTracks forty minutes late. I was already past the first bend at Atkarwadi, chai in one hand, when I remembered. So the first 2 km of the climb has no track at all. The app rebuilt it from the GPS fixes on my voice notes, and the route on the cover has one straight line where the switchbacks should be. I left it.&lt;/p&gt;

&lt;p&gt;Whisper struggled with the fort. It heard "Tanaji Kada" as "tanaji cada" and "Kalyan Darwaja" as "kalyan the wajah". Everything else came out clean, so I didn't notice until I read the landmark chips and 5 of the 9 were gibberish. I added a short glossary of 12 fort names, and now it fixes them before anything else sees the transcript.&lt;/p&gt;

&lt;p&gt;The fog was the worst. Around 7:50 at the top I said four notes in a row into a wind so loud that two of them are just noise, with my voice buried somewhere underneath. The journal skips them. The gap sits between the gate and the bhaji stall. I could've faked a line to fill it, but every sentence in this thing is supposed to be something I actually said. So it stays empty.&lt;/p&gt;

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

&lt;p&gt;Here's what going open actually bought me, from things that happened while I built this.&lt;/p&gt;

&lt;p&gt;The fort has no signal. A closed API would stop working at the base of the climb. With Whisper and Gemma on my laptop the whole pipeline runs with Wi-Fi off.&lt;/p&gt;

&lt;p&gt;The recordings are my voice and several hours of my location history. I didn't want either on a server I don't control. With local models nothing leaves the laptop. When I publish, only the finished journal goes online, and there's a switch that hides the first and last 300 metres of the route so nobody can tell where I started.&lt;/p&gt;

&lt;p&gt;And I can swap models by changing one line in the config. When Whisper mangled the fort names, the fix was a small glossary file I could edit myself. You can only make that kind of fix when you own the stack. It costs nothing per trek, too.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of ElevenLabs:&lt;/strong&gt; I used ElevenLabs to narrate the voiceover of the demo video and also for text to speech and speech to text generations ElevenLabs is being used.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma:&lt;/strong&gt; Gemma 3 runs locally through Ollama for extraction, captions and journal writing.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Best Use of Temporal:&lt;/strong&gt; the whole post-trek pipeline is one workflow.&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%2Fxv7hwmieo6vreoqy1y5b.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%2Fxv7hwmieo6vreoqy1y5b.png" alt="Temporal workflow screenshot for Walkworth" width="799" height="359"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Best Use of Render:&lt;/strong&gt; the finished journal is deployed as a static site from a &lt;code&gt;render.yaml&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>opensource</category>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>Please Give this a read</title>
      <dc:creator>Aditya Kumar</dc:creator>
      <pubDate>Sat, 03 Oct 2026 15:17:23 +0000</pubDate>
      <link>https://dev.to/adityakumar2358/please-give-this-a-read-f4i</link>
      <guid>https://dev.to/adityakumar2358/please-give-this-a-read-f4i</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/adityakumar2358/salt-story-my-maasis-recipes-saved-in-her-own-voice-56g8" class="crayons-story__hidden-navigation-link"&gt;Salt &amp;amp; Story: My Maasi's Recipes, Saved in Her Own Voice&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/adityakumar2358/salt-story-my-maasis-recipes-saved-in-her-own-voice-56g8" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Hacktoberfest: Maintainer Spotlight&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/adityakumar2358" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F4152822%2F9a5cf499-275d-4935-b473-c7ce914c5856.png" alt="adityakumar2358 profile" class="crayons-avatar__image" width="460" height="460"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/adityakumar2358" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Aditya Kumar
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Aditya Kumar
                
                
              
              &lt;div id="story-author-preview-content-4792488" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/adityakumar2358" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F4152822%2F9a5cf499-275d-4935-b473-c7ce914c5856.png" class="crayons-avatar__image" alt="" width="460" height="460"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Aditya Kumar&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/adityakumar2358/salt-story-my-maasis-recipes-saved-in-her-own-voice-56g8" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Oct 3&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/adityakumar2358/salt-story-my-maasis-recipes-saved-in-her-own-voice-56g8" id="article-link-4792488"&gt;
          Salt &amp;amp; Story: My Maasi's Recipes, Saved in Her Own Voice
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/weekendchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;weekendchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/hf26challenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;hf26challenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/hacktoberfest"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;hacktoberfest&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/adityakumar2358/salt-story-my-maasis-recipes-saved-in-her-own-voice-56g8" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;19&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/adityakumar2358/salt-story-my-maasis-recipes-saved-in-her-own-voice-56g8#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              2&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            9 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>Salt &amp; Story: My Maasi's Recipes, Saved in Her Own Voice</title>
      <dc:creator>Aditya Kumar</dc:creator>
      <pubDate>Sat, 03 Oct 2026 15:16:50 +0000</pubDate>
      <link>https://dev.to/adityakumar2358/salt-story-my-maasis-recipes-saved-in-her-own-voice-56g8</link>
      <guid>https://dev.to/adityakumar2358/salt-story-my-maasis-recipes-saved-in-her-own-voice-56g8</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;blockquote&gt;
&lt;p&gt;⭐ &lt;strong&gt;If this story means something to you, please star the repo:&lt;/strong&gt; &lt;a href="https://github.com/ADITYA-KUMAR-2358/salt-and-story" rel="noopener noreferrer"&gt;github.com/ADITYA-KUMAR-2358/salt-and-story&lt;/a&gt;. It helps more families find it.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;h3&gt;
  
  
  Who I built it for
&lt;/h3&gt;

&lt;p&gt;My &lt;strong&gt;Maasi&lt;/strong&gt; (my mom's sister, my aunt) has cancer. A few weeks ago we learned she probably has two to three years left.&lt;/p&gt;

&lt;p&gt;She makes the best food I know. Not fancy food: comforting, tasty, the kind you remember for the rest of your life.&lt;/p&gt;

&lt;p&gt;A few days back I saw her writing in her diary. When I asked, she told me it was her famous &lt;strong&gt;chili and lemon pickle&lt;/strong&gt; recipe. She had written a few others too, each with a lovely message and the name of the person it was for. My favourite thing she cooks is her &lt;strong&gt;Dahi Wada&lt;/strong&gt;, and guess what: there it was, a recipe addressed to me.&lt;/p&gt;

&lt;p&gt;She had spent hours writing those pages by hand. So I thought: what if she could just &lt;em&gt;talk&lt;/em&gt;, the way she does in the kitchen, and her recipe came out exactly in her words?&lt;/p&gt;

&lt;p&gt;That became &lt;strong&gt;Salt &amp;amp; Story&lt;/strong&gt;. Maasi has now recorded those recipes with her voice, and they are live, written the way she said them. I also added a way to turn them into a personalised book, and a lot more, because &lt;em&gt;every recipe has a story&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The problem it solves for her
&lt;/h3&gt;

&lt;p&gt;Writing recipes by hand is slow and tiring, and the way Maasi really cooks ("a pinch of this, cook it till it looks right") never fits neatly on a page anyway. Salt &amp;amp; Story lets her simply speak, and it keeps her exact words instead of flattening them into a generic recipe. For our family, it means her food and her voice stay with us.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it does
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Salt &amp;amp; Story&lt;/strong&gt; is a web app that turns spoken recipes into a printable family cookbook.&lt;/p&gt;

&lt;p&gt;You record a voice memo in the browser (or upload one, or paste the words), and Salt &amp;amp; Story:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;transcribes it,&lt;/li&gt;
&lt;li&gt;structures it into ingredients, steps and tips,&lt;/li&gt;
&lt;li&gt;turns vague measures like "a fistful" into rough quantities &lt;strong&gt;while keeping the original phrase right next to them&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;keeps one memorable line, &lt;strong&gt;verbatim&lt;/strong&gt;, as a pull-quote (checked against the transcript in code),&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;never invents&lt;/strong&gt; an ingredient, amount or step that wasn't said,&lt;/li&gt;
&lt;li&gt;exports everything as a designed A5 PDF cookbook.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal was never a recipe database. It was a book that sounds like Maasi.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's in it
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;What you can do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Capture&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Record in the browser with a live level meter, upload a memo (mp3, m4a, wav, webm, ogg), paste a transcript, or write a recipe by hand&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Recipe&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Read it with an ingredient checklist and tappable steps, edit everything (with an unsaved-changes guard), add a photo, keep the original transcript one tap away&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cook mode&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One step at a time in large type, the screen kept awake, arrow keys or big buttons&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Listen&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ElevenLabs narration of the whole recipe, cached so it is paid for once&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Book&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pick and order recipes, a live cover preview, a dedication, an editable "Recipes told by" line, and an A5 PDF with contents and page numbers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Organise&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Search, favourites, delete with confirmation, backup and restore as JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Accounts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sign in with Google; each family's recipes are private to their account; delete your account and everything in it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Start fast&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Six American and European family classics with openly licensed photos, added in one tap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Comfort&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Light and dark mode, 17px base text, 44px tap targets, keyboard and screen reader friendly, reduced-motion support&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;&lt;strong&gt;Live app:&lt;/strong&gt; &lt;a href="https://salt-and-story-web.onrender.com/" rel="noopener noreferrer"&gt;https://salt-and-story-web.onrender.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&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%2Fspfwzty8m25p9rscmgi6.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%2Fspfwzty8m25p9rscmgi6.png" alt="Salt &amp;amp; Story landing page with the tagline &amp;quot;Because Every Recipe Has A Story&amp;quot;, a deck of family food photos and handwritten-style quote cards" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&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%2Fauyje16v47xz95xp3ss0.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%2Fauyje16v47xz95xp3ss0.png" alt="A recipe page in Salt &amp;amp; Story showing the photo, a pull-quote in the cook's own words, an ingredient checklist and numbered steps" width="800" height="363"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&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%2Fimyr4o3y2ejshy5ticuo.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%2Fimyr4o3y2ejshy5ticuo.png" alt="Cook mode on a phone: a single recipe step in large type with big Previous and Next buttons" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&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%2Fh1o12s0lt1bda5doomqr.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%2Fh1o12s0lt1bda5doomqr.png" alt="A two-page spread from the printed A5 PDF cookbook: photo, title, story and the cook's words on the left; ingredients, method and tips on the right" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&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/ADITYA-KUMAR-2358" rel="noopener noreferrer"&gt;
        ADITYA-KUMAR-2358
      &lt;/a&gt; / &lt;a href="https://github.com/ADITYA-KUMAR-2358/salt-and-story" rel="noopener noreferrer"&gt;
        salt-and-story
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Salt &amp;amp; Story turns voice memos of a relative cooking into clean, printable recipes, while keeping the speaker's own words beside them. Record or upload a memo, an open-weight model (Gemma 4) writes it up, and you export a cookbook PDF that looks like a gift.  It is built for one real family: Because Every Recipe Has A Story
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Salt &amp;amp; Story&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Because Every Recipe Has A Story&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Salt &amp;amp; Story turns voice memos of a relative cooking into clean, printable recipes, while keeping the speaker's own words beside them. Record or upload a memo, an open-weight model (&lt;strong&gt;Gemma 4&lt;/strong&gt;) writes it up, and you export a cookbook PDF that looks like a gift.&lt;/p&gt;
&lt;p&gt;It is built for one real family: the person who tells recipes out loud and has never written them down, and the grandchild who wants to keep them.&lt;/p&gt;
&lt;p&gt;Built by &lt;strong&gt;Aditya Kumar&lt;/strong&gt; (&lt;a href="https://github.com/ADITYA-KUMAR-2358" rel="noopener noreferrer"&gt;@ADITYA-KUMAR-2358&lt;/a&gt;) for the DEV Hacktoberfest Weekend Challenge, "Build for a Friend".&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Agents and contributors: start with &lt;a href="https://github.com/ADITYA-KUMAR-2358/salt-and-story/docs/" rel="noopener noreferrer"&gt;&lt;code&gt;docs/&lt;/code&gt;&lt;/a&gt; (&lt;a href="https://github.com/ADITYA-KUMAR-2358/salt-and-story/docs/PRD.md" rel="noopener noreferrer"&gt;PRD&lt;/a&gt;, &lt;a href="https://github.com/ADITYA-KUMAR-2358/salt-and-story/docs/ARCHITECTURE.md" rel="noopener noreferrer"&gt;Architecture&lt;/a&gt;, &lt;a href="https://github.com/ADITYA-KUMAR-2358/salt-and-story/docs/RULES.md" rel="noopener noreferrer"&gt;Rules&lt;/a&gt;, &lt;a href="https://github.com/ADITYA-KUMAR-2358/salt-and-story/docs/DESIGN.md" rel="noopener noreferrer"&gt;Design&lt;/a&gt;, &lt;a href="https://github.com/ADITYA-KUMAR-2358/salt-and-story/docs/TASKS.md" rel="noopener noreferrer"&gt;Tasks&lt;/a&gt;, &lt;a href="https://github.com/ADITYA-KUMAR-2358/salt-and-story/docs/MEMORY.md" rel="noopener noreferrer"&gt;Memory&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What it does&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Capture&lt;/strong&gt;: record in the browser (live level meter), upload a memo, paste a transcript, or write a recipe by hand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write it up&lt;/strong&gt;: ElevenLabs…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ADITYA-KUMAR-2358/salt-and-story" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;⭐ A star on the repo would genuinely make my day.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Open-source AI at the core:&lt;/strong&gt; &lt;strong&gt;Gemma 4&lt;/strong&gt; (&lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt;, Google's open-weight model) structures every recipe. I call it through the Gemini API's OpenAI-compatible endpoint on the free tier, so the same code also runs against &lt;strong&gt;local Ollama&lt;/strong&gt; (for example &lt;code&gt;gemma3:4b&lt;/code&gt;) by changing three environment variables. The model turns a rambling transcript into structured JSON, and it is the heart of Salt &amp;amp; Story.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+--------------------------------------+
| BROWSER                              |
| React 19, Vite, TypeScript 7         |
| Tailwind v4, GSAP                    |
+--------------------------------------+
    |             |              |
    | app files   | JSON +       | Sign in
    |             | Bearer       | with Google
    v             v              v
+--------+  +-------------+  +----------+
| Static |  | FastAPI     |  | Google   |
| site   |  | Python 3.14 |  | Identity |
+--------+  +-------------+  +----------+
                   |
                   +--&amp;gt; SQLite: accounts, recipes
                   +--&amp;gt; Files: photos, audio
                   +--&amp;gt; ElevenLabs: STT + TTS
                   +--&amp;gt; Gemma 4: Gemini API
                   |             or Ollama
                   +--&amp;gt; WeasyPrint: HTML -&amp;gt; PDF

  Hosted on Render (or docker compose locally)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;Choice&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;React 19, Vite, TypeScript 7, Tailwind v4, GSAP&lt;/td&gt;
&lt;td&gt;Fast to build, strict types, a few deliberate animations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;FastAPI, Pydantic v2, SQLModel on Python 3.14&lt;/td&gt;
&lt;td&gt;Typed models end to end; background tasks for slow AI work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI writer&lt;/td&gt;
&lt;td&gt;Gemma 4 26B (A4B) via an OpenAI-compatible API&lt;/td&gt;
&lt;td&gt;Open weights, swappable host, free tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speech&lt;/td&gt;
&lt;td&gt;ElevenLabs Scribe (speech-to-text) and multilingual TTS&lt;/td&gt;
&lt;td&gt;Handles messy kitchen audio; natural narration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PDF&lt;/td&gt;
&lt;td&gt;WeasyPrint with Jinja2 templates&lt;/td&gt;
&lt;td&gt;Real print CSS: page counters, running headers, leaders&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accounts&lt;/td&gt;
&lt;td&gt;Google Identity Services + signed sessions&lt;/td&gt;
&lt;td&gt;No passwords to store&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hosting&lt;/td&gt;
&lt;td&gt;Render Blueprint: Docker web service + static site&lt;/td&gt;
&lt;td&gt;One &lt;code&gt;render.yaml&lt;/code&gt; describes both&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  From a voice memo to a recipe
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; Cook records or uploads a voice memo
        |
        v
 ElevenLabs Scribe ----&amp;gt; transcript
        |
        v
 Gemma 4 &amp;lt;---- rules: never invent,
        |             keep their words
        v
 recipe as JSON
        |
        v
 Pydantic check --bad JSON--&amp;gt; retry,
        |                     error fed back
        v
 Is the quote really in the transcript?
        |   no --&amp;gt; use closest real sentence
        v
 Ready to read, cook, edit and print
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The status moves &lt;code&gt;uploaded → transcribing → structuring → ready&lt;/code&gt; (or &lt;code&gt;failed&lt;/code&gt;, always with a reason and a next step). If the server restarts mid-memo, it marks that memo as interrupted instead of leaving a spinner forever.&lt;/p&gt;

&lt;h3&gt;
  
  
  Things I had to get right
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Not inventing things.&lt;/strong&gt; The prompt forbids adding ingredients or steps that weren't said, the JSON is validated with Pydantic, and bad output is retried with the validation error fed back. For Maasi's recipes this mattered more than anything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keeping her voice.&lt;/strong&gt; The pull-quote must be an exact substring of the transcript. The code checks this and falls back to the closest real sentence if the model paraphrases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swappable models.&lt;/strong&gt; The model endpoint is three environment variables, so the same code runs against local Ollama or a hosted open-weight model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A book that looks like a gift.&lt;/strong&gt; Each recipe is a two-page spread: photo, title, story and their words on the left; ingredients, method and tips on the right. Steps never split across pages, headings never strand at the bottom, and continuation pages carry the recipe name in a running header. I checked it by rendering real books and looking at every page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A free API key that strangers can't drain.&lt;/strong&gt; See the next section.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Protecting a free API key
&lt;/h3&gt;

&lt;p&gt;A public demo on free tiers needs guardrails, so every request passes through several layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; Sign in with Google
   |-- throwaway email domain?  --&amp;gt; refused
   |   (about 9,200 blocked)
   |-- 2+ new accounts from this
   |   network today?           --&amp;gt; refused
   v
 Ask for a recipe
   |-- account used its 5 today? --&amp;gt; try tomorrow
   |-- network used its 10?      --&amp;gt; refused
   |-- same transcript before?   --&amp;gt; reused, free
   v
 Throttle + queue (one call at a time)
   |-- 429 or 5xx --&amp;gt; wait, retry, then explain
   v
 Gemma 4 writes the recipe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Guard&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Recipes (or narrations) per account per day&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Fair share of the free quota&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New accounts per network per day&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Stops one device making many accounts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI requests per network per day&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Stops one device spending many accounts' quota&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Throwaway email domains refused&lt;/td&gt;
&lt;td&gt;about 9,200&lt;/td&gt;
&lt;td&gt;No disposable sign-ups&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Requests per account per 10 minutes&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Stops bursts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model calls per minute / per day (whole server)&lt;/td&gt;
&lt;td&gt;10 / 300&lt;/td&gt;
&lt;td&gt;Last line of defence for the key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Identical transcripts&lt;/td&gt;
&lt;td&gt;reused&lt;/td&gt;
&lt;td&gt;"Try a sample" costs nothing the second time&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Only real AI calls count against an account's 5: writing by hand, editing, photos, classics and books are free. IP addresses are stored only as salted hashes, and the visitor's IP is read from Cloudflare's &lt;code&gt;True-Client-IP&lt;/code&gt; header on Render, never from a header the client can fake.&lt;/p&gt;

&lt;h3&gt;
  
  
  Numbers
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Time to write one recipe, Gemma 4 default reasoning&lt;/td&gt;
&lt;td&gt;80 to 190 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same, with minimal thinking (&lt;code&gt;thinking_level: minimal&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;12 to 44 seconds&lt;/strong&gt; in most runs (one slow free-tier run took about 2 minutes)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend tests&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;83&lt;/strong&gt;, all mocked (no quota used)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend branch coverage&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;92%&lt;/strong&gt; (CI requires at least 90%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser checks against the Docker build&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;123&lt;/strong&gt;: every page, every link, the book PDF, a real Gemma recipe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Responsive audit&lt;/td&gt;
&lt;td&gt;14 pages at 5 widths (320 to 768px) plus 6 sizes up to 1920px: no text overflow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A six-recipe book&lt;/td&gt;
&lt;td&gt;19 A5 pages including cover, contents and closing page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python versions tested&lt;/td&gt;
&lt;td&gt;3.13 and 3.14&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Quality checks on every pull request
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; Pull request
   |
   +--&amp;gt; Lint + format (ruff, Oxlint) -----+
   |                                      |
   +--&amp;gt; Security (CodeQL, Gitleaks,       |
   |    pip-audit, npm audit) ------------+
   |                                      |
   +--&amp;gt; Tests (Py 3.13 + 3.14,            |
   |    coverage &amp;gt;= 90%) ---+             |
   |                        |             |
   +--&amp;gt; Type check + build -+             |
                            |             |
                            v             |
              Docker build + 123          |
              browser checks -------------+
                                          |
                                          v
                              All checks passed
                                          |
                                          v
                                   Ready to merge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dependabot keeps Python, npm, Docker images and GitHub Actions up to date, and every update goes through the same checks.&lt;/p&gt;

&lt;h3&gt;
  
  
  What was hard
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Speed.&lt;/strong&gt; Gemma 4 reasons before it answers, and my first recipes took up to three minutes. Passing a minimal thinking level brought that down to well under a minute with the same quality.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reasoning text in the output.&lt;/strong&gt; Gemma 4 prefixes its answer with a &lt;code&gt;&amp;lt;thought&amp;gt;&lt;/code&gt; block, which broke JSON parsing until I stripped it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free-tier limits.&lt;/strong&gt; 429s and the occasional 500 from the provider needed polite retries, a one-at-a-time queue and clear "try again in a minute" messages instead of crashes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The PDF engine everywhere.&lt;/strong&gt; WeasyPrint needs native libraries (Pango): easy in Docker and on Render, painful on Windows until I scripted a private install.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The real visitor IP.&lt;/strong&gt; Behind Render's proxy, the usual &lt;code&gt;X-Forwarded-For&lt;/code&gt; header can be faked by the client, so the per-network limits read Cloudflare's &lt;code&gt;True-Client-IP&lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tooling on the newest versions.&lt;/strong&gt; TypeScript 7 is so new that typescript-eslint doesn't support it yet, so I lint with Oxlint instead.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What I'd do next
&lt;/h3&gt;

&lt;p&gt;Hindi and Hinglish support (with a Devanagari PDF font), so Maasi's recipes can be printed in the language she actually speaks; shared family libraries so several relatives can add to one book; playback of the original voice memo, so we can always hear her say it; and a printed hardcover option.&lt;/p&gt;

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

&lt;p&gt;Salt &amp;amp; Story handles something deeply personal: a family member's voice and memories.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Control.&lt;/strong&gt; With an open-weight model, the structuring step can run on my own machine or server. In the hosted demo, audio goes to ElevenLabs for transcription and transcripts go to Google's Gemini API, which runs Gemma; switching &lt;code&gt;LLM_BASE_URL&lt;/code&gt; to local Ollama keeps transcripts on my own computer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swappability.&lt;/strong&gt; Because the model sits behind a standard endpoint, I can change models without rewriting the app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost.&lt;/strong&gt; It's free to run, on the free tier or locally, which matters when the "user" is a family member and not a customer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tunability.&lt;/strong&gt; I could shape the prompt and behaviour to protect what mattered most: faithfulness to what was actually said.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With a closed model, Maasi's words would only ever be processed wherever one company decided. With open weights, they can stay with our family.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma&lt;/strong&gt;: Gemma 4 structures every recipe, with its output validated and its quotes checked against the transcript.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Render&lt;/strong&gt;: Salt &amp;amp; Story is deployed on Render from a Blueprint: a Docker web service for the API and a static site for the app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of ElevenLabs&lt;/strong&gt;: speech-to-text turns voice memos into transcripts, and text-to-speech reads recipes aloud.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Somewhere in that app is a Dahi Wada recipe with my name on it, in Maasi's own words. That's the whole reason it exists.&lt;/p&gt;

&lt;p&gt;If you have someone whose recipes live only in their head, record them while you can. &lt;strong&gt;Try it:&lt;/strong&gt; &lt;a href="https://salt-and-story-web.onrender.com/" rel="noopener noreferrer"&gt;https://salt-and-story-web.onrender.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And if this story touched you, please ⭐ &lt;strong&gt;&lt;a href="https://github.com/ADITYA-KUMAR-2358/salt-and-story" rel="noopener noreferrer"&gt;star Salt &amp;amp; Story on GitHub&lt;/a&gt;&lt;/strong&gt;. Thank you for reading. ❤️&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>hf26challenge</category>
      <category>hacktoberfest</category>
    </item>
  </channel>
</rss>
