<?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: Penta Dank</title>
    <description>The latest articles on DEV Community by Penta Dank (@pentadank).</description>
    <link>https://dev.to/pentadank</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%2F3145348%2F08d18db4-cffc-4612-ac2a-463b1348152d.jpg</url>
      <title>DEV Community: Penta Dank</title>
      <link>https://dev.to/pentadank</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pentadank"/>
    <language>en</language>
    <item>
      <title>Please Hold: the customer-service call you keep putting off, written by a Gemma that isn't allowed to make things up</title>
      <dc:creator>Penta Dank</dc:creator>
      <pubDate>Sun, 25 Oct 2026 18:25:36 +0000</pubDate>
      <link>https://dev.to/pentadank/please-hold-the-customer-service-call-you-keep-putting-off-written-by-a-gemma-that-isnt-allowed-45mj</link>
      <guid>https://dev.to/pentadank/please-hold-the-customer-service-call-you-keep-putting-off-written-by-a-gemma-that-isnt-allowed-45mj</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19"&gt;Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Everybody has one. The charge you meant to dispute. The subscription that renewed after you cancelled. The bill that went up $30 with no warning. You know exactly what you want. You just don't want to sit through the phone tree, explain it three times, and remember to ask for a reference number.&lt;/p&gt;

&lt;p&gt;Before I built anything this week, I had an agent go read what people actually complain about online. The loudest category wasn't sleep or inboxes. It was dealing with companies. A February 2026 Groundwork Collaborative study, &lt;a href="https://www.fortune.com/2026/02/19/americans-paying-over-165-billion-annually-vibes-based-taxes-annoyance-economy" rel="noopener noreferrer"&gt;reported by Fortune&lt;/a&gt;, puts the "annoyance economy" at about $165 billion a year and finds Americans spend 60% more time on customer-service calls than 20 years ago. On &lt;a href="https://www.trustpilot.com/review/www.calm.com" rel="noopener noreferrer"&gt;Trustpilot&lt;/a&gt;, Calm sits at 1.4 out of 5, and the reviews are mostly billing traps: "They charged me $85 for a free trial and then refused a refund."&lt;/p&gt;

&lt;p&gt;Then I checked this challenge's tag. Around 545 Week 3 posts: a lot of file sorters, a lot of inbox digests, and four bedtime companions, which was the idea I'd planned to build. Nobody had taken the customer's side of the phone call.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Please Hold&lt;/strong&gt; does. You type one sentence:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lumen Fitness charged me $49.99 on Oct 3 even though I cancelled on Sept 28. Member #448210. I want it refunded.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and get back the whole errand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A phone script&lt;/strong&gt; in your voice: the first thing to say, the exact ask, three polite lines for when they say no, and how to close (agent's name, reference number, what was agreed).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An email and a chat message&lt;/strong&gt;, ready to send.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your leverage.&lt;/strong&gt; Short, sourced consumer-rights pointers for the US, UK and EU that match the errand. I wrote these by hand. The model never writes them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hold mode.&lt;/strong&gt; A full-screen card with your script, a hold timer, and calm hold music generated on your device. Your hold music, not theirs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After the call.&lt;/strong&gt; Type the agent's name and reference number, and it writes the confirmation email and a calendar reminder to check they actually did it. No model in this step, so nothing gets made up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gemma runs &lt;strong&gt;on your own computer&lt;/strong&gt; through Ollama. Your account numbers, your address, the money you're owed: none of it leaves your machine. If you just want to try it on a phone, there's an opt-in cloud mode, clearly labeled.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://please-hold.dankpenta.workers.dev" rel="noopener noreferrer"&gt;https://please-hold.dankpenta.workers.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To keep everything local, install &lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;, run &lt;code&gt;ollama pull gemma3:4b&lt;/code&gt;, and start it with the site allowed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;OLLAMA_ORIGINS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://please-hold.dankpenta.workers.dev ollama serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Or pick &lt;strong&gt;Gemma 4 26B on Cloudflare&lt;/strong&gt; to try it on any device right now.&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%2Fuwjehm8fmais39juj6tl.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%2Fuwjehm8fmais39juj6tl.png" alt="A finished kit: receipts summary, the ask, and the phone script" width="800" height="1586"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnsber5gur03gyyxgtyg1.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%2Fnsber5gur03gyyxgtyg1.png" alt="Hold mode: timer, your script, your own hold music" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F80mdg98m3uhlpsanbw2d.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%2F80mdg98m3uhlpsanbw2d.png" alt="After the call: a confirmation email written from your own notes" width="800" height="1545"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Screenshots from a run on my laptop with &lt;code&gt;gemma3:4b&lt;/code&gt; in Ollama. The ledger numbers are from that test run.&lt;/em&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/5thlegend" rel="noopener noreferrer"&gt;
        5thlegend
      &lt;/a&gt; / &lt;a href="https://github.com/5thlegend/please-hold" rel="noopener noreferrer"&gt;
        please-hold
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Please Hold&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Type the customer-service errand you've been avoiding. Get everything you need to finish it in one call.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Live: &lt;a href="https://please-hold.dankpenta.workers.dev" rel="nofollow noopener noreferrer"&gt;https://please-hold.dankpenta.workers.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You write one sentence, like &lt;em&gt;"Lumen Fitness charged me $49.99 on Oct 3 even though I cancelled on Sept 28. Member #448210. I want it refunded."&lt;/em&gt; Please Hold gives you back:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A phone script:&lt;/strong&gt; the first thing to say, the exact ask, three polite lines for when they say no, and how to close the call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An email&lt;/strong&gt; and a &lt;strong&gt;chat message&lt;/strong&gt;, ready to send.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your leverage:&lt;/strong&gt; hand-written, sourced consumer-rights pointers (US, UK, EU) that match the errand. These are never written by the model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hold mode:&lt;/strong&gt; a full-screen card with your script, a hold timer, and calm hold music generated on your device.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After the call:&lt;/strong&gt; log the agent's name and reference number, then get a confirmation email and a calendar reminder to check they actually did…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/5thlegend/please-hold" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;MIT licensed. Plain HTML, CSS and ES modules, no build step. One small Cloudflare Worker for the opt-in cloud route.&lt;/p&gt;
&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;
&lt;h3&gt;
  
  
  The model writes words, never facts
&lt;/h3&gt;

&lt;p&gt;Small models are helpful in the worst way. Ask one for a cancellation email and it may add a support phone number, a "within 5 business days" promise, or a consumer protection act. None of that came from you, and some of it is invented. On a customer-service call that's not a style problem. Read a made-up policy to an agent and you've lost the call.&lt;/p&gt;

&lt;p&gt;So Please Hold never trusts the model's output. It runs two passes, then checks the receipts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pass 1, extract.&lt;/strong&gt; Gemma pulls out the company, the errand type, and the facts, each with a quote from your sentence. A fact survives only if its quote really is your words, or if every number in it matches what you typed and most of its words are yours. Anything else is dropped before a word gets written.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pass 2, write.&lt;/strong&gt; Gemma writes the email, chat message and phone script from the surviving facts only, in your voice. Unknowns become &lt;code&gt;[ORDER NUMBER]&lt;/code&gt;-style blanks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The receipts check.&lt;/strong&gt; Plain JavaScript, no model, finds every checkable claim in the output (phone numbers, URLs, emails, amounts, dates, durations, percentages, account numbers, legal-sounding phrases) and compares each one against your own words.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// public/js/verify.js (trimmed)&lt;/span&gt;
&lt;span class="k"&gt;for &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;c&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;findClaims&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;))&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;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;isVerified&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;verified&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;                       &lt;span class="c1"&gt;// it's in what you typed&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;catchable&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;caught&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;           &lt;span class="c1"&gt;// phone/URL/email you never gave: replaced&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unverified&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                    &lt;span class="c1"&gt;// number, date, deadline, law: highlighted&lt;/span&gt;
  &lt;span class="nx"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;caught&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;PLACEHOLDER&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;status&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;On screen, anything from your words gets a dotted underline. An invented phone number is removed and replaced with &lt;em&gt;[COMPANY PHONE — copy it from your bill]&lt;/em&gt;. Anything else you didn't say is highlighted yellow so you check it before you read it to a stranger.&lt;/p&gt;

&lt;p&gt;Both passes use &lt;strong&gt;structured output&lt;/strong&gt;: the JSON schema goes to the model, so it can only produce the fields the app expects (Ollama's &lt;code&gt;format&lt;/code&gt;, Workers AI's &lt;code&gt;response_format&lt;/code&gt;).&lt;/p&gt;
&lt;h3&gt;
  
  
  The parts I wrote by hand
&lt;/h3&gt;

&lt;p&gt;Anything that has to be right isn't generated. That covers the consumer-rights pointers, each checked against an official page (&lt;a href="https://consumer.ftc.gov/articles/using-credit-cards-and-disputing-charges" rel="noopener noreferrer"&gt;FTC&lt;/a&gt;, &lt;a href="https://europa.eu/youreurope/citizens/consumers/shopping/returns/index_en.htm" rel="noopener noreferrer"&gt;Your Europe&lt;/a&gt;, &lt;a href="https://www.citizensadvice.org.uk/about-us/media-centre/press-releases/citizens-advice-top-tips-for-safe-and-savvy-consumers-on-black-friday/" rel="noopener noreferrer"&gt;Citizens Advice&lt;/a&gt;). It also covers the "getting to a human" tips, the follow-up email built from your call log, and the &lt;code&gt;.ics&lt;/code&gt; reminder. The hold music is four slow major-seventh chords and a soft bell, generated live with the Web Audio API. No audio files.&lt;/p&gt;
&lt;h3&gt;
  
  
  Where Gemma runs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Where your text goes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Your computer (default when found)&lt;/td&gt;
&lt;td&gt;any Gemma in Ollama, e.g. &lt;code&gt;gemma3:4b&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Nowhere&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloudflare (opt-in)&lt;/td&gt;
&lt;td&gt;Gemma 4 26B A4B on Workers AI&lt;/td&gt;
&lt;td&gt;Cloudflare. The app doesn't store or log it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  What broke: I tried to put Gemma in the browser
&lt;/h2&gt;

&lt;p&gt;My plan was for Gemma to run inside the tab with nothing to install. I spent most of an afternoon on it, and it didn't ship. Here's what happened on my laptop (RTX 4050 6 GB, 16 GB RAM, Chrome):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gemma 4 E2B on WebLLM 0.2.86&lt;/strong&gt;, the first WebLLM release with Gemma 4, lost the WebGPU device on the first token. So did every other model on 0.2.86. 0.2.85 is stable but has no Gemma 4.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemma 4 E2B on Transformers.js 4.3.0&lt;/strong&gt; downloaded all ~3.3 GB of weights, then the tab crashed loading them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemma 3 1B on WebLLM 0.2.85&lt;/strong&gt; runs, but it's too small for this job. Under a JSON grammar it printed whitespace until it hit the token limit. Without one, it echoed my prompt back, or worse: it answered with a refund for "$10.99 on Oct 28." The user had typed $49.99 and Oct 3.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one is the whole argument for the receipts check, made by the model itself. It's still in the app behind &lt;code&gt;?lab=1&lt;/code&gt; if you want to watch it struggle.&lt;/p&gt;

&lt;p&gt;Two bugs from that detour that you might hit too:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hugging Face rejects &lt;code&gt;*.workers.dev&lt;/code&gt; referrers.&lt;/strong&gt; WebLLM said &lt;code&gt;Failed to execute 'open' on 'CacheStorage'&lt;/code&gt;, then &lt;code&gt;Failed to fetch&lt;/code&gt;. Chrome said CORS, and curl said everything was fine. Replaying Chrome's exact request one header at a time showed it: Hugging Face returns 404 with no CORS headers to any model download whose &lt;code&gt;Referer&lt;/code&gt; is a &lt;code&gt;*.workers.dev&lt;/code&gt; page. The fix is one line, &lt;code&gt;&amp;lt;meta name="referrer" content="no-referrer"&amp;gt;&lt;/code&gt; (plus the matching &lt;code&gt;Referrer-Policy&lt;/code&gt; header).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebLLM's prebuilt Gemma 3 1B config rejects itself.&lt;/strong&gt; It sets both a 4096 context and a 512 sliding window, and WebLLM refuses that combination. &lt;code&gt;chatOpts: { context_window_size: 4096, sliding_window_size: -1 }&lt;/code&gt; gets it to load.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the local path is Ollama. It's one install, and the model then runs on your own GPU with native CUDA.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does it actually behave?
&lt;/h2&gt;

&lt;p&gt;I wrote 24 realistic errands (refunds, cancellations, a lost suitcase, a pharmacy overcharge, a security deposit, a free trial about to convert, an errand where the person doesn't know their account number), ran each through the full pipeline on both backends, and counted what the receipts check found.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Runs on&lt;/th&gt;
&lt;th&gt;Errands&lt;/th&gt;
&lt;th&gt;Claims checked&lt;/th&gt;
&lt;th&gt;Matched your words&lt;/th&gt;
&lt;th&gt;Flagged for you&lt;/th&gt;
&lt;th&gt;Invented contact details&lt;/th&gt;
&lt;th&gt;Avg time per kit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 26B&lt;/td&gt;
&lt;td&gt;Cloudflare Workers AI&lt;/td&gt;
&lt;td&gt;24/24&lt;/td&gt;
&lt;td&gt;169&lt;/td&gt;
&lt;td&gt;165&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;12.8 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 3 4B&lt;/td&gt;
&lt;td&gt;my laptop, via Ollama&lt;/td&gt;
&lt;td&gt;24/24&lt;/td&gt;
&lt;td&gt;155&lt;/td&gt;
&lt;td&gt;151&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;16.7 s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All eight flags were Gemma doing arithmetic. "My bill went from $65 to $95" became "the $30 increase," and "$120 for a prescription that's supposed to be $10" became "a $110 refund." The math is right, but you never said $30, so it's highlighted for you to confirm. The check doesn't decide what's true. It shows you what didn't come from you.&lt;/p&gt;

&lt;p&gt;Neither model invented a phone number on this set. I'd still never ship without the check, after watching the 1B model invent a whole charge on its first try. The local model also had 6 extracted facts dropped for not matching the user's words, before they could reach the email.&lt;/p&gt;

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

&lt;p&gt;Across the 24 errands, you type about 19 words and Please Hold writes about 220: an email, a chat message, and a four-part phone script with your facts already in it. Each kit takes 13–17 seconds on average.&lt;/p&gt;

&lt;p&gt;The app keeps a &lt;strong&gt;lazy ledger&lt;/strong&gt; in your browser: errands finished, time spent on hold, words you didn't have to write, and money recovered.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The sensitive part is the data.&lt;/strong&gt; A customer-service errand is account numbers, addresses, and money owed. With open weights on your own machine, that text is never sent anywhere. It isn't a "we don't store it" promise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No subscription, for an app about subscription traps.&lt;/strong&gt; The thing people hate most about the incumbents is getting charged. A model on your own GPU costs nothing per errand, forever.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I can hold it to account because I can run it.&lt;/strong&gt; Open weights plus open runtimes let me force a JSON schema, run the same model family locally or in the cloud, and check every output with my own code. The honesty system is mine, not a vendor setting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You choose where it runs.&lt;/strong&gt; The same Gemma family runs on a laptop GPU through Ollama, or on Cloudflare when you're on a phone. Open weights make that a radio button, not a migration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where open beat closed, and where it didn't.&lt;/strong&gt; A frontier API would write smoother emails. It would also send your account details to one company so you can argue with another. And open isn't magic: the in-browser route wasn't ready on my hardware this week. Small, local, and checked was the right trade for this job.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What it doesn't do
&lt;/h2&gt;

&lt;p&gt;It doesn't make the call for you, and it doesn't give legal advice. The rights pointers are general information with links to the official source. The local 4B model writes plainer prose than the cloud one, and that's why the checks exist.&lt;/p&gt;

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

&lt;p&gt;I built this with an AI agent in one long sitting, from "go research what people actually complain about" to deploy. The session shows the research that killed my first idea, the rule that the model writes words and never facts, the Referer bug, and the in-browser attempts that didn't make it.&lt;/p&gt;


&lt;div class="ltag-agent-session"&gt;
  &lt;div class="agent-session-header"&gt;
    
    &lt;span class="agent-session-tool-icon-badge" title="Claude Code"&gt;
&lt;/span&gt;
    &lt;span class="agent-session-title"&gt;Please Hold: from 'what are people complaining about?' to a local Gemma errand kit&lt;/span&gt;
  &lt;/div&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Bring my Hacktoberfest run up to date for the week of 2026-10-20 and ship this week's entry. Week 3 'Slow and Steady' is open: build something with open-weight models / open-source AI that rewards laziness. Pitch 3 concepts that fit my strengths (local-first open-weight AI like Storyhouse/Lore Walk), let me pick, build it, deploy it, save the session, draft the DEV post. Never publish or register without my yes.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-getchallenges"&gt;get_challenges&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;DevRelay&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;DevRelay&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Week 3 'Slow and Steady' (Oct 19-25, due Sat 11:59 PM PDT). Writing quality weighted most. Post must explain why open innovation matters and show the lazy payoff.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-searchmlhevents"&gt;search_mlh_events&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Open-Source AI Challenge&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Open-Source AI Challenge&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;MLH event 'Hacktoberfest Open-Source AI Challenge: Week 3' exists; not registered yet.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Pitched three: an offline wind-down companion that slows down with you, a local file tidier, and fridge-photo-to-grocery-list. Recommended the wind-down companion.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Go out on the internet and deep research what people are complaining about in this area or theme and we can come up with ideas to reward their laziness.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Ran four parallel research tracks (life admin, household/food, sleep and wind-down, developer drudgery plus the competition), then a report writer combined them into one ranked report.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-researchlifeadmin"&gt;research: life admin&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;HN, r/ADHD snapshots, Trustpilot, surveys&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;HN, r/ADHD snapshots, Trustpilot, surveys&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Top pains: customer-service calls and hold time, insurance/medical paperwork, subscription cancelling. Groundwork Collaborative (Feb 2026): $165B/yr 'annoyance economy', call time up 60% in 20 years.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-researchsleep"&gt;research: sleep&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Trustpilot, app stores, AASM, Talker Research&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Trustpilot, app stores, AASM, Talker Research&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Calm 1.4/5 on Trustpilot (492 reviews, 78% one-star), mostly billing traps: 'They charged me $85 for a free trial and then refused a refund'.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-researchcompetition"&gt;research: competition&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;dev.to #hf26challenge&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;dev.to #hf26challenge&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;~545 Week 3 entries. ~119 file sorters, ~80 summarizers, ~48 inbox/chat digests.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-searchdevtosemantic"&gt;search_dev_to_semantic&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;hf26challenge bedtime sleep wind-down offline&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;hf26challenge bedtime sleep wind-down offline&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Sloth Companion, SnoozeScape, Compline, SlumberSafe: the bedtime idea is already taken.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-searchdevtosemantic"&gt;search_dev_to_semantic&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;hf26challenge fridge / timesheet / insurance letter&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;hf26challenge fridge / timesheet / insurance letter&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Fridge: 4+ this week. Timesheet: 'lowkey' did it in Week 2. Letter decoder: Week 2.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-searchdevtosemantic"&gt;search_dev_to_semantic&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;hf26challenge cancel subscription customer service call script&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;hf26challenge cancel subscription customer service call script&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;No Week 3 entry on the consumer side of customer-service errands.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;My original pick was already taken four times. The most-complained-about pain (calling a company to cancel, refund, or dispute) had no Week 3 entry. New pitch: Please Hold. One sentence in, the whole errand kit out, written on your device.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Build Please Hold — the local customer-service errand kit.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;HF API: onnx-community + mlc-ai gemma models; npm view @mlc-ai/web-llm&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ HF API: onnx-community + mlc-ai gemma models; npm view @mlc-ai/web-llm&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;gemma-4-E2B-it-q4f16_1-MLC (2.8 GB, 3.4 GB VRAM) is in WebLLM 0.2.86 but not 0.2.85. gemma3-1b-it (0.6 GB) in both. Workers AI has @cf/google/gemma-4-26b-a4b-it.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Decision: on-device Gemma 4 E2B through WebLLM as the default (pinned and vendored 0.2.86), Gemma 3 1B as a light option, the user's own Ollama, and an opt-in cloud fallback (Gemma 4 26B on Workers AI) for browsers without WebGPU. Same open model family, the user picks where it runs.&lt;/p&gt;

                &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Design rule: the model writes words, never facts. Pass 1 extracts facts and must quote the user word for word. Pass 2 writes the kit only from verified facts. Then a deterministic 'receipts check' scans every phone number, URL, email, amount, date, duration, percentage, account number and legal-sounding phrase, and compares it to the user's own text. Invented contact details get replaced with a placeholder; other unverified claims are highlighted. Consumer-rights pointers, IVR tips, the follow-up email and the calendar reminder are written by hand, with no model involved.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;node test/verify.test.mjs&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ node test/verify.test.mjs&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;verify: all checks passed&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Workers AI REST: gemma-4-26b-a4b-it with json_schema response_format&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Workers AI REST: gemma-4-26b-a4b-it with json_schema response_format&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;200 in 5.6s. Clean JSON, but facts came back as fragments ('on Oct 3'). Fixed the prompt: each fact is one short third-person sentence.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-webfetch"&gt;WebFetch&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;consumer.ftc.gov/articles/using-credit-cards-and-disputing-charges&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;consumer.ftc.gov/articles/using-credit-cards-and-disputing-charges&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;'Send your letter so that it reaches the issuer within 60 days after the first bill with the error was sent to you.' Rewrote the US leverage text to match. Two Citizens Advice URLs 404'd; swapped them for a live Citizens Advice page that states the 14-day and 30-day rules.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;npx wrangler deploy&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ npx wrangler deploy&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;https://please-hold.dankpenta.workers.dev&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;node test/eval-cloud.mjs (24 realistic errands)&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ node test/eval-cloud.mjs (24 realistic errands)&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;24/24 ok. 178 checkable claims: 174 matched the user's words, 0 invented contact details, 4 flagged ($110, a difference Gemma calculated from $120 and $10, which isn't in the user's words). Avg 17s per kit, ~216 words written per errand.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-browser"&gt;browser&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;on-device run in the in-app browser&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;on-device run in the in-app browser&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Blocked: the sandboxed browser pane can't reach huggingface.co for the weights. Switched to Playwright driving real Chrome on the RTX 4050.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-playwright"&gt;Playwright&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;CreateMLCEngine('gemma-4-E2B-it-q4f16_1-MLC')&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;CreateMLCEngine('gemma-4-E2B-it-q4f16_1-MLC')&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;UnknownError: Failed to execute 'open' on 'CacheStorage'. My IndexedDB fallback used the old option name (useIndexedDBCache); WebLLM 0.2.86 renamed it to cacheBackend: 'indexeddb'. Fixed and redeployed.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-playwright"&gt;Playwright&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;fetch(huggingface.co/.../mlc-chat-config.json) from the app&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;fetch(huggingface.co/.../mlc-chat-config.json) from the app&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Still 'Failed to fetch': CORS, no Access-Control-Allow-Origin. The cache error had been a red herring. Direct navigation to the same URL works.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;curl with Chrome's exact headers, varying one at a time&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ curl with Chrome's exact headers, varying one at a time&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Referer: https://please-hold.dankpenta.workers.dev/ -&amp;gt; 404 from CloudFront (no CORS headers). No Referer -&amp;gt; 302. Referer: https://example.com/ -&amp;gt; 302. Hugging Face rejects downloads referred by *.workers.dev pages.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Fix: &amp;lt;meta name="referrer" content="no-referrer"&amp;gt; plus a Referrer-Policy: no-referrer header in public/_headers. One line each. Re-probe: all three files 200.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-playwright"&gt;Playwright&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Gemma 4 E2B on WebLLM 0.2.86, RTX 4050, real Chrome&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Gemma 4 E2B on WebLLM 0.2.86, RTX 4050, real Chrome&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Model loaded (428s, 2.8 GB). First generated token: 'Failed to execute mapAsync on GPUBuffer: A valid external Instance reference no longer exists.' The WebGPU device was lost. Same with Gemma 3 1B on 0.2.86, even for a 40-token plain-text reply.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-playwright"&gt;Playwright&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Same Gemma 3 1B on WebLLM 0.2.85&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Same Gemma 3 1B on WebLLM 0.2.85&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Works: 2.2s plain, 5.3s with a JSON schema. 0.2.86 is the regression, and it's the only version with Gemma 4.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-playwright"&gt;Playwright&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Gemma 3 1B on the real facts prompt (341 tokens)&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Gemma 3 1B on the real facts prompt (341 tokens)&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Under the JSON grammar: '{"company"' followed by 1,200 characters of whitespace. Without a grammar: echoes '---' or the prompt. With a system role it answered about a refund 'of $10.99 on Oct 28'. The user typed $49.99 and Oct 3. Too small for this job, so it moved behind ?lab=1.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-playwright"&gt;Playwright&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Gemma 4 E2B via Transformers.js 4.3.0 (+esm build)&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Gemma 4 E2B via Transformers.js 4.3.0 (+esm build)&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;All weights downloaded (~3.3 GB), then the tab crashed while loading them. 16 GB RAM, 2.5 GB free.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Decision: the local path is Ollama (native CUDA). It's the default whenever the site detects it, the cloud is opt-in, and the in-browser path stays behind a flag with an honest write-up. Added an in-app message for GPU resets and a copyable OLLAMA_ORIGINS command for Mac/Linux and Windows.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;node test/eval-ollama.mjs gemma3:4b (first run)&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ node test/eval-ollama.mjs gemma3:4b (first run)&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;24/24, 110 of 111 claims matched, 0 invented contacts, but 10 facts dropped. They were mostly false positives: the model 'quoted' its own paraphrase ('They were charged $120 for a prescription').&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Loosened checkFacts: a fact is kept if its quote really is the user's words, or if every number in it checks out and at least 60% of its content words are the user's. Added unit tests for both, including one where a fact with an invented $140 still gets dropped.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-read"&gt;Read&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;docs/shots/02-kit.png&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;docs/shots/02-kit.png&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;The phone opener came out in the agent's voice: 'Thank you for contacting Lumen Fitness... I'm here to assist you today.' Fixed the prompt to say everything is in the CUSTOMER's voice, said TO the company. The goal and fallback are now short phrases, and the 'have these ready' items are plain lowercase.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;final evals, both backends, final prompts&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ final evals, both backends, final prompts&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Gemma 4 26B (Workers AI): 24/24, 165 of 169 claims matched, 4 flagged, 0 invented contacts, 12.8s avg. Gemma 3 4B (Ollama, RTX 4050): 24/24, 151 of 155 matched, 4 flagged, 0 invented contacts, 6 facts dropped, 16.7s avg. All 8 flags were Gemma's own arithmetic ($95 - $65 = '$30', $120 - $10 = '$110'), so they're highlighted for the user to confirm.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
  &lt;/div&gt;

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


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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma:&lt;/strong&gt; Gemma is the whole engine. Gemma 3 4B runs locally through Ollama, and Gemma 4 26B on Workers AI is the opt-in fallback. Both are held to the same receipts check, and both are measured on the same 24 errands above.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>gemma</category>
      <category>opensource</category>
    </item>
    <item>
      <title>LORE WALK: I built an app that wants you to put it away</title>
      <dc:creator>Penta Dank</dc:creator>
      <pubDate>Sun, 11 Oct 2026 02:57:42 +0000</pubDate>
      <link>https://dev.to/pentadank/lore-walk-i-built-an-app-that-wants-you-to-put-it-away-2d7c</link>
      <guid>https://dev.to/pentadank/lore-walk-i-built-an-app-that-wants-you-to-put-it-away-2d7c</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05"&gt;Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I run Next Realm Interactive. My friend and creative director, Bully (&lt;a href="https://instagram.com/BullyStepHarder" rel="noopener noreferrer"&gt;@BullyStepHarder&lt;/a&gt;), is the guy on our team who holds the tablet. I see the blueprint; he translates it into something people can actually see. We call him the Lorekeeper, half as a joke. But most of his lore gets made indoors, under a ceiling, staring at a screen.&lt;/p&gt;

&lt;p&gt;So I built him something that argues with that, and gets him curious about what open AI can do in his hands.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LORE WALK&lt;/strong&gt; is a phone app whose main instruction is &lt;em&gt;put me away&lt;/em&gt;. You tap &lt;strong&gt;Start a walk&lt;/strong&gt;, and the screen tells you exactly one thing: &lt;em&gt;find something worth remembering.&lt;/em&gt; Then you go. When something stops you, like a tree with a split trunk, a door painted a color nobody would choose, or a rock that looks like it's been waiting, you pull the phone out for about ten seconds and take one photo.&lt;/p&gt;

&lt;p&gt;A small open-weight model running &lt;strong&gt;on the phone&lt;/strong&gt; reads the photo. A second small model takes what it saw and writes a title and a few sentences of lore, treating the place as a location in some old world. Mythic, but tied to what's actually there. That's a &lt;strong&gt;Lore Shard&lt;/strong&gt;. Then the phone goes back in your pocket.&lt;/p&gt;

&lt;p&gt;When you end the walk, you get the &lt;strong&gt;Lore Codex&lt;/strong&gt;: every shard in the order you found it, with an optional little route line if you turned on location. You can export it as Markdown or as one tall image to share.&lt;/p&gt;

&lt;p&gt;The screen should be the shortest part of the walk. That was the whole design brief.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://lore-walk-nextrealm.dankpenta.workers.dev" rel="noopener noreferrer"&gt;https://lore-walk-nextrealm.dankpenta.workers.dev&lt;/a&gt; (open it on your phone; it installs as a PWA)&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%2F9jgb0ts208k6xnilazu6.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%2F9jgb0ts208k6xnilazu6.png" alt="Lore Walk home screen" width="390" height="844"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgwrc2lpliwggrlfkqvc6.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%2Fgwrc2lpliwggrlfkqvc6.png" alt="A Lore Shard being written" width="390" height="844"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwk3tejy8x2ir0f1j42o5.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%2Fwk3tejy8x2ir0f1j42o5.png" alt="The Lore Codex" width="390" height="1796"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Screenshots from a full run on my machine: photo in, caption, tags, lore, Codex.&lt;/em&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/5thlegend" rel="noopener noreferrer"&gt;
        5thlegend
      &lt;/a&gt; / &lt;a href="https://github.com/5thlegend/lore-walk" rel="noopener noreferrer"&gt;
        lore-walk
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      LORE WALK by Bully · Next Realm Interactive. Turn a walk into world lore with open models running on your phone.
    &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;LORE WALK — by Penta Dank · Next Realm Interactive&lt;/h1&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Walk the world. Write its lore.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;LORE WALK&lt;/strong&gt; is a tiny phone app that wants you to put it away. Start a walk, pocket your phone, and only pull it out when something stops you — a crooked tree, a doorway, a mural, a rock that looks like it has a name. Snap it. An &lt;strong&gt;open-weight AI model running entirely on your device&lt;/strong&gt; reads the place and writes a short piece of world lore about it. That's a &lt;strong&gt;Lore Shard&lt;/strong&gt;. End the walk and you get a &lt;strong&gt;Lore Codex&lt;/strong&gt;: your shards in order, with an optional route line, exportable as Markdown or an image.&lt;/p&gt;
&lt;p&gt;Live: &lt;a href="https://lore-walk-nextrealm.dankpenta.workers.dev" rel="nofollow noopener noreferrer"&gt;https://lore-walk-nextrealm.dankpenta.workers.dev&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Built by &lt;strong&gt;Penta Dank&lt;/strong&gt; (General Dank) of Next Realm Interactive for his friend and creative director &lt;strong&gt;Bully&lt;/strong&gt; (&lt;a href="https://instagram.com/BullyStepHarder" rel="nofollow noopener noreferrer"&gt;@BullyStepHarder&lt;/a&gt;), a.k.a. &lt;em&gt;The Lorekeeper&lt;/em&gt;, to pull his creativity outside and into open…&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/5thlegend/lore-walk" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;MIT licensed. It's plain HTML, CSS, and one JS module. No build step and no backend.&lt;/p&gt;

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

&lt;p&gt;The whole app is static files. All the intelligence runs in the browser through &lt;strong&gt;&lt;a href="https://huggingface.co/docs/transformers.js" rel="noopener noreferrer"&gt;Transformers.js v3&lt;/a&gt;&lt;/strong&gt;, which uses &lt;strong&gt;WebGPU&lt;/strong&gt; when the phone supports it and falls back to &lt;strong&gt;WASM&lt;/strong&gt; on the CPU when it doesn't.&lt;/p&gt;

&lt;p&gt;The pipeline for each shard:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Downscale on device.&lt;/strong&gt; The photo goes through a canvas and comes out at 512px for the models and 480px as a JPEG thumbnail. The original never gets uploaded anywhere, because there's nowhere to upload it to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read the place.&lt;/strong&gt; &lt;code&gt;Xenova/vit-gpt2-image-captioning&lt;/code&gt; (8-bit quantized) gives a plain caption, something like "a large tree in a grassy field."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name the thing.&lt;/strong&gt; &lt;code&gt;Xenova/clip-vit-base-patch32&lt;/code&gt; does zero-shot classification against a short list of things worth stopping for (tree, doorway, mural, rock, bridge, stairs, gate…). That gives the lore writer a noun to hold onto.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write the lore.&lt;/strong&gt; &lt;code&gt;HuggingFaceTB/SmolLM2-360M-Instruct&lt;/code&gt; gets the caption and tags with a tight prompt: a 2–5 word place name, then three sentences of lore, in a fixed &lt;code&gt;TITLE:&lt;/code&gt; / &lt;code&gt;LORE:&lt;/code&gt; format that I parse and trim.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never break.&lt;/strong&gt; If a model fails to load, the phone runs out of memory, or the small model rambles past the format, a seeded template generator builds the shard from the same caption and tags. On a trail, the demo can't be the thing that breaks.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every shard records which models actually produced it, and the Codex shows that. The ⚙ panel lets you &lt;strong&gt;swap models&lt;/strong&gt;: SmolLM2-135M for older phones, Qwen2.5-0.5B-Instruct if you've got the headroom, or template-only for zero download.&lt;/p&gt;

&lt;p&gt;For offline use, a service worker caches the app shell and the library, and Transformers.js keeps the model weights in the browser's Cache API. Load it once on Wi-Fi at home and the walk itself needs no signal. Shards live in &lt;code&gt;localStorage&lt;/code&gt; as small thumbnails.&lt;/p&gt;

&lt;p&gt;The look comes from our studio: violet-black, galaxy purple, burning gold, fire orange, and white used sparingly. Big condensed type, like the spine of a tome. There's a maple leaf hidden in there too.&lt;/p&gt;

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

&lt;p&gt;Because of where this app is meant to be used: outside, where the signal is bad.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Offline on a trail.&lt;/strong&gt; A closed API needs a round trip to a datacenter for every photo. Here the model is a file sitting on my phone. Signal bar or no signal bar, it writes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The data stays on the device.&lt;/strong&gt; I'm asking people to photograph their neighborhood, their walk home, the tree outside their kid's school. Those photos shouldn't be training data for anyone. With local inference, privacy isn't a promise in a policy. The photos physically never leave.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swap the model.&lt;/strong&gt; Open weights mean the app isn't married to one vendor. When a better small vision model ships next month, changing it is one line.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero cost.&lt;/strong&gt; No API key, no per-request bill, no free tier that runs out. It costs nothing to run whether ten people use it or ten thousand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where open beat closed.&lt;/strong&gt; A giant closed model would write prettier sentences. But it would also need a connection, a key, a budget, and trust, and it would make the phone a pipe to somewhere else. The small open models are a little rougher, and honestly that roughness reads like found folklore. For an app whose job is to get you off the screen, small, local, and free beats big and remote.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This was built with an AI agent working alongside me, start to finish in one evening. Here's the real session: model choices, the first run where the small model ignored my output format, the CORS wall on the live site, the fallback that kept it from breaking, and the final run where all three open models wrote "The Luminous Tree."&lt;/p&gt;


&lt;div class="ltag-agent-session"&gt;
  &lt;div class="agent-session-header"&gt;
    
    &lt;span class="agent-session-tool-icon-badge" title="Gemini CLI"&gt;
&lt;/span&gt;
    &lt;span class="agent-session-title"&gt;LORE WALK: building an on-device open-model app that wants you to put it away&lt;/span&gt;
  &lt;/div&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Hacktoberfest Open-Source AI Challenge, Week 1: Touch Grass. Build an app for my friend and creative director Bully, the 'Lorekeeper', that gets his creativity outside and into open AI. Use open-weight models running on-device, make it look like Next Realm Interactive, and deploy it to Cloudflare.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Plan: a phone PWA whose main instruction is 'put me away'. Start a walk, snap one photo when something stops you, and on-device models turn it into a Lore Shard. End the walk to get a Lore Codex. Static files only, no backend, so photos never leave the phone.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Model stack, all in the browser via Transformers.js v3 (WebGPU if available, else WASM): vit-gpt2 captioning to read the place, CLIP zero-shot to name the thing, SmolLM2-360M-Instruct to write the lore, and a seeded template generator so a shard always gets made.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-write"&gt;Write&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;dist/app.js (pipeline excerpt)&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;js &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pipeline&lt;/span&gt; &lt;span class="nx"&gt;excerpt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight javascript"&gt;&lt;code&gt;&lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Reading the place…&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image-to-text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;device&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wasm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dtype&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;q8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="nx"&gt;max_new_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Naming what it is…&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zero-shot-image-classification&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;device&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wasm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dtype&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;q8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="nx"&gt;LABELS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`a photo of a &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;templateLore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;caption&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;111&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;templateLore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;caption&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;template (seeded by vision output)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;GPU detection gets a 2.5s timeout so a hanging adapter request can't freeze startup. Model downloads begin as soon as the walk starts.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-write"&gt;Write&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;dist/app.js&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight javascript"&gt;&lt;code&gt;&lt;span class="mi"&gt;4&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;hasGPU&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gpu&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;race&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestAdapter&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;2500&lt;/span&gt;&lt;span class="p"&gt;))]));&lt;/span&gt;
&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;warm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* start downloading while they walk */&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;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;The lore prompt asks for a strict TITLE: / LORE: format: a 2-5 word place name, then 3 sentences.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-write"&gt;Write&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;dist/app.js (prompt)&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;js &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight javascript"&gt;&lt;code&gt;&lt;span class="mi"&gt;96&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`A traveler on foot found this: "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;seedText&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;".\nInvent a short place-name title (2-5 words) and 3 sentences of world lore about it as a location in an ancient world ...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Headless end-to-end test harness: a 390x844 phone viewport, a real tree photo (test.jpg), a full walk, and screenshots of home, walk and codex.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-write"&gt;Write&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;test.py&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;pg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://localhost:8765/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;click&lt;/span&gt; &lt;span class="c1"&gt;#startBtn; set_input_files('#photo','test.jpg'); wait_for_selector('#lastShard .shard', timeout=840000); print RESULT; click #endBtn; screenshots shot-home/shot-walk/shot-codex.png&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;First local run with the real models. All three models loaded on CPU (no GPU adapter in the headless box). The caption and CLIP outputs were good, but SmolLM2 drifted off the format and the parser couldn't use it, so the template fallback wrote the shard.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-shell"&gt;Shell&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;python3 test.py &amp;gt; test.log  (v1 commit)&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;python3 test.py &amp;gt; test.log  (v1 commit)&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;0s C: No available adapters.
0s C: [status] Reading the place…
14s C: [status] Naming what it is…
21s C: [status] Writing the lore…
   **Lore:** 
Located deep within a lush, earthy grove, The Tree Oak stands tall, its majestic trunk reaching toward the sky like a giant emerald heart. ...
RESULT: SHARD 01 · 7:11 PM
THE WATCH OF ORRIN

Long before the roads had names, the tree at Orrin was where the Realm kept its promises. Travelers describe it plainly — a tree with a large, colorful, and colorful tree trunk — and that is how it hides. ...

seen: a tree with a large, colorful, and colorful tree trunk · tags: tree
models: Xenova/vit-gpt2-image-captioning → Xenova/clip-vit-base-patch32 → template (seeded by vision output) · 97.4s on-device&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Fallback worked as designed: the shard still came out and was honestly labeled 'template (seeded by vision output)'. The model had written a markdown '&lt;strong&gt;Lore:&lt;/strong&gt;' header instead of the requested format. The shipped parser tolerates TITLE variants and recovers the LORE text:&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-edit"&gt;Edit&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;dist/app.js (parser)&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;js &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight javascript"&gt;&lt;code&gt;&lt;span class="mi"&gt;101&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;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/TITLE&lt;/span&gt;&lt;span class="se"&gt;[^&lt;/span&gt;&lt;span class="sr"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\n]{0,12}&lt;/span&gt;&lt;span class="sr"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;([^\n&lt;/span&gt;&lt;span class="sr"&gt;,&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;?)(?=\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;(?:&lt;/span&gt;&lt;span class="sr"&gt;,|LORE:|TITLE|&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sr"&gt;|$&lt;/span&gt;&lt;span class="se"&gt;))&lt;/span&gt;&lt;span class="sr"&gt;/i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="mi"&gt;103&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;rest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/LORE:&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;([\s\S]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;/i&lt;/span&gt;&lt;span class="p"&gt;)?.[&lt;/span&gt;&lt;span class="mi"&gt;1&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="nx"&gt;t&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/TITLE&lt;/span&gt;&lt;span class="se"&gt;[^&lt;/span&gt;&lt;span class="sr"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\n]{0,12}&lt;/span&gt;&lt;span class="sr"&gt;:/gi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="mi"&gt;109&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text model failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&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;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Deployed to Cloudflare as a Workers static-assets site. The whole config is one line pointing at ./dist.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-write"&gt;Write&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;wrangler.jsonc&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight json-doc"&gt;&lt;code&gt;&lt;span class="err"&gt;wrangler.jsonc&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight json-doc"&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;"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;"lore-walk-nextrealm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"compatibility_date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-10-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"assets"&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;"directory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./dist"&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;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-shell"&gt;Shell&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;npx wrangler deploy&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;npx wrangler deploy&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;(deploy output not preserved; the live URL is the one served in test_live.log: https://lore-walk-nextrealm.dankpenta.workers.dev)&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Ran the same end-to-end test against the live URL.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-shell"&gt;Shell&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;python3 test_live.py &amp;gt; test_live.log&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;python3 test_live.py &amp;gt; test_live.log&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;0s REQ https://lore-walk-nextrealm.dankpenta.workers.dev/
1s REQ .../sw.js
1s C: [status] Reading the place…
1s REQ https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.7.2/dist/transformers.min.js
1s C: Access to fetch at 'https://huggingface.co/Xenova/vit-gpt2-image-captioning/resolve/main/tokenizer_config.json' from origin 'https://lore-walk-nextrealm.dankpenta.workers.dev' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
FAIL .../tokenizer_config.json net::ERR_FAILED
... (same CORS failure for CLIP and SmolLM2 config/tokenizer files)&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;CORS problem: in the live headless run, every Hugging Face model file was blocked, so all three models failed. The app still didn't break. It fell back to the template and produced a shard in 0.4s.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-read"&gt;Read&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;test_live.log (result)&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;test_live.log (result)&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;RESULT: SHARD 01 · 7:14 PM
THE THRESHOLD OF EMBERLINE

Long before the roads had names, the stone at Emberline was where the Realm kept its promises. Most walk past it without a second look, which is exactly how it survives. Touch it once and you will remember a place you have never been.

seen: —
models: template (seeded by vision output) · 0.4s on-device

Shard saved. Now put me away again.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Made the offline story concrete: a service worker caches the app shell and the library, and Transformers.js keeps model weights in the Cache API. Shards go into localStorage as small thumbnails, and if storage fills up the app degrades to keeping only the most recent walks.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-read"&gt;Read&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;dist/app.js&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight javascript"&gt;&lt;code&gt;&lt;span class="mi"&gt;15&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;saveWalks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lw_walks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lw_walks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)));&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;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Committed v1: app, icons, OG image, manifest, service worker, README, MIT license, DEV post draft, and test logs.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-shell"&gt;Shell&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;git commit -m 'LORE WALK v1'&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;git commit -m 'LORE WALK v1'&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;35c86b7 LORE WALK v1
 23 files changed, 665 insertions(+)
 dist/app.js | 188 +, dist/index.html | 90 +, DEV_POST.md | 66 +, README.md | 35 +, test.py, test_live.py, wrangler.jsonc ...&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Credit me (Penta Dank) as the maker. It's made for Bully.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Updated the byline across the page title, OG tags, header, manifest, README and post.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-shell"&gt;Shell&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;git show 6014c8a -- dist/index.html&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;git show 6014c8a -- dist/index.html&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;-&amp;lt;title&amp;gt;LORE WALK — by Bully · Next Realm Interactive&amp;lt;/title&amp;gt;
+&amp;lt;title&amp;gt;LORE WALK — by Penta Dank · Next Realm Interactive&amp;lt;/title&amp;gt;
-  &amp;lt;div class="by"&amp;gt;by Bully · Next Realm Interactive&amp;lt;/div&amp;gt;
+  &amp;lt;div class="by"&amp;gt;by Penta Dank · Next Realm Interactive · made for Bully&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-shell"&gt;Shell&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;git commit&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;git commit&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;6014c8a Credit Penta Dank as maker; made for Bully
 5 files changed, 14 insertions(+), 14 deletions(-)&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Added screenshots to the post and hosted them from the deployed site so DEV can embed them.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-shell"&gt;Shell&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;git log --oneline (screenshots)&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;git log --oneline (screenshots)&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;33193c0 Screenshots + final post
e5cffd5 Add screenshots (docs/shot-*.png)
d6b7445 Host screenshots (dist/shot-*.png, DEV_POST.md)&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Do a Next Realm signature design pass.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Design pass: a cinematic violet-black world, galaxy purple, burning gold, fire orange, white used sparingly, condensed tome-spine type, tome-styled shards, new icons and OG image, and polished exports.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-edit"&gt;Edit&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;dist/style.css, index.html, app.js, icon.svg, sw.js&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;dist/style.css, index.html, app.js, icon.svg, sw.js&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;style.css | 126 +++++---  index.html | 27 ++-  app.js | 16 +-  sw.js | 6 +-  icon-192/512.png, og.png regenerated&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Responsive QA script. It forces template-only mode so it runs fast, makes two shards, ends the walk, and checks for horizontal overflow at 390x844, 1280x800 and 320x640.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-write"&gt;Write&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;qa.py&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;qa&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="mi"&gt;390&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;844&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;m&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),(&lt;/span&gt;&lt;span class="mi"&gt;1280&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;d&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),(&lt;/span&gt;&lt;span class="mi"&gt;320&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;640&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)]:&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
  &lt;span class="n"&gt;visionSel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;none&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;clipSel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;none&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;textSel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;template&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
  &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="nf"&gt;set_input_files&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#photo&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;test.jpg&lt;/span&gt;&lt;span class="sh"&gt;'&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;wait&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SHARD 0n&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
  &lt;span class="n"&gt;screenshots&lt;/span&gt; &lt;span class="n"&gt;qa&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;walk&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;shard&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;codex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;png&lt;/span&gt;
  &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;scrollWidth&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;scrollWidth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Reran the full real-model test after the design pass. This time SmolLM2-360M's output got through the parser, so all three open models produced the shard (124.4s on CPU). The output is wild, rambling found folklore.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-shell"&gt;Shell&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;python3 test.py &amp;gt; test.log&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;python3 test.py &amp;gt; test.log&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;2s C: [status] Reading the place…
17s C: [status] Naming what it is…
24s C: [status] Writing the lore…
36s C: Unable to add response to browser cache: UnknownError: Failed to execute 'put' on 'Cache': Unexpected internal error..
RESULT:
SHARD 01 · 7:36 PM
PUKUTUKA [BY AETHERE] : THE LUMINOUS TREE

At twilight the Moon-Moon rises against the sky of pukutuckana over Pikinipu’s sacred hui iwi – and to your knowledge that is where you find what was once white from its blossoms all around under great oak... 

seen: a tree with a large, colorful, and colorful tree trunk · tags: tree
models: Xenova/vit-gpt2-image-captioning → Xenova/clip-vit-base-patch32 → HuggingFaceTB/SmolLM2-360M-Instruct · 124.4s on-device&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Committed the design pass with refreshed screenshots for mobile, desktop and small phones.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-shell"&gt;Shell&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;git commit&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;git commit&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;f06f986 Next Realm signature design pass: cinematic world, tome shards, new icons/OG, export polish
 34 files changed, 226 insertions(+), 126 deletions(-)&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Final DEV post is honest about status: the full flow was tested end to end on a real tree photo, a shard takes about 1.5-2 minutes on a laptop CPU, phone WebGPU speed hasn't been measured, and the first real walk is Bully's.&lt;/p&gt;

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

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


&lt;h2&gt;
  
  
  Taking It Outside
&lt;/h2&gt;

&lt;p&gt;Honest status: this one was built against the clock tonight, and the walk hasn't happened yet. I ran the full flow end to end on my machine with a real tree photo. The caption model saw "a tree with a large, colorful… tree trunk," CLIP tagged it as a tree, and SmolLM2 wrote back a few lines about "The Tree Oak" standing tall with its trunk reaching for the sky. That's a little clumsy, a little mythic, and exactly the kind of found folklore I was after.&lt;/p&gt;

&lt;p&gt;On a laptop CPU, each shard took about a minute and a half. On a phone with WebGPU it should be faster, but I haven't measured that, so I won't claim it.&lt;/p&gt;

&lt;p&gt;The first real walk is Bully's. That was always the point: I build the engine, the Lorekeeper writes the world. When he takes it out, I'll post the Codex in the comments, including whatever the models get wrong.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
    <item>
      <title>Storyhouse: I built my grandmother somewhere for her stories to live</title>
      <dc:creator>Penta Dank</dc:creator>
      <pubDate>Mon, 05 Oct 2026 02:13:42 +0000</pubDate>
      <link>https://dev.to/pentadank/storyhouse-i-built-my-grandmother-somewhere-for-her-stories-to-live-1f6m</link>
      <guid>https://dev.to/pentadank/storyhouse-i-built-my-grandmother-somewhere-for-her-stories-to-live-1f6m</guid>
      <description>&lt;p&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01"&gt;Hacktoberfest Weekend Challenge: Build for a Friend&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;I built Storyhouse for my grandmother.&lt;/p&gt;

&lt;p&gt;She's in her eighties, and she's living with early Alzheimer's. The hardest part isn't only the memories she may lose — it's realizing how many stories she's carrying right now. The Sunday peach pies her mother baked. The dance where she met my grandfather. The old blue Beetle with the heater that never worked. Eighty years of stories, and almost none of them written down. And fewer people around to tell them to than there used to be.&lt;/p&gt;

&lt;p&gt;I didn't want to build another chatbot.&lt;/p&gt;

&lt;p&gt;I wanted to build somewhere her stories could live.&lt;/p&gt;

&lt;p&gt;Storyhouse is a local-first, voice-first AI companion and family memory archive. It sits in the room, listens while she talks, responds warmly, and quietly turns the meaningful moments into a structured, family-owned Memory Vault — connecting people, places, recipes, and decades into something the whole family can keep forever.&lt;/p&gt;

&lt;p&gt;It is deliberately not a few things: not an Alzheimer's treatment, not a medical device, not a replacement for family, and never a fake relative pretending to be her granddaughter. It's a companion and a memory-preservation system — and it always nudges her back toward real people.&lt;/p&gt;

&lt;p&gt;The interface isn't a chat window. It's a house you walk into: a Living Room to talk, a Library of preserved stories in her own words, a Gallery, a Life Timeline, and a Vault she (and the family) fully own. There's a read-only Family View so relatives can wander the archive, and a printable storybook PDF so her words can live on paper too.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;She spent 80 years collecting stories. We built somewhere for them to live.&lt;/p&gt;
&lt;/blockquote&gt;

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

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

&lt;p&gt;The demo runs in Demo Mode with a fictional woman, "Margaret," so no real family memory is ever exposed. Her seeded life is built to show the system actually &lt;em&gt;thinking&lt;/em&gt;: ask it about "Grandpa's car" and it retrieves the right memory; it links the blue Chevrolet to teaching their son to drive; it holds an unfinished story to gently return to later; and it keeps a deliberately conflicting date ("1957"… "actually, maybe 1958") as two recollections — because it is not allowed to quietly decide which one is true.&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/5thlegend" rel="noopener noreferrer"&gt;
        5thlegend
      &lt;/a&gt; / &lt;a href="https://github.com/5thlegend/storyhouse" rel="noopener noreferrer"&gt;
        storyhouse
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🏠 Storyhouse&lt;/h1&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;A home for the stories that make us who we are.&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;Storyhouse is a &lt;strong&gt;local-first, voice-first AI companion and family memory archive&lt;/strong&gt;. It listens to an elderly loved one tell the stories of their life, remembers them, connects them across the decades, and preserves them in a structured, family-owned &lt;strong&gt;Memory Vault&lt;/strong&gt; — all powered by an &lt;strong&gt;open-weight Gemma model running locally&lt;/strong&gt;, so the most private memories a family has never leave the device.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;She spent 80 years collecting stories.&lt;/em&gt;
&lt;em&gt;We built somewhere for them to live.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;The person I built it for&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;I built Storyhouse for &lt;strong&gt;my grandmother&lt;/strong&gt;, who is in her eighties and living with early Alzheimer's.&lt;/p&gt;
&lt;p&gt;The hardest part isn't only the memories she may lose. It's realizing how many stories she is carrying &lt;em&gt;right now&lt;/em&gt; — about her mother's Sunday peach pies, the dance where she met my grandfather, the old blue…&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/5thlegend/storyhouse" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


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

&lt;p&gt;The intelligence is Google Gemma 3 (open-weight, 4B), running entirely locally via &lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt; — no cloud, no API key, no bill. Gemma does the real work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the warm companion responses (streamed token-by-token, so it feels like talking, not waiting),&lt;/li&gt;
&lt;li&gt;memory extraction — turning a spoken passage into structured JSON (title, people, places, dates, emotions, themes),&lt;/li&gt;
&lt;li&gt;entity extraction and novelty reasoning,&lt;/li&gt;
&lt;li&gt;retrieval synthesis ("what did I tell you about Grandpa's car?").&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Semantic memory search uses the open &lt;code&gt;nomic-embed-text&lt;/code&gt; model, also local. Everything sits behind a provider abstraction, so the model is swappable and nothing is coupled to a vendor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AIProvider
  ├── OllamaProvider   (Gemma — the open-source core)
  └── MockProvider     (honest offline fallback: the app still opens, the Vault still works)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It's a real memory system, not a prompt stuffed with history. Her words → embedding → cosine search over the vault → only the relevant memories are assembled into Gemma's context. The whole archive is never dumped into the model.&lt;/p&gt;

&lt;p&gt;And the honesty rails are in the data model, not just the vibes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Immutable originals — her exact words are stored once, never overwritten. A revised detail becomes a &lt;em&gt;new&lt;/em&gt; recollection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provenance on everything&lt;/strong&gt; — each fact is tagged &lt;code&gt;DIRECT&lt;/code&gt; (her words), &lt;code&gt;APPROXIMATE&lt;/code&gt;, &lt;code&gt;FAMILY_REPORTED&lt;/code&gt;, &lt;code&gt;DERIVED&lt;/code&gt; (AI inference), or &lt;code&gt;GENERATED&lt;/code&gt; (AI art). The UI shows it; the AI is told to say "you told me…", never "it is true that…".&lt;/li&gt;
&lt;li&gt;Never invent — if nothing relevant is retrieved, it says "I don't have that one yet — I'd love to hear about it," instead of making something up. If she says "1944," it keeps the year; it won't fabricate a day.&lt;/li&gt;
&lt;li&gt;Consent — a story is kept only when offered and accepted. The microphone only listens when tapped.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the whole family. A read-only Family View (passcode-unlocked) lets relatives browse the Library, Gallery, Timeline and Vault — but the Living Room, the microphone, and all editing stay private to her, and anything marked private is never shown. It's enforced on the server, not just hidden in the UI. It runs on the home device; for family far away, a Cloudflare Tunnel keeps the data on that device while making it privately reachable — no cloud database, ever. And the whole archive exports as a storybook PDF (her words, provenance, and the memory art embedded) or as JSON/Markdown — the family owns it, forever.&lt;/p&gt;

&lt;p&gt;Memory art uses another open-weight model — Flux.1 &lt;a href="//Apache-2.0"&gt;schnell&lt;/a&gt; — hosted on Cloudflare Workers AI, which turns a scene she described ("an enormous orange tree, the light coming through all gold") into a labeled painting. It runs on Cloudflare's GPUs so it doesn't fight Gemma for the laptop's 6 GB. It's the one piece that calls out — disclosed in the app, and always labeled "AI-generated visual interpretation," never a real photograph.&lt;/p&gt;

&lt;p&gt;Stack: React + Vite + Tailwind on the front, Node + Express on the back, and the Memory Vault in SQLite via Node's built-in &lt;code&gt;node:sqlite&lt;/code&gt; (which, as a bonus, means zero native build step — a real gift on Windows without a C++ toolchain). A nice detail for small hardware: on a 6 GB laptop GPU, Gemma and the embedder were fighting for VRAM, so I pinned both resident with &lt;code&gt;keep_alive&lt;/code&gt; and a boot warmup. Warm turns land in ~2 seconds.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Because these are a dying woman's most intimate memories.&lt;/p&gt;

&lt;p&gt;For this project, open-weight, local AI isn't a nice-to-have — it's the only ethically defensible architecture.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔒 Private by construction. Her stories are processed on the device and stored in a local vault. Nothing is uploaded. A closed API would mean sending my grandmother's life to a company's servers.&lt;/li&gt;
&lt;li&gt;✈️ Works offline. It runs on a laptop with no internet — and the roadmap puts it on her own phone, fully on-device, using Gemma 3n via Google AI Edge / MediaPipe.&lt;/li&gt;
&lt;li&gt;💸 Free to run, forever. No per-token meter running while a grandchild keeps a grandparent's memory alive.&lt;/li&gt;
&lt;li&gt;🔧 Ours to change. We own the weights. We can swap models or fine-tune on the family's own voice, because nothing is locked behind a vendor. Even the image model is open-weight (Flux.1) — the only thing we don't own is the GPU it briefly borrows.&lt;/li&gt;
&lt;li&gt;🧭 Provable. Because I control the whole pipeline, I can show that her conversations never leave the device — not just promise it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A closed API could have produced the conversation. It could not have produced the ownership. That difference is the entire point.&lt;/p&gt;
&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;I built this with Claude Code (and saved the session with DevRelay). Here's the real build — including the honest engineering saves: swapping a native SQLite dependency for Node's built-in &lt;code&gt;node:sqlite&lt;/code&gt; when there was no C++ toolchain, pinning both models resident to stop VRAM thrashing on a 6 GB GPU, and catching the moment it fabricated a memory (a stale fallback embedding had broken retrieval) and hardening it so it can never invent her life.&lt;/p&gt;


&lt;div class="ltag-agent-session"&gt;
  &lt;div class="agent-session-header"&gt;
    
    &lt;span class="agent-session-tool-icon-badge" title="Claude Code"&gt;
&lt;/span&gt;
    &lt;span class="agent-session-title"&gt;Building Storyhouse: a local-first memory companion on open-weight Gemma&lt;/span&gt;
  &lt;/div&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;For the Hacktoberfest 'Build for a Friend' challenge: build Storyhouse — a local-first, voice-first AI memory companion for my grandmother (80s, early Alzheimer's) to preserve her life stories. Open-source AI must be at the core. Can it run open AI locally, and ideally on-device on her phone?&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Yes — and Gemma is the ideal pick. Gemma 3 runs locally via Ollama now, and Gemma 3n is purpose-built for on-device Android (text + audio) via MediaPipe, so the same open model family can eventually run fully offline on her phone. For a weekend we'll ship a local-first web MVP (installable as a PWA), with on-device Android documented as Phase 2. Let me check the hardware first.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;nvidia-smi --query-gpu=name,memory.total --format=csv,noheader&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ nvidia-smi --query-gpu=name,memory.total --format=csv,noheader&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;NVIDIA GeForce RTX 4050 Laptop GPU, 6141 MiB&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;6 GB VRAM — enough for gemma3:4b (quality sweet spot) plus a small embedder. Pulling both open models.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;ollama pull gemma3:4b &amp;amp;&amp;amp; ollama pull nomic-embed-text&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ ollama pull gemma3:4b &amp;amp;&amp;amp; ollama pull nomic-embed-text&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;gemma3:4b (3.3 GB) + nomic-embed-text (274 MB) pulled&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;curl ollama /api/chat gemma3:4b 'Reply: ready'&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ curl ollama /api/chat gemma3:4b 'Reply: ready'&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;reply: 'Ready!'  |  gen ~23 tok/s warm&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Open core confirmed. Architecture: React + Vite + Tailwind client; Node + Express API; a real Memory Vault in SQLite (not chat logs). Every model sits behind an AIProvider abstraction (OllamaProvider for Gemma + an honest MockProvider fallback) so the open model is the core and nothing is coupled to a vendor. Scaffolding the server, DB schema, provider layer, memory store, and the fictional 'Margaret' demo seed.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;First real snag: better-sqlite3 tried to compile from source and failed — no Visual Studio C++ toolchain on this Windows machine.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;npm install&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ npm install&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;gyp ERR! find VS — Could not find any Visual Studio installation to use (better-sqlite3 rebuild failed)&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Rather than make the user install a multi-GB compiler, I switched to Node's built-in node:sqlite (--experimental-sqlite) — same synchronous API, zero native build. A nice side effect: the project now installs clean on any machine with no toolchain.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Second snag, specific to small VRAM: the first conversation turn timed out and retrieval came back empty. Gemma (~5 GB) and the embedder were evicting each other between turns. Checked residency:&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;ollama ps&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ ollama ps&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;gemma3:4b 100% GPU + nomic-embed-text 100% GPU  |  GPU 5.5/6.1 GB — both fit!&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;They fit together; the models were just unloading on the default keep_alive. Fix: pin both resident with keep_alive:'30m' on every call + a boot warmup. Warm turns now land in ~2–4 s.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Core loop working end-to-end. The companion is grounded ONLY in retrieved memories (embed the query → cosine search the vault → assemble just the relevant memories → Gemma). Tested:&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-api"&gt;api&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;POST /conversations/:id/messages { text: "Do you remember what I told you abo...&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;POST /conversations/:id/messages { text: "Do you remember what I told you about Grandpa's car?" }&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Storyhouse: "You mentioned… Harold's blue Chevrolet. Is that what you were thinking of?"  |  grounded on: Teaching their son to drive (0.62), The old blue Chevrolet …&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Memory extraction: Gemma turns a spoken passage into a structured, provenance-tagged memory — never a raw transcript, never inventing facts.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-api"&gt;api&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;POST /consolidate { text: "My sister Eleanor and I walked to the schoolhouse ...&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;POST /consolidate { text: "My sister Eleanor and I walked to the schoolhouse in Cedar Falls every morning in 1944, even in the snow..." }&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;TITLE: Morning Walks to School | ENTITIES: person:Eleanor, place:Cedar Falls, place:schoolhouse, event:walking to school | THEMES: family, childhood | CONFIDENCE: DIRECT&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Honesty rails are in the data model, not just prompts: immutable originals (a revised date becomes a SECOND recollection — both kept, never silently chosen), provenance tags on every fact (DIRECT / APPROXIMATE / DERIVED / GENERATED), never-invent-date-precision (I clamp year-only dates so '1944' never becomes a fabricated day), consent-to-save, mic-only-on-tap, and AI art always explicitly labeled as an interpretation.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Verified the UI live in the browser: the warm 'Memory House' renders with a breathing presence orb ('I'm here.'), a Gemma-online indicator, the Living Room conversation, and the Library showing memory cards with 'Her words' provenance badges and entity chips. Then shipped it: wrote the README + docs + MIT license, committed, and pushed a public repo.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;git commit &amp;amp;&amp;amp; gh repo create storyhouse --public --source=. --push&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ git commit &amp;amp;&amp;amp; gh repo create storyhouse --public --source=. --push&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;https://github.com/5thlegend/storyhouse — public, main branch, 54 files&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Why does the open-source approach matter here, honestly?&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Because these are a dying woman's most intimate memories. Local, open-weight AI is the only architecture that keeps them on the device (nothing uploaded), works offline, costs nothing to run, and lets the family own, swap, or fine-tune the model with nothing locked behind a vendor — and because I control the whole pipeline, I can PROVE nothing leaves the device rather than just promise it. A closed API could produce the conversation; it could not produce the ownership. That difference is the entire point of Storyhouse.&lt;/p&gt;

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

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



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

&lt;ul&gt;
&lt;li&gt;Gemma — the open-weight Gemma model is genuinely the core intelligence of the app (conversation, memory extraction, entity reasoning, retrieval), run locally. I've deliberately &lt;em&gt;not&lt;/em&gt; claimed partner categories for tech I didn't actually use.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Built by &lt;a href="https://dev.to/generaldank"&gt;Next Realm Interactive&lt;/a&gt;. For my grandmother — and for everyone's.&lt;/p&gt;

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