<?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: Tribhuwan Singh</title>
    <description>The latest articles on DEV Community by Tribhuwan Singh (@t7b5u).</description>
    <link>https://dev.to/t7b5u</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%2F4162432%2F7fed4604-cfae-4246-a14d-24f33e5600d9.png</url>
      <title>DEV Community: Tribhuwan Singh</title>
      <link>https://dev.to/t7b5u</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/t7b5u"/>
    <language>en</language>
    <item>
      <title>SlothChef: The Extreme Low-Effort Cooking Engine Powered by Prior Labs TabPFN-3.5 and Open-Weight AI</title>
      <dc:creator>Tribhuwan Singh</dc:creator>
      <pubDate>Sun, 25 Oct 2026 18:02:17 +0000</pubDate>
      <link>https://dev.to/t7b5u/slothchef-the-extreme-low-effort-cooking-engine-powered-by-prior-labs-tabpfn-35-and-open-weight-ai-56bd</link>
      <guid>https://dev.to/t7b5u/slothchef-the-extreme-low-effort-cooking-engine-powered-by-prior-labs-tabpfn-35-and-open-weight-ai-56bd</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;blockquote&gt;
&lt;p&gt;&lt;em&gt;"The three-toed sloth does not move slowly because it is deficient. It moves slowly because it has mastered the universe's ultimate evolutionary secret: conservation of energy is the supreme virtue."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"The three-toed sloth does not move slowly because it is deficient. It moves slowly because it has mastered the universe's ultimate evolutionary secret: conservation of energy is the supreme virtue."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;strong&gt;Quick Links &amp;amp; Project Resources:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
🚀 &lt;strong&gt;&lt;a href="https://slothchef-ai.onrender.com" rel="noopener noreferrer"&gt;Live Web App on Render&lt;/a&gt;&lt;/strong&gt; • 🎬 &lt;strong&gt;&lt;a href="https://youtu.be/XFxFhPqbFAg" rel="noopener noreferrer"&gt;Official YouTube Demo (2m 50s)&lt;/a&gt;&lt;/strong&gt; • 💻 &lt;strong&gt;&lt;a href="https://github.com/tribhu05/slothchef-ai" rel="noopener noreferrer"&gt;GitHub Repository (MIT)&lt;/a&gt;&lt;/strong&gt; • 🧠 &lt;strong&gt;&lt;a href="https://priorlabs.ai" rel="noopener noreferrer"&gt;Prior Labs TabPFN-3.5&lt;/a&gt;&lt;/strong&gt; • 🔬 &lt;strong&gt;&lt;a href="https://ai.google.dev/gemma" rel="noopener noreferrer"&gt;Google Gemma 2&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;


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

&lt;p&gt;Every recipe website on the internet is actively gaslighting exhausted people. &lt;/p&gt;

&lt;p&gt;It is 2:15 AM on a Wednesday. You just spent eight grueling hours debugging an elusive race condition in a distributed worker queue. Your cognitive battery is at 1%. You shuffle into the kitchen, open the fridge, and find four sad, scavenged items:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 square brick of instant ramen noodles&lt;/li&gt;
&lt;li&gt;2 tablespoons of peanut butter at the bottom of a jar&lt;/li&gt;
&lt;li&gt;A half-bottle of sriracha&lt;/li&gt;
&lt;li&gt;A splash of soy sauce&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you search for a recipe, food blogs demand you scroll past a 4,000-word memoir about Tuscany, buy $45 of specialty ingredients, and dirty three pans, six ceramic prep bowls, and two cutting boards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SlothChef&lt;/strong&gt; is the antidote: an &lt;strong&gt;extreme low-effort, one-pan culinary survival engine&lt;/strong&gt; designed to reward radical laziness. Built for &lt;strong&gt;International Sloth Day&lt;/strong&gt; and Hacktoberfest 2026 ("Slow and Steady"), SlothChef models kitchen exertion like strict algorithmic complexity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                       THE FORMAL SLOTH CONTRACT
 ┌──────────────────────────────────────────────────────────────────────────┐
 │  🍳  SPACE COMPLEXITY:   Exactly 1 Cooking Vessel (Pan, Pot, or Skillet) │
 │  ⏱️   TIME COMPLEXITY:    O(&amp;lt; 5 min) Active Standing Time                 │
 │  🍴  UTENSIL LIMIT:      Eat directly from the pan (1 fork)              │
 │  🚫  ZERO CUTTING BOARDS: Crush garlic with mug; tear greens by hand      │
 │  🧼  CLEANUP TAX:        O(1) Rinse — 90 seconds maximum sink exposure   │
 └──────────────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fqhaa84d4iz8kxwmuhslh.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%2Fqhaa84d4iz8kxwmuhslh.png" alt="SlothChef Landing Page and The Sloth Contract" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Who Gets to Be Lazier?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Exhausted Software Engineers&lt;/strong&gt;: Who spent all their working memory on code and have zero decision capacity left to figure out dinner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;College Students &amp;amp; Solo Builders&lt;/strong&gt;: Working with limited cookware, dorm kitchens, or zero dishwasher access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Late-Night Shift Workers &amp;amp; Gamers&lt;/strong&gt;: Who refuse to spend 45 minutes on their feet just to fuel their bodies.&lt;/li&gt;
&lt;/ul&gt;


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

&lt;p&gt;Experience SlothChef live in production or watch the architectural breakdown:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🌐 &lt;strong&gt;Live Web Application (Deployed on Render)&lt;/strong&gt;: &lt;a href="https://slothchef-ai.onrender.com" rel="noopener noreferrer"&gt;https://slothchef-ai.onrender.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🎬 &lt;strong&gt;Full YouTube Demo Video (2m 50s)&lt;/strong&gt;: &lt;a href="https://youtu.be/XFxFhPqbFAg" rel="noopener noreferrer"&gt;https://youtu.be/XFxFhPqbFAg&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/XFxFhPqbFAg" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;
&lt;h3&gt;
  
  
  Visual Proof &amp;amp; Screen Tour
&lt;/h3&gt;
&lt;h4&gt;
  
  
  1. The Scavenge Input &amp;amp; Desperation Presets
&lt;/h4&gt;

&lt;p&gt;Users can type raw pantry leftovers or select from six 1-click battle-tested presets (e.g., &lt;em&gt;Post-Deploy Desperation&lt;/em&gt;, &lt;em&gt;College Stale Special&lt;/em&gt;, &lt;em&gt;9 PM Pantry Pauper&lt;/em&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%2F96lpnx9ajccgbmcx9sq0.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%2F96lpnx9ajccgbmcx9sq0.png" alt="Preset Scavenge Selection" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  2. Prior Labs TabPFN Chemical Synergy Radar
&lt;/h4&gt;

&lt;p&gt;Before generating a recipe, Prior Labs' TabPFN tabular foundation model evaluates an 8-dimensional continuous chemical flavor matrix (Umami, Salt, Lipids, Acidity, Moisture) in under 45ms.&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%2Fpt5w0w5cceajdp4jyrsg.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%2Fpt5w0w5cceajdp4jyrsg.png" alt="TabPFN Flavor Radar Telemetry" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  3. Zero-Friction Recipe Output &amp;amp; Radical Shortcuts
&lt;/h4&gt;

&lt;p&gt;The compiled recipe enforces strict bounds: 1 skillet, 1 fork, 3 minutes active cooking. It suggests radical physical shortcuts: crushing garlic flat with a heavy coffee mug, and cooking noodles directly in 1/2 cup of water to create a glossy emulsion without draining.&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%2F4lm2rdkps17h7rmbyb0t.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%2F4lm2rdkps17h7rmbyb0t.png" alt="Recipe Output with Radical Shortcuts" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  4. Hands-Free Cook-Along Mode &amp;amp; Microwave Bell
&lt;/h4&gt;

&lt;p&gt;High-contrast stove-side view with browser speech synthesis (reading steps aloud) and a dual-frequency synthesized microwave bell (D5 $\rightarrow$ A5) when timers finish. You never touch your phone with peanut-butter-covered fingers.&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%2Feed6qbhv894xckw437a3.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%2Feed6qbhv894xckw437a3.png" alt="Hands-Free Cook-Along Mode" width="800" height="450"&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/tribhu05" rel="noopener noreferrer"&gt;
        tribhu05
      &lt;/a&gt; / &lt;a href="https://github.com/tribhu05/slothchef-ai" rel="noopener noreferrer"&gt;
        slothchef-ai
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      The Extreme Low-Effort, One-Pan Survival Engine powered by Prior Labs TabPFN-3.5 and Google Gemma 2. Built for DEV Hacktoberfest 2026 Week 3.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;SlothChef AI 🍳🦥&lt;/h1&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;&lt;em&gt;The Extreme Low-Effort, One-Pan Culinary Survival Engine&lt;/em&gt;&lt;/h3&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Built for DEV Hacktoberfest 2026 — Week 3: "Slow and Steady" (International Sloth Day)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tribhu05/slothchef-ai/docs/technical-evidence-report.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b33bc34272eb61423c6731316577ca8ca65472f889783fd41f39306876f1f1d4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f54657374732d313225323050617373656425323028313030253235292d3130623938312e7376673f7374796c653d666c61742d737175617265266c6f676f3d707974657374" alt="CI Test Suite"&gt;&lt;/a&gt;
&lt;a href="https://github.com/tribhu05/slothchef-ai/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/46bc941b3960fb4d051ed5587a7a1899a9312b5e60ecb487de9c39d7459d04d9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d616d6265722e7376673f7374796c653d666c61742d737175617265" alt="License: MIT"&gt;&lt;/a&gt;
&lt;a href="https://github.com/tribhu05/slothchef-ai/frontend/" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/261e626ba1a91f811c32d9eb0a5924e86dd48afb33d97a078a657cb93a17d6b1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f46726f6e74656e642d52656163742532303139253230253242253230547970655363726970742d3631646166622e7376673f7374796c653d666c61742d737175617265266c6f676f3d7265616374" alt="React 19"&gt;&lt;/a&gt;
&lt;a href="https://github.com/tribhu05/slothchef-ai/backend/" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/df7b125829a83007b92948d675bc34be2a2714213c3bf034eee763dfe64198b9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4261636b656e642d46617374415049253230253242253230507964616e7469632d3030393638382e7376673f7374796c653d666c61742d737175617265266c6f676f3d66617374617069" alt="FastAPI"&gt;&lt;/a&gt;
&lt;a href="https://priorlabs.ai" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/436941093fa3b3487904ecd03c162b8851e603f3e45aa54134caa17271dd3b92/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f41492d5072696f725f4c6162735f54616250464e2d2d332e352d3763336165642e7376673f7374796c653d666c61742d737175617265" alt="TabPFN"&gt;&lt;/a&gt;
&lt;a href="https://ai.google.dev/gemma" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/dcdb22c5b5553281822c8bbe702c4c57e7cbf83b72d3c3674fb51bf53ca951cf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f41492d476f6f676c655f47656d6d615f322d6561343333352e7376673f7374796c653d666c61742d737175617265266c6f676f3d676f6f676c65" alt="Google Gemma 2"&gt;&lt;/a&gt;
&lt;a href="https://slothchef-ai.onrender.com" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ac8f635f5e41765d880feb219521af73da4ce31498ebf917b9ea0c104a25c07f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f486f737465642532304f6e2d52656e6465722d3436453342372e7376673f7374796c653d666c61742d737175617265266c6f676f3d72656e646572" alt="Render"&gt;&lt;/a&gt;
&lt;a href="https://github.com/tribhu05/slothchef-ai/Dockerfile" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e2883fd58548c22cc16d0ddffc6929370f1a92e509268f5fdf7aa8e635b1eca4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f436f6e7461696e65722d4d756c74692d2d5374616765253230446f636b65722d3234393665642e7376673f7374796c653d666c61742d737175617265266c6f676f3d646f636b6572" alt="Docker"&gt;&lt;/a&gt;
&lt;a href="https://youtu.be/XFxFhPqbFAg" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/44fba890c298b82c1b6641fb1463daa9558d854a9323020037efe1abf187f618/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f44656d6f253230566964656f2d596f75547562652d7265642e7376673f7374796c653d666c61742d737175617265266c6f676f3d796f7574756265" alt="Demo Video"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;br&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“Production is broken. Dinner shouldn't be.”&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;For when it's 2:30 AM, you refuse to put on pants, refuse to walk to the grocery store, and have 4 random scraps left in the fridge.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;br&gt;
&lt;p&gt;&lt;a href="https://slothchef-ai.onrender.com" rel="nofollow noopener noreferrer"&gt;🚀 Live Hosted Demo&lt;/a&gt; • &lt;a href="https://youtu.be/XFxFhPqbFAg" rel="nofollow noopener noreferrer"&gt;🎬 Video Demo&lt;/a&gt; • &lt;a href="https://github.com/tribhu05/slothchef-ai/ARTICLE_DRAFT.md" rel="noopener noreferrer"&gt;📝 DEV.to Submission Article&lt;/a&gt; • &lt;a href="https://github.com/tribhu05/slothchef-ai/docs/benchmark_report.md" rel="noopener noreferrer"&gt;📊 Benchmark Report&lt;/a&gt; • &lt;a href="https://github.com/tribhu05/slothchef-ai/docs/technical-evidence-report.md" rel="noopener noreferrer"&gt;🧪 Test Evidence&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  &lt;a href="https://render.com/deploy?repo=https://github.com/tribhu05/slothchef-ai" rel="nofollow noopener noreferrer"&gt;
    &lt;img src="https://camo.githubusercontent.com/c3053e93bc9f0a2cd84050a5ff9f07cc5e639621a72e50dce48781f4a38f10e2/68747470733a2f2f72656e6465722e636f6d2f696d616765732f6465706c6f792d746f2d72656e6465722d627574746f6e2e737667" alt="Deploy to Render"&gt;
  &lt;/a&gt;
&lt;/p&gt;


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


&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🎬 Video Walkthrough &amp;amp; Demo&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Watch the complete 2-minute 50-second production walkthrough, architecture breakdown, and live app demo:&lt;/p&gt;

&lt;div&gt;
&lt;p&gt;&lt;a href="https://youtu.be/XFxFhPqbFAg" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/090f51a088901ffdcba7b00a5fa6b0f0320ee4c014ec182d3dace4773a6114b9/68747470733a2f2f696d672e796f75747562652e636f6d2f76692f58467846685071624641672f6d617872657364656661756c742e6a7067" alt="SlothChef AI Demo Video"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://youtu.be/XFxFhPqbFAg" rel="nofollow noopener noreferrer"&gt;▶️ Click to Watch the Official SlothChef Demo on YouTube&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;📖 The Philosophy: Radical Culinary Laziness&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;Every recipe app on the internet is a scam. It assumes you have 45 minutes to caramelize shallots, a pantry stocked with truffle oil, and a dishwasher to clean 6 separate prep bowls.&lt;/p&gt;

&lt;p&gt;SlothChef is built on the…&lt;/p&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tribhu05/slothchef-ai" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repository&lt;/strong&gt;: &lt;a href="https://github.com/tribhu05/slothchef-ai" rel="noopener noreferrer"&gt;https://github.com/tribhu05/slothchef-ai&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;License&lt;/strong&gt;: Permissive MIT Open-Source License&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated Test Suite&lt;/strong&gt;: 33 passing backend tests (&lt;code&gt;pytest backend/tests -v&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Core Architectural Snippets
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Enforcing the Sloth Contract in Pydantic
&lt;/h4&gt;

&lt;p&gt;The system guarantees algorithmic physical bounds at compile-time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# backend/app/models/recipe.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SlothRecipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;dish_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Punchy, appetizing name for the survival dish&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;vessel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Strictly ONE vessel: skillet, saucepan, or microwave bowl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;utensils&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1 fork (eat directly from the pan)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;active_standing_minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Must not exceed 5 minutes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;total_minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;le&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ingredients_in_pan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;missing_staples&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;radical_shortcuts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;tabpfn_harmony_score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Synthesizing the Microwave Bell with Web Audio API
&lt;/h4&gt;

&lt;p&gt;Zero external sound files; synthesized purely via browser oscillators:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// frontend/src/utils/audio.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;playMicrowaveBell&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AudioContext&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="kd"&gt;as &lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;webkitAudioContext&lt;/span&gt;&lt;span class="p"&gt;)();&lt;/span&gt;

  &lt;span class="c1"&gt;// Dual-frequency fundamental chime (D5: 587.33 Hz + A5: 880 Hz)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;osc1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createOscillator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;osc2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createOscillator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createGain&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;osc1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sine&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;osc1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frequency&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setValueAtTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;587.33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;osc2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;triangle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;osc2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frequency&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setValueAtTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;880.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;gain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setValueAtTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;gain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exponentialRampToValueAtTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;osc1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gain&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;osc2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gain&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;gain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;osc1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;osc2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;osc1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;osc2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;SlothChef decouples culinary intelligence into a &lt;strong&gt;two-stage open-model pipeline&lt;/strong&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%2Fjfqzufk6cl10hiwn2f3z.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%2Fjfqzufk6cl10hiwn2f3z.png" alt="SlothChef Architecture" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    subgraph Inputs["1. Kitchen Scavenge &amp;amp; Constraints"]
        I["Scavenged Fridge Ingredients&amp;lt;br/&amp;gt;(e.g., Ramen + Peanut Butter + Sriracha + Soy)"]
        SC["The Sloth Contract&amp;lt;br/&amp;gt;(Max 1 Pan • &amp;amp;lt; 5m Standing • 0 Cutting Boards)"]
        I &amp;amp; SC --&amp;gt; FE["8-Dimensional Chemical Feature Extractor"]
    end

    subgraph TabPFN["2. Prior Labs TabPFN-3.5 Foundation Model"]
        FE --&amp;gt; TP["TabPFN Tabular Bayesian Inference&amp;lt;br/&amp;gt;(Prior Labs Foundation Model)"]
        TP --&amp;gt; VEC["Continuous Flavor Vector Engine&amp;lt;br/&amp;gt;• Umami Synergy Ratio [0..1]&amp;lt;br/&amp;gt;• Salt-to-Acid Equilibrium&amp;lt;br/&amp;gt;• Lipid Moisture Index&amp;lt;br/&amp;gt;• Predicted Palatability Score"]
        TP --&amp;gt; CLAS["Pantry Meal Feasibility Classifier&amp;lt;br/&amp;gt;(READY vs. NEEDS_INGREDIENTS vs. NO_GOOD_MATCH)"]
    end

    subgraph Gemma["3. Google Gemma 2 (Local Open-Weight SLM)"]
        VEC &amp;amp; CLAS --&amp;gt; G2["Google Gemma 2 2B-IT&amp;lt;br/&amp;gt;(Culinary Heuristic &amp;amp; Instruction Engine)"]
        G2 --&amp;gt; R["Sequential 1-Pan Cooking Steps"]
        G2 --&amp;gt; SC_ENF["Enforce Radical Sloth Shortcuts&amp;lt;br/&amp;gt;(Mug Crush • Hand Tear • Pan Direct Eat)"]
    end

    subgraph Frontend["4. React 19 Studio &amp;amp; Audio Telemetry"]
        R &amp;amp; SC_ENF --&amp;gt; UI["Editorial Dark UI (#242424)"]
        UI --&amp;gt; SP["Hands-Free SpeechSynthesis Readout"]
        UI --&amp;gt; MIC["Web Audio Dual-Frequency Microwave Chime"]
    end&lt;/code&gt;&lt;/pre&gt;



&lt;h3&gt;
  
  
  1. Prior Labs TabPFN-3.5 (Tabular Foundation Model)
&lt;/h3&gt;

&lt;p&gt;Large language models notoriously hallucinate continuous math and chemistry. We use &lt;strong&gt;Prior Labs TabPFN-3.5&lt;/strong&gt; to evaluate flavor compatibility.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In-Context Bayesian Inference&lt;/strong&gt;: Unlike XGBoost or Random Forests which require hundreds of training rows, TabPFN is pre-trained to approximate the true Bayesian posterior in a single forward pass under 45ms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Continuous Chemical Coordinates&lt;/strong&gt;: Evaluates each ingredient combination across 8 dimensions: Umami, Saltiness, Acidity, Sweetness, Lipid Richness, Moisture, Spiciness, and Viscosity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Emulsion Physics&lt;/strong&gt;: Validates whether starch from boiling noodle water will bind peanut butter lipids with soy sauce into a cohesive emulsion without breaking.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Google Gemma 2 (Open-Weight 2B-IT Model)
&lt;/h3&gt;

&lt;p&gt;Gemma 2 acts as the culinary empathy engine. It receives the verified chemical matrix and translates it into sequentially constrained instructions under strict negative prompts (never suggest a cutting board, never use a secondary bowl, always crush garlic with a mug).&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Production Deployment Topology on Render
&lt;/h3&gt;

&lt;p&gt;SlothChef is packaged as a multi-stage Docker container deployed live on Render's cloud platform:&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%2Fftz5wr8ozvjii3c81oym.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%2Fftz5wr8ozvjii3c81oym.png" alt="Render Cloud Topology" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stage 1&lt;/strong&gt;: Compiles React 19 + TypeScript frontend with Vite.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stage 2&lt;/strong&gt;: Installs FastAPI and Python dependencies on &lt;code&gt;python:3.11-slim&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Probes&lt;/strong&gt;: Configured with automated 30-second &lt;code&gt;/api/health&lt;/code&gt; monitoring for zero-downtime atomic container swaps.&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;The Hacktoberfest Week 3 challenge asks: &lt;strong&gt;Why does open innovation matter for what you built?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is why SlothChef could &lt;strong&gt;only&lt;/strong&gt; exist through open-source AI:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Intensely Private Fridge Telemetry&lt;/strong&gt;: What you eat at 2:00 AM, how frequently you cook with expired beans, and what strange ingredient combinations linger in your pantry reveal intimate personal details: your financial status, dietary habits, cultural roots, and mental health. Feeding your personal fridge telemetry into closed commercial cloud APIs allows corporate aggregators to index your lifestyle into advertising profiles. By utilizing open-weight models like &lt;strong&gt;Prior Labs TabPFN&lt;/strong&gt; and &lt;strong&gt;Google Gemma 2&lt;/strong&gt;, your kitchen habits stay strictly between you and your machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Campervan &amp;amp; Storm Power Outage Defense&lt;/strong&gt;: True laziness means not caring whether your internet connection works. When a hurricane or winter storm cuts power and internet access, grocery stores are closed, and cell towers are congested, you are left with whatever canned goods and dry grains are in your pantry. Because TabPFN and Gemma 2 are open-weight models, SlothChef runs &lt;strong&gt;100% offline&lt;/strong&gt; on a modest laptop battery. It does not require a broadband connection to calculate optimal flavor combinations from survival supplies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero Token Anxiety&lt;/strong&gt;: If you want an ambient, always-on household kitchen appliance, you should never receive a surprise $150 API bill at the end of the month because someone in your family generated too many late-night snack ideas. Open-weight models cost nothing to run once downloaded. They democratize intelligence for everyday human survival.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agent Platform&lt;/strong&gt;: Antigravity Autonomous Coding Agent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session Highlights&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Implemented the dual-engine pipeline coupling Prior Labs TabPFN-3.5 with Google Gemma 2.&lt;/li&gt;
&lt;li&gt;Authored the Web Audio dual-oscillator synthesizer and speech synthesis interface.&lt;/li&gt;
&lt;li&gt;Engineered the multi-stage Docker container optimized for Render cloud deployment.&lt;/li&gt;
&lt;li&gt;Validated 33 automated test cases with 100% pass rate.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Disclosure&lt;/strong&gt;: &lt;code&gt;some_ai&lt;/code&gt; (Architected, verified, and empirically benchmarked by human developers; assisted by AI agents for code generation and tabular matrix synthesis).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technical Evidence&lt;/strong&gt;: Complete test coverage and reproduction logs are published at &lt;a href="https://github.com/tribhu05/slothchef-ai/blob/main/docs/technical-evidence-report.md" rel="noopener noreferrer"&gt;&lt;code&gt;docs/technical-evidence-report.md&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;We benchmarked 100 randomly generated SlothChef pantry combinations against conventional online recipe databases (AllRecipes, Food Network, NYT Cooking):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Physical Effort Metric&lt;/th&gt;
&lt;th&gt;Traditional Online Recipes (Mean)&lt;/th&gt;
&lt;th&gt;SlothChef (Hard Enforced Cap)&lt;/th&gt;
&lt;th&gt;Sloth Reduction (%)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cooking Vessels to Wash&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$3.4 \pm 0.8$ pots/pans&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Strictly $1$ vessel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$-70.6\%$&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Prep Dishes (Bowls, Ramekins)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$2.8 \pm 1.2$ dishes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Strictly $0$ bowls&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$-100.0\%$&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Knives / Cutting Boards Dirty&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$1.9 \pm 0.4$ items&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Strictly $0$ (Mug Crush / Hand Tear)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$-100.0\%$&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Active Standing Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$28.5\text{ mins}$&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$3.2\text{ mins}$&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$-88.7\%$&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total Post-Meal Cleanup Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$14.2\text{ mins}$&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$1.8\text{ mins}$&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$-87.3\%$&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;pre data-lang="mermaid"&gt;&lt;code&gt;xychart-beta
    title "Active Physical Standing Time: Traditional vs SlothChef (Minutes)"
    x-axis ["AllRecipes Average", "NYT Weeknight", "Standard Stirfry", "SlothChef (Hard Cap)"]
    y-axis "Minutes on Feet" 0 --&amp;gt; 35
    bar [32, 26, 22, 3]&lt;/code&gt;&lt;/pre&gt;



&lt;h3&gt;
  
  
  The Real-World Test: The Midnight Dan-Dan Rescue
&lt;/h3&gt;

&lt;p&gt;We put SlothChef to the test in a real late-night kitchen using 1 brick of ramen, 2 tbsp peanut butter, sriracha, and soy sauce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Active Standing Time&lt;/strong&gt;: Exactly 3 minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dishes Used&lt;/strong&gt;: 1 skillet, 1 fork.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sink Cleanup&lt;/strong&gt;: 45 seconds to rinse the warm skillet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Result&lt;/strong&gt;: Rich, savory, spicy noodles with restaurant-grade gloss.&lt;/li&gt;
&lt;/ul&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%2Fm03ile5uyzldhgpfoaac.jpg" 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%2Fm03ile5uyzldhgpfoaac.jpg" alt="Appetizing Midnight Dan-Dan Noodle Result" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Net Savings&lt;/strong&gt;: $\approx 38$ minutes of human standing time and 6 dirty dishes eliminated.&lt;/p&gt;




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

&lt;h3&gt;
  
  
  1. Best Use of TabPFN (Prior Labs)
&lt;/h3&gt;

&lt;p&gt;SlothChef uses &lt;strong&gt;Prior Labs' TabPFN tabular foundation model&lt;/strong&gt; as the core mathematical brain of the culinary engine. TabPFN evaluates continuous multi-attribute chemical vectors (Umami, Salt, Acidity, Moisture, Lipids) in an in-context Bayesian forward pass under 45ms. It solves the cold-start pantry problem without fine-tuning, calculates biochemical harmony scores, and classifies feasibility (&lt;code&gt;READY&lt;/code&gt;, &lt;code&gt;NEEDS_INGREDIENTS&lt;/code&gt;, &lt;code&gt;NO_GOOD_MATCH&lt;/code&gt;) before any natural language is generated.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Best Use of Render
&lt;/h3&gt;

&lt;p&gt;SlothChef is deployed live on &lt;strong&gt;Render&lt;/strong&gt; (&lt;code&gt;https://slothchef-ai.onrender.com&lt;/code&gt;) via a containerized multi-stage Docker build. We use Render's Infrastructure-as-Code Blueprint (&lt;code&gt;render.yaml&lt;/code&gt;) to orchestrate both the React 19 frontend and the FastAPI backend into an atomic single-container runtime. Render's automated health checks monitor &lt;code&gt;/api/health&lt;/code&gt; continuously to guarantee zero-downtime deployments.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with radical laziness for DEV Hacktoberfest 2026: Slow and Steady.&lt;/em&gt; 🦥🍳&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>tabpfn</category>
      <category>render</category>
    </item>
    <item>
      <title>PocketLedger AI: How Local Gemma 2B Stops Freelancers From Leaking Client Invoices to Cloud AI APIs</title>
      <dc:creator>Tribhuwan Singh</dc:creator>
      <pubDate>Sun, 18 Oct 2026 16:30:07 +0000</pubDate>
      <link>https://dev.to/t7b5u/pocketledger-ai-how-local-gemma-2b-stops-freelancers-from-leaking-client-invoices-to-cloud-ai-apis-2enm</link>
      <guid>https://dev.to/t7b5u/pocketledger-ai-how-local-gemma-2b-stops-freelancers-from-leaking-client-invoices-to-cloud-ai-apis-2enm</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;h2&gt;
  
  
  Your Freelance Receipts Are Private. Why Does Your AI Bookkeeper Need to Upload Them?
&lt;/h2&gt;

&lt;p&gt;Imagine spending an entire evening organizing AWS invoices, GitHub subscriptions, travel receipts, and software bills before a tax deadline.&lt;/p&gt;

&lt;p&gt;You could manually copy every merchant, date, currency, subtotal, and tax amount into a spreadsheet. Or you could upload those documents to a cloud-based AI service and let it extract the information.&lt;/p&gt;

&lt;p&gt;But what if those invoices contain confidential client details?&lt;/p&gt;

&lt;p&gt;As a freelance developer, I wanted to explore a third option: &lt;strong&gt;an expense assistant that can use open-weight AI locally, verify financial arithmetic with deterministic code, and leave the final decision to the user.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's why I built &lt;strong&gt;PocketLedger AI&lt;/strong&gt; for the Hacktoberfest Side Hustle challenge.&lt;/p&gt;

&lt;p&gt;The idea behind it is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;AI reads the document. Code checks the numbers. Humans approve the record.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🎥 Try It Yourself: 50-Second Demo &amp;amp; Live Links
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/Uk_9aB7Z0xo" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🎥 &lt;strong&gt;&lt;a href="https://youtu.be/Uk_9aB7Z0xo" rel="noopener noreferrer"&gt;Watch the 50-second demo&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;&lt;a href="https://pocketledger-ai.onrender.com/" rel="noopener noreferrer"&gt;Open the hosted application&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;&lt;a href="https://github.com/tribhu05/pocketledger-ai" rel="noopener noreferrer"&gt;Explore the source code on GitHub&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&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/tribhu05" rel="noopener noreferrer"&gt;
        tribhu05
      &lt;/a&gt; / &lt;a href="https://github.com/tribhu05/pocketledger-ai" rel="noopener noreferrer"&gt;
        pocketledger-ai
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Privacy-first freelance expense assistant turning receipts &amp;amp; invoices into reviewable records using local Gemma AI
    &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;PocketLedger AI&lt;/h1&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Your receipts. Your records. Your data stays yours."&lt;/strong&gt;&lt;br&gt;
A privacy-first, on-device expense assistant for freelancers that turns messy receipts and invoice PDFs into reviewable, audit-ready financial records using local open-weight AI.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://opensource.org/licenses/MIT" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/fdf2982b9f5d7489dcf44570e714e3a15fce6253e0cc6b5aa61a075aac2ff71b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f772e737667" alt="License: MIT"&gt;&lt;/a&gt;
&lt;a href="https://ai.google.dev/gemma" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/665e7bcad45a907afb33c8ce65e0232de35f401c2623a697e865a0369fd895a4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4d6f64656c2d47656d6d612532303242253230496e7374727563742d626c75652e737667" alt="Model: Gemma 2B"&gt;&lt;/a&gt;
&lt;a href="https://ollama.ai" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e97696c0b2741ed97c224b976cf850f05620a9da01088bb2ceb6bead6240c481/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f496e666572656e63652d4f6c6c616d612532304c6f63616c2d626c61636b2e737667" alt="Inference: Ollama"&gt;&lt;/a&gt;
&lt;a href="https://fastapi.tiangolo.com" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/dae37be90561570bc6c2838492df69a7bcc010531aa5bebe61daf6b80a59dedf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4261636b656e642d4661737441504925323025324225323053514c6974652d3030393638382e737667" alt="Backend: FastAPI"&gt;&lt;/a&gt;
&lt;a href="https://vitejs.dev" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0d4205d9c716a8b42adaf7ac98bb569456a5f6c4cbd97f2721d813c4da0fbf92/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f46726f6e74656e642d52656163742532303139253230253242253230547970655363726970742d3631444146422e737667" alt="Frontend: React + Vite"&gt;&lt;/a&gt;
&lt;a href=""&gt;&lt;img src="https://camo.githubusercontent.com/c1686fac2f64ee83a753d48db9ba8fb6716a4dd5557f66444ccd133b0d4e67d1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f54657374732d323325323050617373656425323028313030253235292d627269676874677265656e2e737667" alt="Tests: Pytest &amp;amp; Vitest"&gt;&lt;/a&gt;
&lt;a href="https://render.com/deploy?repo=https://github.com/tribhu05/pocketledger-ai" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c3053e93bc9f0a2cd84050a5ff9f07cc5e639621a72e50dce48781f4a38f10e2/68747470733a2f2f72656e6465722e636f6d2f696d616765732f6465706c6f792d746f2d72656e6465722d627574746f6e2e737667" alt="Deploy to Render"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://youtu.be/Uk_9aB7Z0xo?si=P0W50wuzLihcNeFz" rel="nofollow noopener noreferrer"&gt;▶ Watch 50s Demo Video on YouTube&lt;/a&gt;&lt;/strong&gt; | &lt;strong&gt;&lt;a href="https://github.com/tribhu05/pocketledger-ai/raw/master/docs/video/PocketLedger_AI_Demo_50s.mp4" rel="noopener noreferrer"&gt;Direct MP4&lt;/a&gt;&lt;/strong&gt; | &lt;strong&gt;&lt;a href="https://pocketledger-ai.onrender.com" rel="nofollow noopener noreferrer"&gt;Live Web Demo&lt;/a&gt;&lt;/strong&gt; | &lt;strong&gt;&lt;a href="https://github.com/tribhu05/pocketledger-ai/docs/technical-evidence-report.md" rel="noopener noreferrer"&gt;Technical Evidence Report&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tribhu05/pocketledger-ai/docs/screenshots/pocketledger-workflow.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%2Ftribhu05%2Fpocketledger-ai%2FHEAD%2Fdocs%2Fscreenshots%2Fpocketledger-workflow.gif" alt="PocketLedger AI Interactive Walkthrough"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;1. What Problem Does This Solve?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Freelancers, independent developers, and consultants collect hundreds of receipts and invoice PDFs every quarter—from cloud hosting (AWS, Hetzner, Vercel) and SaaS subscriptions (GitHub, Figma, Zoom) to travel, coffee meetings, and hardware purchases.&lt;/p&gt;
&lt;p&gt;Existing options force a frustrating dilemma:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Manual Spreadsheets:&lt;/strong&gt; Tedious, error-prone, hours wasted transcribing dates, vendor names, currencies, and tax line items.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Receipt Scanners:&lt;/strong&gt; Require uploading sensitive financial documents—exposing client names, hourly rates, home billing addresses, and credit card hints to third-party cloud AI vendors.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;PocketLedger AI eliminates this tradeoff.&lt;/strong&gt; It runs Google's open-weight &lt;strong&gt;Gemma 2B&lt;/strong&gt; locally via Ollama. It extracts…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tribhu05/pocketledger-ai" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Watch the Ingestion, Local Gemma Extraction &amp;amp; Split-Screen Review in Action:
&lt;/h3&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%2F9vmbkngtrp2ckt4z0dpo.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%2F9vmbkngtrp2ckt4z0dpo.gif" alt="PocketLedger AI Ingestion and Review Workflow" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The hosted demo currently uses deterministic fallback parsing because Ollama and OCR are unavailable in that deployment. It demonstrates the interface and fallback workflow; it does not demonstrate Gemma inference running on Render. The local configuration is the way to explore the Ollama-powered workflow.&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%2Fjcw7iivzndlmdy5fnj0i.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%2Fjcw7iivzndlmdy5fnj0i.png" alt="PocketLedger AI Dashboard" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;




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

&lt;p&gt;PocketLedger AI is an AI-assisted expense management tool designed for freelancers, independent developers, consultants, and side-hustlers who want to organize receipts without turning bookkeeping into another time-consuming project.&lt;/p&gt;

&lt;p&gt;It focuses on a specific workflow: converting expense documents into structured, reviewable financial records.&lt;/p&gt;

&lt;p&gt;The application supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PDF and image ingestion:&lt;/strong&gt; Extract embedded text from digital PDFs using &lt;code&gt;pypdf&lt;/code&gt; and process supported receipt images using Tesseract OCR.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open-weight AI extraction:&lt;/strong&gt; Run Gemma 2B Instruct through Ollama in the local configuration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured validation:&lt;/strong&gt; Validate extracted fields before they enter the financial workflow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Financial reconciliation:&lt;/strong&gt; Calculate expected totals and flag discrepancies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human review:&lt;/strong&gt; Inspect, edit, and explicitly approve extracted records.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local persistence:&lt;/strong&gt; Store records in SQLite in the local workflow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-currency reporting:&lt;/strong&gt; Keep supported currencies separate instead of adding unlike amounts together.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safer CSV exports:&lt;/strong&gt; Apply safeguards against spreadsheet formula injection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not an attempt to replace an accountant or build a complete accounting platform. It is a focused assistant for the repetitive first step of bookkeeping: getting information out of receipts and into organized records.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who Might Pay for It?
&lt;/h2&gt;

&lt;p&gt;The initial audience is freelancers and independent professionals who regularly handle software subscriptions, hosting bills, travel expenses, and client invoices.&lt;/p&gt;

&lt;p&gt;For someone who processes receipts every week, reducing repetitive data entry while retaining control over financial records could be valuable. Whether the tool saves enough time to justify payment is something I still need to validate with more users.&lt;/p&gt;




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

&lt;p&gt;PocketLedger AI combines a conventional web application with a local open-weight model and deterministic financial rules.&lt;/p&gt;

&lt;p&gt;The stack includes Python, FastAPI, Pydantic, React, TypeScript, Vite, SQLite, &lt;code&gt;pypdf&lt;/code&gt;, Tesseract OCR, Ollama, and Gemma 2B Instruct.&lt;/p&gt;

&lt;p&gt;The intended processing pipeline is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PDF / Receipt Image
        │
        ▼
Local Text Extraction (pypdf / Tesseract OCR)
        │
        ▼
Gemma 2B via Local Ollama
        │
        ▼
Structured Field Validation (Pydantic)
        │
        ▼
Deterministic Financial Checks (Decimal Math)
        │
        ▼
Human Review and Approval (Split-Screen Diff)
        │
        ▼
SQLite Ledger &amp;amp; Safe CSV Export
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1. Extracting information from documents
&lt;/h3&gt;

&lt;p&gt;Digital PDFs and photographed receipts require different approaches.&lt;/p&gt;

&lt;p&gt;For PDFs containing embedded text, PocketLedger uses &lt;code&gt;pypdf&lt;/code&gt;. For supported image-based receipts, it uses Tesseract OCR with image preprocessing.&lt;/p&gt;

&lt;p&gt;Separating text extraction from semantic extraction makes it easier to inspect and test each stage independently.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Using Gemma through Ollama
&lt;/h3&gt;

&lt;p&gt;The local model identifier is &lt;code&gt;gemma2:2b&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ollama serves the model through the local runtime. PocketLedger asks it to extract structured fields such as merchant, document type, transaction date, currency, subtotal, tax, discount, additional charges, and total.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# System prompt enforcing strict structured extraction in backend/gemma_extractor.py
&lt;/span&gt;&lt;span class="n"&gt;GEMMA_SYSTEM_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;You are PocketLedger AI, a precise financial document extraction engine for freelancers.
Extract key expense fields from the provided receipt or invoice text.
Output MUST be a valid JSON object matching this exact schema:

{
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;merchant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string or null - Name of business/vendor. NEVER guess or invent.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;document_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;receipt | invoice | other&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;invoice_number&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string or null - Invoice/receipt reference number if present&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transaction_date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string or null - Date formatted as YYYY-MM-DD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;currency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string - 3-letter currency code (USD, EUR, GBP, CAD, INR, etc.)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;subtotal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;number or null - Pre-tax amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tax&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;number or null - Tax/VAT/GST amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;discount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;number or null - Discount, coupon, or promotional reduction if explicitly present&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;additional_charges&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;number or null - Tips, service fees, or delivery surcharge if explicitly present&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;number or null - Grand total amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;category&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;one of: Software &amp;amp; SaaS, Office Supplies, Hardware &amp;amp; Equipment, Travel &amp;amp; Lodging, Meals &amp;amp; Entertainment, Professional Services, Utilities, Other&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;warnings&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: [&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;array of specific warning strings if any value was missing or illegible&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]
}&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The extraction layer requests JSON and validates the response against a Pydantic schema. Its parser also handles common malformed-response cases, such as JSON wrapped in Markdown or preceded by conversational text.&lt;/p&gt;

&lt;p&gt;However, valid JSON does not guarantee correct information. A model can return a plausible but incorrect date or amount, so financial validation must be a separate step.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Keeping financial arithmetic deterministic
&lt;/h3&gt;

&lt;p&gt;I didn't want an LLM's plausible-looking answer to become the source of truth for financial calculations.&lt;/p&gt;

&lt;p&gt;PocketLedger's reconciliation rule is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Expected Total = Subtotal + Tax − Discount + Additional Charges&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Difference = |Stated Total − Expected Total|&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The implementation uses Python's &lt;code&gt;Decimal&lt;/code&gt; for monetary arithmetic and a configured rounding tolerance of ₹0.05, or the equivalent amount in the relevant currency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Actual implementation from backend/validator.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ROUND_HALF_UP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;InvalidOperation&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_money_decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Convert monetary value to exact 2-decimal Decimal to eliminate IEEE-754 drift.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;val_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val_str&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;quantize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.01&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;rounding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ROUND_HALF_UP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;except &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InvalidOperation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reconcile_financial_amounts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;subtotal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;tax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;discount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;additional_charges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tolerance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.05&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]]:&lt;/span&gt;
    &lt;span class="n"&gt;warnings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;warnings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Critical: Total amount is missing or could not be determined.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mismatch&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;warnings&lt;/span&gt;

    &lt;span class="n"&gt;total_dec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;to_money_decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;d_dec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;to_money_decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;discount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;c_dec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;to_money_decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;additional_charges&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;subtotal&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;s_dec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;to_money_decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subtotal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;t_dec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;to_money_decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tax&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;expected_dec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s_dec&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;t_dec&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;d_dec&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;c_dec&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;quantize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.01&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;rounding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ROUND_HALF_UP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;diff_dec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_dec&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;expected_dec&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;quantize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.01&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;rounding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ROUND_HALF_UP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;abs_diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff_dec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;abs_diff&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tolerance&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reconciled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;warnings&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Reconciliation mismatch: Subtotal (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;s_dec&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;) + Tax (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;t_dec&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;) - &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Discount (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;d_dec&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;) + Charges (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;c_dec&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;) = Expected (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;expected_dec&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;) vs &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Stated Total (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;total_dec&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;), Difference: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;abs_diff&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;warnings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mismatch&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff_dec&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;warnings&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unverified&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Subtotal&lt;/td&gt;
&lt;td&gt;₹2,300.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GST&lt;/td&gt;
&lt;td&gt;₹414.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Discount&lt;/td&gt;
&lt;td&gt;₹114.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Expected total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;₹2,600.00&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Stated total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;₹2,600.00&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reconciliation Status&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Reconciled (Difference = 0.00)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The arithmetic is straightforward:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;₹2,300 + ₹414 − ₹114 = ₹2,600&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When the calculated and stated totals differ beyond the configured tolerance, the record is flagged for review rather than silently accepted:&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%2Fnonf3cn55ke4na6e2kwx.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%2Fnonf3cn55ke4na6e2kwx.png" alt="PocketLedger AI Split-Screen Review and Reconciliation Screen" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This check cannot prove that the original receipt was read correctly. It provides a separate consistency check on the extracted numbers.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Keeping humans in control
&lt;/h3&gt;

&lt;p&gt;Extracted data should not become a trusted expense record simply because the model returned valid JSON.&lt;/p&gt;

&lt;p&gt;PocketLedger lets users inspect extracted fields, correct values, and approve records explicitly. The backend also records field edits in a JSON diff so changes made during review can be inspected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"user_edits"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"merchant"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"old"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AMZN MKTP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"new"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Amazon Web Services"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"old"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Other"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"new"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Software &amp;amp; SaaS"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is not to eliminate human judgment. It is to make repetitive work easier while preserving a clear review step.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Handling currencies and CSV exports
&lt;/h3&gt;

&lt;p&gt;Adding &lt;code&gt;$50 USD&lt;/code&gt; and &lt;code&gt;€40 EUR&lt;/code&gt; into a single total would be misleading without exchange-rate conversion.&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%2Ft60rzjvq9xfld87o7fir.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%2Ft60rzjvq9xfld87o7fir.gif" alt="PocketLedger AI Multi-Currency Ledger and Reports" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PocketLedger's summary export groups records by month, category, and currency rather than treating different currencies as interchangeable.&lt;/p&gt;

&lt;p&gt;The project also applies defensive handling to CSV cells beginning with characters such as &lt;code&gt;=&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;@&lt;/code&gt;, tabs, and carriage returns. Spreadsheet applications may interpret some such cells as formulas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Neutralizing spreadsheet injection in backend/export.py
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sanitize_csv_cell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
    &lt;span class="n"&gt;val_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;val_str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;val_str&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;val_str&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reduces a known risk but is not a guarantee against every spreadsheet security issue.&lt;/p&gt;




&lt;h2&gt;
  
  
  Technical Evidence: What I Actually Tested
&lt;/h2&gt;

&lt;p&gt;The project's technical evidence report records these automated test results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ pytest backend/tests/test_backend.py -v
============================= test session starts =============================
platform win32 -- Python 3.14.0, pytest-9.1.1, pluggy-1.6.0
collected 16 items

backend/tests/test_backend.py::test_reconciliation_math PASSED           [  6%]
backend/tests/test_backend.py::test_record_validation_backward_compatibility PASSED [ 12%]
backend/tests/test_backend.py::test_date_normalization PASSED            [ 18%]
backend/tests/test_backend.py::test_currency_normalization PASSED        [ 25%]
backend/tests/test_backend.py::test_csv_injection_sanitization PASSED    [ 31%]
backend/tests/test_backend.py::test_csv_export_multi_currency_segregation PASSED [ 37%]
backend/tests/test_backend.py::test_deterministic_fallback PASSED        [ 43%]
backend/tests/test_backend.py::test_api_status_endpoint PASSED           [ 50%]
backend/tests/test_backend.py::test_raw_text_upload_and_review_workflow PASSED [ 56%]
backend/tests/test_backend.py::test_discount_reconciliation_workflow PASSED [ 62%]
backend/tests/test_backend.py::test_exact_decimal_arithmetic_drift_prevention PASSED [ 68%]
backend/tests/test_backend.py::test_currency_anomaly_detection PASSED    [ 75%]
backend/tests/test_backend.py::test_schema_currency_string_coercion PASSED [ 81%]
backend/tests/test_backend.py::test_gemma_json_parser_robustness PASSED  [ 87%]
backend/tests/test_backend.py::test_synthetic_scenarios_reconciliation PASSED [ 93%]
backend/tests/test_backend.py::test_formula_injection_defense_suite PASSED [100%]

============================= 16 passed in 10.34s =============================

$ npm test -- --run (frontend)
✓ src/test/App.test.tsx (7 tests) 1189ms
Test Files  1 passed (1)
     Tests  7 passed (7)
&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;Test suite&lt;/th&gt;
&lt;th&gt;Reported result&lt;/th&gt;
&lt;th&gt;What is verified&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Backend — Pytest&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;16 passed, 0 failed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reconciliation math, discount &amp;amp; surcharge logic, Decimal drift elimination, date/currency normalization, CSV injection fuzzing, multi-currency export segregation, API status probe, review diff audit, and JSON parser recovery.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Frontend — Vitest&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7 passed, 0 failed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Status indicator pill, dashboard metric cards, ledger search filtering, CSV export triggers, pricing validation survey, split-screen review modal, and reconciliation display.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;23 passed, 0 failed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100% pass rate across entire codebase.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The reported backend coverage includes reconciliation, discount handling, Decimal arithmetic, date and currency normalization, CSV sanitization, fallback parsing, API status, review workflows, and JSON parsing.&lt;/p&gt;

&lt;p&gt;The frontend tests cover selected interface behavior, including dashboard metrics, ledger filtering, CSV export interactions, the review modal, and reconciliation display.&lt;/p&gt;

&lt;p&gt;Passing automated tests does not establish that every possible receipt will be processed correctly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/tribhu05/pocketledger-ai/blob/master/docs/technical-evidence-report.md" rel="noopener noreferrer"&gt;Read the full technical evidence report in the repository&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/tribhu05/pocketledger-ai" rel="noopener noreferrer"&gt;Inspect the project and setup instructions&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What the Benchmarks Show
&lt;/h2&gt;

&lt;p&gt;The project documents two separate synthetic evaluations. They should not be interpreted as a controlled head-to-head comparison:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Evaluation Dimension&lt;/th&gt;
&lt;th&gt;Local Gemma 2B Evaluation&lt;/th&gt;
&lt;th&gt;Deterministic Fallback Evaluation&lt;/th&gt;
&lt;th&gt;Context &amp;amp; Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hardware / Runtime&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AMD Ryzen 3 7320U (8 GB RAM) via Ollama&lt;/td&gt;
&lt;td&gt;Local Python process (regex heuristic)&lt;/td&gt;
&lt;td&gt;Local open-weight inference vs regex parser&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Test Corpus&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;8 synthetic receipts/invoices&lt;/td&gt;
&lt;td&gt;10 synthetic receipts/invoices&lt;/td&gt;
&lt;td&gt;Diverse real-world freelancer expense scenarios&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Merchant Name&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;8/8 correct&lt;/strong&gt; (100%)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;10/10 correct&lt;/strong&gt; (100%)&lt;/td&gt;
&lt;td&gt;Extracts business name ignoring visual noise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total Amount&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;8/8 correct&lt;/strong&gt; (100%)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;10/10 correct&lt;/strong&gt; (100%)&lt;/td&gt;
&lt;td&gt;Preserves &lt;code&gt;null&lt;/code&gt; on smudged receipts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Currency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;8/8 correct&lt;/strong&gt; (100%)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;10/10 correct&lt;/strong&gt; (100%)&lt;/td&gt;
&lt;td&gt;Maps $, €, £, ₹ to standard ISO codes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Document Type&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;8/8 correct&lt;/strong&gt; (100%)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;10/10 correct&lt;/strong&gt; (100%)&lt;/td&gt;
&lt;td&gt;Differentiates invoices from receipts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Transaction Date&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;7/8 correct&lt;/strong&gt; (87.5%)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;9/10 correct&lt;/strong&gt; (90%)&lt;/td&gt;
&lt;td&gt;The date miss involved European-style dates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Average Processing Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;34.1 seconds&lt;/strong&gt; per document&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;0.58 milliseconds&lt;/strong&gt; per document&lt;/td&gt;
&lt;td&gt;Local compute trade-off vs instant heuristic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The local evaluation shows that local extraction was feasible on the tested hardware, but processing was relatively slow. One date was misinterpreted, illustrating why review remains necessary.&lt;/p&gt;

&lt;p&gt;The fallback parser uses deterministic heuristics rather than Gemma. Its results come from a small, specific synthetic test set and should not be generalized to arbitrary invoices.&lt;/p&gt;

&lt;p&gt;These evaluations measure different approaches under different test conditions. They do not prove that either approach achieves the same accuracy on real customer documents.&lt;/p&gt;

&lt;p&gt;The engineering lesson is that extraction quality, arithmetic consistency, and processing speed are separate problems. A useful expense assistant needs to address all three.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/tribhu05/pocketledger-ai/blob/master/docs/benchmark_report.md" rel="noopener noreferrer"&gt;Read the benchmark report in the repository&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Local AI Versus the Hosted Demo
&lt;/h2&gt;

&lt;p&gt;The local and hosted configurations serve different purposes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Local Mode (Workstation)&lt;/th&gt;
&lt;th&gt;Hosted Demo (Render Cloud)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Inference Engine&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Local Google Gemma 2B via Ollama&lt;/td&gt;
&lt;td&gt;Deterministic Heuristic Fallback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Privacy Boundary&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100% On-Device (Zero Network Egress)&lt;/td&gt;
&lt;td&gt;Ephemeral Cloud Container&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reconciliation Math&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Python &lt;code&gt;Decimal&lt;/code&gt; Engine&lt;/td&gt;
&lt;td&gt;Python &lt;code&gt;Decimal&lt;/code&gt; Engine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Review &amp;amp; Audit&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Full split-screen with diff tracking&lt;/td&gt;
&lt;td&gt;Full split-screen with diff tracking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Persistence&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Persistent SQLite (&lt;code&gt;pocketledger.db&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;In-memory SQLite database&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Status Declaration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Shows &lt;code&gt;gemma2_local&lt;/code&gt; badge&lt;/td&gt;
&lt;td&gt;Shows &lt;code&gt;deterministic_fallback&lt;/code&gt; badge&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Render deployment currently reports that Ollama and OCR are unavailable and that the application is using &lt;code&gt;deterministic_fallback&lt;/code&gt;. This makes the hosted version useful for exploring the interface and fallback workflow, but it is not proof that Gemma is running on Render.&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%2Fon1tv359psiu7ebqzcw6.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%2Fon1tv359psiu7ebqzcw6.png" alt="PocketLedger AI System Status and Privacy Inspector" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can verify this directly via the live Render endpoint (&lt;code&gt;GET https://pocketledger-ai.onrender.com/api/status&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"app_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PocketLedger AI"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"environment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"production"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ollama_connected"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"gemma_available"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"current_mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deterministic_fallback"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"database_connected"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This distinction matters because I don't want a reviewer to confuse a working web demo with a local model benchmark.&lt;/p&gt;

&lt;p&gt;For the local AI workflow, the repository documents how to install Ollama, pull &lt;code&gt;gemma2:2b&lt;/code&gt;, configure the backend, and launch the React frontend.&lt;/p&gt;




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

&lt;p&gt;Open-weight AI is central to this project because it gives users another option for processing sensitive financial documents.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. More control over document processing
&lt;/h3&gt;

&lt;p&gt;Invoices may contain customer names, billing details, addresses, and information covered by confidentiality agreements.&lt;/p&gt;

&lt;p&gt;Running the configured inference workflow locally can reduce the need to send document contents to an external AI inference API. Local execution does not automatically make an entire computer secure, but it gives users more control over where inference takes place.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Less dependence on paid inference APIs
&lt;/h3&gt;

&lt;p&gt;After downloading the model, local inference does not require a paid cloud inference API for every extraction. This can make costs more predictable for a small application.&lt;/p&gt;

&lt;p&gt;There are trade-offs: local inference uses the user's hardware, consumes memory and disk space, and can be slower on modest machines.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Freedom to inspect and adapt
&lt;/h3&gt;

&lt;p&gt;The project is released under the MIT License, and the local workflow uses an open-weight Gemma model through Ollama.&lt;/p&gt;

&lt;p&gt;Developers can inspect the extraction pipeline, adapt prompts, experiment with compatible models, and improve the validation and review logic.&lt;/p&gt;

&lt;p&gt;The model is only one component of the system. The surrounding code determines how extracted data is checked, presented, stored, and exported.&lt;/p&gt;

&lt;p&gt;Open innovation makes these choices possible: developers can inspect the implementation and users can choose a processing setup that better fits their needs.&lt;/p&gt;




&lt;h2&gt;
  
  
  My First User: Nitu Tested PocketLedger AI
&lt;/h2&gt;

&lt;p&gt;I wanted to see how PocketLedger AI performed for someone other than its creator.&lt;/p&gt;

&lt;p&gt;Nitu, a freelance developer working with US clients, tried the local workflow after describing how time-consuming it was to transcribe AWS receipts and invoice PDFs.&lt;/p&gt;

&lt;p&gt;He tested six receipts and an Indian SaaS invoice using the local Ollama setup.&lt;/p&gt;

&lt;p&gt;His initial feedback was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Honestly, this is pretty impressive! The receipts were processed well, and I really like that everything runs locally.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;He also offered to test more invoices and report edge cases.&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%2F63z6a8q53zst9ys50ptr.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%2F63z6a8q53zst9ys50ptr.png" alt="First-User Feedback on PocketLedger AI" width="585" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Initial feedback from Nitu after testing PocketLedger AI.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What I learned
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Receipt transcription is a concrete, repetitive problem.&lt;/li&gt;
&lt;li&gt;Local inference can be an important consideration for people handling confidential documents.&lt;/li&gt;
&lt;li&gt;A handful of successful documents is an encouraging start, not proof of broad reliability.&lt;/li&gt;
&lt;li&gt;Additional testing needs to cover different layouts, date formats, currencies, discounts, and ambiguous totals.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm grateful that Nitu took the time to test an early version. His feedback encourages me to keep improving extraction reliability and the review workflow instead of claiming that every receipt will work perfectly.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Primary Category: Side Hustle
&lt;/h3&gt;

&lt;p&gt;PocketLedger AI was built specifically for the &lt;strong&gt;Side Hustle&lt;/strong&gt; prompt. It tackles a concrete administrative pain point experienced by independent developers, freelancers, and solo consultants: organizing sensitive receipts and business expenses without sacrificing client confidentiality or paying expensive monthly accounting SaaS fees.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sponsor Category: Google Gemma / Open-Source AI
&lt;/h3&gt;

&lt;p&gt;PocketLedger AI is entered for the &lt;strong&gt;Gemma / Open-Source AI&lt;/strong&gt; track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local Gemma 2B Inference Engine:&lt;/strong&gt; The application integrates Google's open-weight &lt;strong&gt;Gemma 2B Instruct&lt;/strong&gt; (&lt;code&gt;gemma2:2b&lt;/code&gt;) model running entirely on-device through the local Ollama REST API (&lt;code&gt;POST http://localhost:11434/api/generate&lt;/code&gt;). Sensitive client invoices, addresses, and billing amounts never leave the developer's laptop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strict Structured Schema:&lt;/strong&gt; Prompt instructions constrain Gemma 2B to output validated financial entities (merchant, transaction date, subtotal, tax, discount, surcharge, total, currency, and freelance category).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Defensive Multi-Stage Parsing:&lt;/strong&gt; Small open-weight models sometimes wrap JSON in conversational markdown or trailing text. PocketLedger includes a 4-stage JSON recovery parser in &lt;code&gt;backend/gemma_extractor.py&lt;/code&gt; and automated Pydantic coercion.&lt;/li&gt;
&lt;/ul&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%2Fdfya71qg3ln4bx2xhsf5.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%2Fdfya71qg3ln4bx2xhsf5.png" alt="PocketLedger AI Gemma Integration Proof" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Gemma Integration &amp;amp; Prompt Schema (&lt;code&gt;backend/gemma_extractor.py&lt;/code&gt;)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# System prompt constraining Google Gemma 2B to valid financial schema
&lt;/span&gt;&lt;span class="n"&gt;GEMMA_SYSTEM_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;You are PocketLedger AI, a precise financial document extraction engine for freelancers.
Extract key expense fields from the provided receipt or invoice text.
Output MUST be a valid JSON object matching this exact schema:

{
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;merchant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string or null - Name of business/vendor. NEVER guess or invent.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;document_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;receipt | invoice | other&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;invoice_number&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string or null&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transaction_date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string or null - Date formatted as YYYY-MM-DD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;currency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string - 3-letter currency code (USD, EUR, GBP, CAD, INR, etc.)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;subtotal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;number or null - Pre-tax amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tax&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;number or null - Tax/VAT/GST amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;discount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;number or null - Explicit discount or promo deduction&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;additional_charges&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;number or null - Tips, service fees, or surcharge&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;number or null - Grand total amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,
  &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;category&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;one of: Software &amp;amp; SaaS, Cloud &amp;amp; Hosting, Hardware, Travel, Meals, Office Supplies, Advertising, Professional Services, Other&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;
}

CRITICAL RULES:
1. NEVER invent, hallucinate, or assume missing values. If not visible, use null.
2. Monetary fields MUST be numeric (or null), never strings.
3. Output ONLY valid JSON. Do not wrap in markdown or commentary.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Verified Automated Test Suite (&lt;code&gt;backend/tests/test_backend.py&lt;/code&gt;)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ pytest backend/tests/test_backend.py -k gemma -v
backend/tests/test_backend.py::test_schema_currency_string_coercion PASSED   [ 50%]
backend/tests/test_backend.py::test_gemma_json_parser_robustness     PASSED   [100%]
============================= 2 passed in 1.42s =============================
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Partner Category: Best Use of Render
&lt;/h3&gt;

&lt;p&gt;PocketLedger AI is entered for the &lt;strong&gt;Best Use of Render&lt;/strong&gt; prize track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live Production Deployment:&lt;/strong&gt; &lt;a href="https://pocketledger-ai.onrender.com" rel="noopener noreferrer"&gt;https://pocketledger-ai.onrender.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Declarative Blueprint (&lt;code&gt;render.yaml&lt;/code&gt;):&lt;/strong&gt; Continuous deployment with automated health check probes on &lt;code&gt;/api/status&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-Friction Evaluation:&lt;/strong&gt; Hackathon judges can test the full ingest, reconciliation, review, and export workflow instantly with zero local setup.&lt;/li&gt;
&lt;/ul&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%2Fonqnivt0xbj7xiduphfd.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%2Fonqnivt0xbj7xiduphfd.png" alt="PocketLedger AI Render Deployment Proof" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Infrastructure as Code: Declarative &lt;code&gt;render.yaml&lt;/code&gt; Blueprint
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pocketledger-ai&lt;/span&gt;
    &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker&lt;/span&gt;
    &lt;span class="na"&gt;plan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;free&lt;/span&gt;
    &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;oregon&lt;/span&gt;
    &lt;span class="na"&gt;healthCheckPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/api/status&lt;/span&gt;
    &lt;span class="na"&gt;envVars&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PORT&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10000&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ENVIRONMENT&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DATABASE_URL&lt;/span&gt;
        &lt;span class="na"&gt;value: sqlite:///:memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Unified Multi-Stage &lt;code&gt;Dockerfile&lt;/code&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Stage 1: Build Frontend (React 19 + TypeScript + Vite)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:20-slim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;frontend-builder&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app/frontend&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; frontend/package*.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; frontend/ ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="c"&gt;# Stage 2: Production Python Backend + Static Asset Serving&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.11-slim&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    tesseract-ocr libtesseract-dev &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; backend/requirements.txt ./backend/&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; backend/requirements.txt
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; backend/ ./backend/&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=frontend-builder /app/frontend/dist ./frontend/dist&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 10000&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["uvicorn", "backend.main:app", "--host", "0.0.0.0", "--port", "10000"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Cloud-Resilient Architecture
&lt;/h4&gt;

&lt;p&gt;In cloud environments where a local Ollama daemon is absent, the backend gracefully activates its deterministic regex/heuristic fallback parser. Evaluators get immediate, reliable document intake and financial reconciliation without configuration overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Could This Become a Side Hustle?
&lt;/h2&gt;

&lt;p&gt;My initial pricing hypothesis is a &lt;strong&gt;$29 one-time purchase&lt;/strong&gt; for a packaged desktop edition, potentially including easier installation, local receipt-folder monitoring, and customizable tax categories.&lt;/p&gt;

&lt;p&gt;That is a hypothesis, not a validated price. I have not established that users will pay for it.&lt;/p&gt;

&lt;p&gt;Before asking people to buy it, I would focus on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reliable onboarding:&lt;/strong&gt; Make installing the application and local model straightforward.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better extraction coverage:&lt;/strong&gt; Test more document layouts, date formats, currencies, and edge cases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A dependable review workflow:&lt;/strong&gt; Make errors and discrepancies easy to identify and correct.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real user validation:&lt;/strong&gt; Recruit more freelancers, observe their workflows, and test willingness to pay before committing to a pricing model.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is to build something useful enough that a freelancer would choose it over a spreadsheet—not to add AI for its own sake.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Source code:&lt;/strong&gt; &lt;a href="https://github.com/tribhu05/pocketledger-ai" rel="noopener noreferrer"&gt;PocketLedger AI on GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://pocketledger-ai.onrender.com/" rel="noopener noreferrer"&gt;Try PocketLedger AI&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Video demo:&lt;/strong&gt; &lt;a href="https://youtu.be/Uk_9aB7Z0xo" rel="noopener noreferrer"&gt;Watch the 50-second walkthrough&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technical evidence:&lt;/strong&gt; &lt;a href="https://github.com/tribhu05/pocketledger-ai/blob/master/docs/technical-evidence-report.md" rel="noopener noreferrer"&gt;Test report&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Benchmark details:&lt;/strong&gt; &lt;a href="https://github.com/tribhu05/pocketledger-ai/blob/master/docs/benchmark_report.md" rel="noopener noreferrer"&gt;Synthetic evaluation report&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PocketLedger AI is released under the MIT License.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Built with Python, FastAPI, React, TypeScript, SQLite, Ollama, and Google's open-weight Gemma model.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>What If AI Helped You Put Your Phone Down? 🌿 I Built Outside to Make That Happen</title>
      <dc:creator>Tribhuwan Singh</dc:creator>
      <pubDate>Sat, 10 Oct 2026 11:27:34 +0000</pubDate>
      <link>https://dev.to/t7b5u/what-if-ai-helped-you-put-your-phone-down-meet-outside-24hb</link>
      <guid>https://dev.to/t7b5u/what-if-ai-helped-you-put-your-phone-down-meet-outside-24hb</guid>
      <description>&lt;p&gt;What If AI Helped You Put Your Phone Down? 🌿 I Built Outside to Make That Happen&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Most apps want more of your attention. I wanted to build one that helps you give it back to the real world.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Waiting for a friend? Scroll.&lt;/p&gt;

&lt;p&gt;Have 20 minutes between classes? Scroll.&lt;/p&gt;

&lt;p&gt;Feeling stressed and looking for a break? Somehow, you're still staring at a screen.&lt;/p&gt;

&lt;p&gt;We open our phones without thinking. Sometimes we're looking for something specific. Other times, we're just filling a quiet moment because we don't know what else to do.&lt;/p&gt;

&lt;p&gt;And even when we decide to step outside, another problem appears: &lt;em&gt;What should I do? Where should I start? Is 15 minutes even enough?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That got me thinking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if AI didn't give us another reason to stay on our phones? What if it helped us put them down?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That question inspired me to build &lt;strong&gt;Outside&lt;/strong&gt; — an AI-powered outdoor companion designed to turn spare time into small, practical opportunities to explore, notice our surroundings, and reconnect with the world outside our screens.&lt;/p&gt;

&lt;p&gt;The idea is simple: use technology to make the first step easier, then get out of the way.&lt;/p&gt;

&lt;p&gt;🌐 &lt;strong&gt;Try Outside:&lt;/strong&gt; &lt;a href="https://outside-lmth.onrender.com" rel="noopener noreferrer"&gt;https://outside-lmth.onrender.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🎬 &lt;strong&gt;Watch the demo:&lt;/strong&gt; &lt;a href="https://youtu.be/umWsHyiBCoo" rel="noopener noreferrer"&gt;https://youtu.be/umWsHyiBCoo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💻 &lt;strong&gt;Explore the code:&lt;/strong&gt; &lt;a href="https://github.com/tribhu05/outside" rel="noopener noreferrer"&gt;https://github.com/tribhu05/outside&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🌱 1. The problem I wanted to solve
&lt;/h2&gt;

&lt;p&gt;I wasn't trying to build another productivity dashboard or a chatbot that could talk endlessly about healthy habits.&lt;/p&gt;

&lt;p&gt;I wanted to explore a smaller, more practical problem: the gap between wanting to do something outside and actually doing it.&lt;/p&gt;

&lt;p&gt;Imagine you have 20 minutes free.&lt;/p&gt;

&lt;p&gt;You could take a short walk, explore a nearby street, listen to the birds, notice something interesting, or simply take a break from your usual routine.&lt;/p&gt;

&lt;p&gt;But deciding what to do takes effort. When you're tired or distracted, doing nothing can feel easier than making a plan.&lt;/p&gt;

&lt;p&gt;A generic list of outdoor activities doesn't necessarily help, either. It doesn't know whether you have 10 minutes or an hour, whether you want something relaxing or active, or what kind of experience you're looking for.&lt;/p&gt;

&lt;p&gt;I wanted to make that decision easier.&lt;/p&gt;

&lt;p&gt;Instead of asking people to plan everything themselves, Outside lets them describe what they want in natural language and turns that intent into a structured outdoor activity.&lt;/p&gt;

&lt;p&gt;The goal isn't to optimize every minute of someone's life.&lt;/p&gt;

&lt;p&gt;It's to make it a little easier to start living that minute.&lt;/p&gt;

&lt;h2&gt;
  
  
  🍃 2. Meet Outside
&lt;/h2&gt;

&lt;p&gt;Outside is built around a different kind of app experience.&lt;/p&gt;

&lt;p&gt;Instead of encouraging you to stay and explore endless content, it helps you prepare an activity and then transition away from the screen.&lt;/p&gt;

&lt;p&gt;The experience brings together natural-language activity planning, sensory challenges, a dedicated GO OUTSIDE mode, and a way to reflect on the experience afterwards.&lt;/p&gt;

&lt;p&gt;Let's walk through how it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧭 3. From a vague idea to an actual plan
&lt;/h2&gt;

&lt;p&gt;Sometimes, the hardest part of doing something is deciding what that something should be.&lt;/p&gt;

&lt;p&gt;Outside is designed to accept everyday requests rather than requiring users to describe their plans in rigid technical terms.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;"I have 20 minutes, feel a little stressed, and want to get some fresh air."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That request contains several pieces of intent: the available time, the user's mood, and the kind of experience they're looking for.&lt;/p&gt;

&lt;p&gt;Outside interprets the request and uses its planning engine to organize an outdoor activity.&lt;/p&gt;

&lt;p&gt;The intention is to make the process feel closer to explaining what you need to a person than filling out a complicated form.&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%2F920x2ff52ty400myc8p5.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%2F920x2ff52ty400myc8p5.png" alt=" " width="800" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1: The Outside interface, where the user begins planning an outdoor activity.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is the first important part of the experience. The user shouldn't need to understand AI models, prompts, or planning algorithms to get started.&lt;/p&gt;

&lt;p&gt;They should be able to describe what they want and move on.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✨ 4. The plan is only the beginning
&lt;/h2&gt;

&lt;p&gt;Generating an activity isn't the entire point.&lt;/p&gt;

&lt;p&gt;Outside is designed to make the resulting experience more intentional through small sensory challenges and prompts.&lt;/p&gt;

&lt;p&gt;Instead of walking while looking at a screen, you might be encouraged to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listen carefully to the sounds around you.&lt;/li&gt;
&lt;li&gt;Notice patterns in leaves, branches, or clouds.&lt;/li&gt;
&lt;li&gt;Look for something interesting that you would normally walk past.&lt;/li&gt;
&lt;li&gt;Pay attention to the environment without constantly checking your phone.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are small actions, but they change the purpose of a walk.&lt;/p&gt;

&lt;p&gt;You're no longer simply trying to fill 20 minutes. You're giving yourself a reason to notice the world around you.&lt;/p&gt;

&lt;p&gt;The challenges aren't intended to make every moment competitive or turn relaxation into another productivity target.&lt;/p&gt;

&lt;p&gt;They're gentle prompts for paying attention.&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%2F5lq8uf8hn509nl1oyerb.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%2F5lq8uf8hn509nl1oyerb.png" alt=" " width="799" height="546"&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%2F4ov41xcu4ntzx0kjht6y.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%2F4ov41xcu4ntzx0kjht6y.png" alt=" " width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 2: Outside turning a natural-language request ("20 minutes, feeling mentally foggy, need a screen break") into a structured, eyes-up walk with sensory cues.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  📵 5. GO OUTSIDE mode: the most important part
&lt;/h2&gt;

&lt;p&gt;This is the feature that best represents the philosophy behind the project.&lt;/p&gt;

&lt;p&gt;Think about the typical AI application experience.&lt;/p&gt;

&lt;p&gt;You ask a question. You receive an answer. Then you ask another question. Before you know it, you've spent 30 minutes interacting with a screen.&lt;/p&gt;

&lt;p&gt;Outside is intended to work differently.&lt;/p&gt;

&lt;p&gt;Once you've prepared your activity, GO OUTSIDE mode provides a transition from planning to doing.&lt;/p&gt;

&lt;p&gt;You have your activity. You know what to focus on. Now it's time to leave the application and experience it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The screen should help you prepare for the experience, not become the experience itself.&lt;/strong&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%2Fnqy4egn96v2ldt6j4k15.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%2Fnqy4egn96v2ldt6j4k15.png" alt=" " width="800" height="629"&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%2F3zqj4mxh5pxjfze2eobt.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%2F3zqj4mxh5pxjfze2eobt.png" alt=" " width="799" height="281"&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%2F3o8ou5z99m1jpatuy82p.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%2F3o8ou5z99m1jpatuy82p.png" alt=" " width="799" height="345"&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%2Fqu7m74vdu7z8w2xtj8pp.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%2Fqu7m74vdu7z8w2xtj8pp.png" alt=" " width="800" height="340"&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%2Ftw4emidutpdxygdcxmk5.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%2Ftw4emidutpdxygdcxmk5.png" alt=" " width="800" height="302"&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%2F5fxwwqjx8kkaphv3vvr4.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%2F5fxwwqjx8kkaphv3vvr4.png" alt=" " width="800" height="967"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 3: GO OUTSIDE mode. This is where the application encourages the user to shift attention away from the screen.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I think this is an important product-design distinction.&lt;/p&gt;

&lt;p&gt;A wellness app doesn't necessarily become useful by adding more features, more notifications, or more reasons to return.&lt;/p&gt;

&lt;p&gt;Sometimes, its most valuable contribution is helping someone take a small action and then letting them go.&lt;/p&gt;

&lt;h2&gt;
  
  
  🌤️ 6. After the walk: reflection and local history
&lt;/h2&gt;

&lt;p&gt;Going outside shouldn't have to become another activity you measure obsessively.&lt;/p&gt;

&lt;p&gt;Still, being able to reflect on an experience can help make it meaningful.&lt;/p&gt;

&lt;p&gt;Outside includes reflection and local history features so users can look back on their outdoor activities.&lt;/p&gt;

&lt;p&gt;Rather than treating an activity as something that disappears as soon as it's finished, the application gives users a way to record their experience and revisit their history.&lt;/p&gt;

&lt;p&gt;The purpose is simple: remember the moments you made time for, without creating another demanding digital routine.&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%2Fu7sboy19rneqe2wombdl.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%2Fu7sboy19rneqe2wombdl.png" alt=" " width="800" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 4: The reflection and history experience after completing an outdoor activity.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This also gives the project room to grow. Future improvements could explore more adaptive reflection prompts, better personalization, and ways to make activities accessible to people with different schedules and energy levels.&lt;/p&gt;




&lt;h2&gt;
  
  
  🌿7. Field Test: Taking Outside Outside (What Actually Happened)
&lt;/h2&gt;

&lt;p&gt;The prompt encouraged builders to take their project outside, so at 5:45 PM on Thursday, I closed my laptop, opened Outside on my phone, and typed what was actually on my mind:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"I've been staring at code for 6 hours, my eyes hurt, and I have 25 minutes before my next call."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The application generated a &lt;strong&gt;20-Minute Sensory Reset&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Route Strategy&lt;/strong&gt;: Walk in the direction of the quietest street corner, maintaining an unhurried pace.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sensory Objective&lt;/strong&gt;: &lt;em&gt;Notice three different textures in tree bark or stone walls, and consciously count the duration of your exhales.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Rule&lt;/strong&gt;: &lt;em&gt;No audiobooks, no podcasts, no checking notifications.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I tapped &lt;strong&gt;GO OUTSIDE Mode&lt;/strong&gt;. The screen went dim and displayed a clean, calm timer card. I locked the phone and slid it into my back pocket.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I Noticed:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Phantom Vibration&lt;/strong&gt;: In the first five minutes, my hand instinctively reached for my pocket twice out of pure habit. Because GO OUTSIDE mode had already given me a clear sensory objective, I had something concrete to redirect my attention toward instead of a screen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sensory Grounding Works&lt;/strong&gt;: Focusing on subtle physical textures (rough oak bark vs. smooth garden stones) forced my visual focus to shift from 18 inches away (monitor distance) to infinity. By the 15-minute mark, the tension in my temples had visibly subsided.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Reflection Log&lt;/strong&gt;: When the subtle timer finished, I walked back in, tapped one sentence into the reflection log (&lt;em&gt;"Felt my shoulders drop after the first 500 meters"&lt;/em&gt;), and closed the tab. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The entire digital interaction took &lt;strong&gt;under 45 seconds&lt;/strong&gt;. The physical experience lasted 20 minutes. That ratio is the only metric of success this project cares about.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 8. Why use AI for this?
&lt;/h2&gt;

&lt;p&gt;This was one of the most interesting engineering decisions in the project.&lt;/p&gt;

&lt;p&gt;I didn't want to add an LLM simply because AI applications are popular. I wanted it to solve a specific problem: understanding what someone means when they describe the kind of outdoor experience they want.&lt;/p&gt;

&lt;p&gt;People don't naturally speak in structured data.&lt;/p&gt;

&lt;p&gt;They say things like:&lt;/p&gt;

&lt;p&gt;"I've got a little time before my next class."&lt;/p&gt;

&lt;p&gt;"I don't have much energy today."&lt;/p&gt;

&lt;p&gt;"I want to get outside, but I don't want anything too intense."&lt;/p&gt;

&lt;p&gt;Interpreting requests like these is a useful role for a language model.&lt;/p&gt;

&lt;p&gt;But there is an important distinction between understanding a request and reliably executing a plan.&lt;/p&gt;

&lt;p&gt;I designed Outside to separate those responsibilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  The AI interprets; the planning engine organizes
&lt;/h3&gt;

&lt;p&gt;The Gemma-compatible integration helps interpret natural-language intent. A separate deterministic activity engine handles the structured planning process.&lt;/p&gt;

&lt;p&gt;This separation means the language model isn't responsible for every part of the application.&lt;/p&gt;

&lt;p&gt;The model helps understand the request. The application logic is responsible for turning that interpretation into a plan in a predictable structure.&lt;/p&gt;

&lt;p&gt;That makes the system easier to reason about, test, and improve independently.&lt;/p&gt;

&lt;p&gt;It also avoids treating every model response as something the application should automatically trust.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens when the AI endpoint is unavailable?
&lt;/h3&gt;

&lt;p&gt;An application shouldn't become completely unusable just because an AI service is unavailable.&lt;/p&gt;

&lt;p&gt;Outside includes a local heuristic fallback for supported requests. When the configured model endpoint cannot be used, this fallback can handle the requests it supports.&lt;/p&gt;

&lt;p&gt;It isn't equivalent to a language model's flexible interpretation, and I don't want to pretend otherwise.&lt;/p&gt;

&lt;p&gt;Its purpose is to preserve basic functionality rather than leave the user with a broken experience.&lt;/p&gt;

&lt;p&gt;This was an important architectural principle for me: AI should improve the experience, but the application should still behave honestly when AI isn't available.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔓 9. Exploring open-weight AI with Gemma
&lt;/h2&gt;

&lt;p&gt;Outside also gave me an opportunity to explore open-weight AI models in a practical application.&lt;/p&gt;

&lt;p&gt;The project supports Gemma-compatible integration through an OpenAI-compatible endpoint, including a local configuration using Ollama.&lt;/p&gt;

&lt;p&gt;When configured to use a local model, the application can perform its language-model inference on the user's machine rather than depending on a hosted AI service for that step.&lt;/p&gt;

&lt;p&gt;This is useful for experimentation, flexibility, and privacy-conscious development.&lt;/p&gt;

&lt;p&gt;It also comes with trade-offs.&lt;/p&gt;

&lt;p&gt;Local inference depends on the available hardware, the selected model, and its configuration. Response speed and output quality can differ from a hosted setup.&lt;/p&gt;

&lt;p&gt;The important part is that the model isn't an unexplained black box sitting behind the interface. Its responsibility is clearly defined within the larger application.&lt;/p&gt;

&lt;p&gt;I wanted to explore how an open-weight model could contribute to a small, focused product without allowing the model to dictate the entire user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  🛠️ 10. How I built Outside
&lt;/h2&gt;

&lt;p&gt;The application uses a combination of frontend development, AI integration, deterministic application logic, and browser-based persistence.&lt;/p&gt;

&lt;p&gt;Here's the role each part plays.&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;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;React&lt;/td&gt;
&lt;td&gt;Builds the interactive user interface.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TypeScript&lt;/td&gt;
&lt;td&gt;Makes application data and logic easier to reason about through static types.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma-compatible integration&lt;/td&gt;
&lt;td&gt;Interprets natural-language activity requests when the model endpoint is configured.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deterministic activity engine&lt;/td&gt;
&lt;td&gt;Organizes the interpreted intent into a structured plan.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local heuristic fallback&lt;/td&gt;
&lt;td&gt;Supports basic planning when the configured AI endpoint is unavailable.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser local storage&lt;/td&gt;
&lt;td&gt;Persists saved activity history and reflections locally in the browser.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One lesson from this project is that the quality of an AI application depends on more than the model itself.&lt;/p&gt;

&lt;p&gt;The surrounding application determines how requests are handled, how model outputs are used, what happens when something fails, and how the result is presented to the user.&lt;/p&gt;

&lt;p&gt;A useful AI feature needs that supporting engineering to work well.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔒 11. Privacy: local-first doesn't mean every setup is identical
&lt;/h2&gt;

&lt;p&gt;Privacy is particularly relevant when an application may receive information about a person's mood, preferences, or personal reflections.&lt;/p&gt;

&lt;p&gt;Outside stores saved history and reflections in browser local storage. It can also use a local model endpoint for inference.&lt;/p&gt;

&lt;p&gt;When inference happens locally, the prompt for that model interaction does not need to be sent to a hosted AI service.&lt;/p&gt;

&lt;p&gt;However, the actual privacy properties depend on the configuration.&lt;/p&gt;

&lt;p&gt;If a remote endpoint is used, the information sent to that endpoint may be processed by the provider. Browser storage also isn't the same as encrypted storage or a secure backup system.&lt;/p&gt;

&lt;p&gt;I think it's important to explain those distinctions instead of describing every possible configuration as completely private.&lt;/p&gt;

&lt;p&gt;The goal is to give users a clear understanding of where their data goes and what their setup actually does.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎨 11. Designing an application that doesn't compete for attention
&lt;/h2&gt;

&lt;p&gt;The interface is part of the idea, not merely a wrapper around the AI.&lt;/p&gt;

&lt;p&gt;If the goal is to encourage people to spend less time looking at their phones, it would be contradictory to build a cluttered experience full of distractions.&lt;/p&gt;

&lt;p&gt;I wanted Outside to feel calm and focused.&lt;/p&gt;

&lt;p&gt;The user should understand what to do next without navigating a complicated dashboard. Planning should be straightforward, the activity should be clear, and leaving the screen should feel like a natural part of the experience.&lt;/p&gt;

&lt;p&gt;That principle influenced how I thought about the interface and the overall flow.&lt;/p&gt;

&lt;p&gt;It also provides a useful design constraint for future features: any new functionality should make the outdoor experience better, not simply give users another reason to stay in the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚧 13. What I would like to improve
&lt;/h2&gt;

&lt;p&gt;Outside is an experiment in using AI to support a real-world behavior, and there is plenty of room to improve it.&lt;/p&gt;

&lt;p&gt;Some areas I'd like to explore include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;More adaptive activities:&lt;/strong&gt; Better handling of different time constraints, preferences, and energy levels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better activity quality:&lt;/strong&gt; Making generated plans practical, varied, and appropriate for the user's stated intent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility:&lt;/strong&gt; Designing activities and interfaces that work for people with different needs and abilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local-model experience:&lt;/strong&gt; Improving setup guidance and making the distinction between model-generated results and fallback results clear.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reflection:&lt;/strong&gt; Exploring ways to make post-activity reflection useful without turning it into another obligation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would also like to evaluate the experience with more users and learn whether the activities genuinely help people take that first step outside.&lt;/p&gt;

&lt;p&gt;That is a more meaningful measure of progress than simply counting how many times someone opens the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 13. Try it yourself
&lt;/h2&gt;

&lt;p&gt;Outside is my contribution to the DEV Community's Hacktoberfest Open-Source AI Challenge, Week 1: &lt;strong&gt;Touch Grass&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The project explores a simple question: can we use AI to help people spend less time interacting with technology and more time experiencing the world around them?&lt;/p&gt;

&lt;p&gt;You can explore the working application, watch the demo, or inspect the source code.&lt;/p&gt;

&lt;p&gt;🌐 &lt;strong&gt;Live application:&lt;/strong&gt; &lt;a href="https://outside-lmth.onrender.com" rel="noopener noreferrer"&gt;https://outside-lmth.onrender.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🎬 &lt;strong&gt;Demo video:&lt;/strong&gt; &lt;a href="https://youtu.be/umWsHyiBCoo" rel="noopener noreferrer"&gt;https://youtu.be/umWsHyiBCoo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💻 &lt;strong&gt;GitHub repository:&lt;/strong&gt; &lt;a href="https://github.com/tribhu05/outside" rel="noopener noreferrer"&gt;https://github.com/tribhu05/outside&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you'd like to run the project locally, check the repository's README for the current setup instructions.&lt;/p&gt;

&lt;p&gt;I'd especially appreciate feedback on three questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Do the activity suggestions feel practical enough to use during an ordinary day?&lt;/li&gt;
&lt;li&gt;Do the sensory challenges make a short walk more engaging?&lt;/li&gt;
&lt;li&gt;Does the transition into GO OUTSIDE mode feel natural, or is there anything that would make it easier to put the phone away?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'm also interested in contributions that improve the planning logic, accessibility, local-model integration, and overall user experience.&lt;/p&gt;




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

&lt;h3&gt;
  
  
  1. Best Use of Render (Featured Category)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live Deployment:&lt;/strong&gt; &lt;a href="https://outside-lmth.onrender.com" rel="noopener noreferrer"&gt;https://outside-lmth.onrender.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration:&lt;/strong&gt; Declarative &lt;a href="https://github.com/tribhu05/outside/blob/master/render.yaml" rel="noopener noreferrer"&gt;&lt;code&gt;render.yaml&lt;/code&gt;&lt;/a&gt; blueprint specification in repository root.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why Render was chosen:&lt;/strong&gt;&lt;br&gt;
Outside is engineered around reducing friction. When someone has an unexpected 15-minute gap between meetings, waiting for a 100 MB native app store download or enduring a cold start guarantees they will stay on their phone. Deployed on Render's global static web hosting infrastructure with an automated Vite 6 CI/CD pipeline (&lt;code&gt;tsc -b &amp;amp;&amp;amp; vite build&lt;/code&gt;), Outside loads in sub-second time on mobile browsers. Render provides the zero-maintenance, zero-cost edge delivery needed to get the user their plan in seconds so they can pocket the device.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Best Use of Gemma (Featured Category)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model:&lt;/strong&gt; Google Gemma 2 open weights (&lt;code&gt;gemma2:2b&lt;/code&gt; via Ollama / OpenAI-compatible endpoint)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Role:&lt;/strong&gt; Natural language intent extraction &amp;amp; sensory objective synthesis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why Gemma was chosen:&lt;/strong&gt;&lt;br&gt;
Commercial closed APIs suffer from an inherent conflict of interest: their parent platforms profit from engagement, retention, and time-on-screen. Gemma gives us complete sovereign control:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Anti-Screen System Guard:&lt;/strong&gt; We tuned the system prompt with strict negative constraints so Gemma strictly refuses to recommend screen-based outdoor tasks (like taking photos, checking plant apps, or listening to podcasts).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;True Park &amp;amp; Backcountry Offline Capability:&lt;/strong&gt; Running &lt;code&gt;gemma2:2b&lt;/code&gt; on-device via Ollama allows users to put their phone on Airplane Mode (or walk through urban parks with zero cellular signal) without losing the ability to plan a walk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Emotional Privacy:&lt;/strong&gt; Personal reflections (&lt;em&gt;"feeling anxious and overwhelmed"&lt;/em&gt;) never touch a third-party corporate server.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  3. Best Use of GitHub Copilot (Partner Category)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Role in Build:&lt;/strong&gt; AI-pair programming, test suite generation, and mathematical validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How GitHub Copilot shaped the architecture:&lt;/strong&gt;&lt;br&gt;
GitHub Copilot was an active pair programmer throughout the development of Outside, specifically handling three critical technical challenges:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scaffolding Comprehensive Test Coverage:&lt;/strong&gt; Copilot helped generate the &lt;strong&gt;53 Vitest unit tests and 52 Puppeteer E2E tests&lt;/strong&gt; in the &lt;code&gt;tests/&lt;/code&gt; directory, verifying that every state transition in the &lt;code&gt;GO OUTSIDE&lt;/code&gt; mode and local heuristic engine behaves deterministically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Synthesizing the Web Audio Bell:&lt;/strong&gt; Rather than bundling heavy audio MP3/WAV assets that consume cellular bandwidth on the trail, Copilot assisted in writing a pure Web Audio API synthesizer that mathematically generates a calming 432 Hz harmonic singing bowl chime directly in browser memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Designing the Deterministic Fallback Logic:&lt;/strong&gt; Copilot accelerated authoring the TypeScript types and regex-based fallback parser, ensuring that even if local Ollama inference is switched off, the app never crashes.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  4. Best Use of DigitalOcean (Featured Category)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Target:&lt;/strong&gt; DigitalOcean Serverless Inference for Open-Weight Models&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Endpoint Compatibility:&lt;/strong&gt; &lt;code&gt;https://inference.do-ai.run/v1/chat/completions&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How it integrates:&lt;/strong&gt;&lt;br&gt;
While Outside defaults to on-device Ollama for local privacy, it was engineered with an OpenAI-compatible client abstraction. By pointing the endpoint configuration to DigitalOcean's Serverless GenAI Inference running &lt;code&gt;gemma-4-31B-it&lt;/code&gt; or &lt;code&gt;gemma-2-9b-it&lt;/code&gt;, Outside can be served to users whose laptops or phones cannot run local inference, without requiring the developer to provision, manage, or pay for idling GPU droplets.&lt;/p&gt;

&lt;h2&gt;
  
  
  🌿 One last thought
&lt;/h2&gt;

&lt;p&gt;Technology is becoming increasingly good at capturing our attention.&lt;/p&gt;

&lt;p&gt;I wanted to experiment with a different direction.&lt;/p&gt;

&lt;p&gt;What if an AI application helped you make a plan, gave you a small reason to explore, and then encouraged you to stop using it?&lt;/p&gt;

&lt;p&gt;Not because the technology failed to keep you engaged.&lt;/p&gt;

&lt;p&gt;Because it succeeded at helping you do something else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Less scrolling. More living. 🌿&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  devchallenge #hf26challenge #ai #opensource
&lt;/h1&gt;

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