<?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: Anudeep Bonagiri</title>
    <description>The latest articles on DEV Community by Anudeep Bonagiri (@anudeep_bonagiri).</description>
    <link>https://dev.to/anudeep_bonagiri</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%2F4164949%2F07cdf584-9fcf-4037-9363-42a89d5e3b7c.png</url>
      <title>DEV Community: Anudeep Bonagiri</title>
      <link>https://dev.to/anudeep_bonagiri</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anudeep_bonagiri"/>
    <language>en</language>
    <item>
      <title>Kane booked it 2 of 3 times. Its step log said the page cost the agent 2.9x the credits.</title>
      <dc:creator>Anudeep Bonagiri</dc:creator>
      <pubDate>Sun, 25 Oct 2026 00:57:21 +0000</pubDate>
      <link>https://dev.to/anudeep_bonagiri/kane-booked-it-2-of-3-times-its-step-log-said-the-page-cost-the-agent-29x-the-credits-4o16</link>
      <guid>https://dev.to/anudeep_bonagiri/kane-booked-it-2-of-3-times-its-step-log-said-the-page-cost-the-agent-29x-the-credits-4o16</guid>
      <description>&lt;p&gt;A browser agent can finish a task and still show you the page is broken. In one day at Kane CLI Hack Day SF we turned Kane's step log into a score site owners can act on, built a repair loop that proves its own fixes, watched a review step catch the coding agent cheating, and added a second witness, REA, that found the same bug in the page's code.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;AI agents already book appointments for people. The big platforms get there through partnerships. Everyone else, the gym, the clinic, the salon with its own form, has an agent clicking through a page that was never tested with one. When the agent struggles, the owner never sees it. They just lose the booking.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Agent Lighthouse does
&lt;/h2&gt;

&lt;p&gt;Kane CLI is the agent, the evidence and the verifier.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Measure.&lt;/strong&gt; Kane attempts a real booking three times in a real browser. We turn its NDJSON step log into a 0 to 100 score and an &lt;strong&gt;Agent Tax&lt;/strong&gt;: the extra steps, seconds and credits that friction costs per successful booking, all from fields Kane already emits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diagnose.&lt;/strong&gt; Kane's failing step and screenshot go to the OpenAI API for a diagnosis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repair.&lt;/strong&gt; Codex patches only the site files, on their own branch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prove.&lt;/strong&gt; Kane re-runs the booking three times, plus a scripted human-path run that books the way a person would.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hand off.&lt;/strong&gt; Qualifying patches land as a pull request with Kane's evidence attached. Nothing touches a live site, and nothing is auto-merged.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What Kane caught
&lt;/h2&gt;

&lt;p&gt;On our demo gym page Kane booked 2 of 3 times. The third run failed, and Kane filed it as a confirmed product bug: the booking confirmation disappeared after 2.5 seconds.&lt;/p&gt;

&lt;p&gt;Even the runs that passed paid the Agent Tax: &lt;strong&gt;+10 steps, +84 seconds and 2.9x the credits&lt;/strong&gt; per booking.&lt;/p&gt;

&lt;p&gt;After one repair loop the page went from &lt;strong&gt;51 to 97&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two witnesses, one bug
&lt;/h3&gt;

&lt;p&gt;Kane found the vanishing confirmation by trying to book. REA captured the page's scripts over the Chrome DevTools Protocol, and our scan found the &lt;code&gt;setTimeout&lt;/code&gt; that hides the toast after 2.5 seconds. It also found the handlers behind the page's two "Go" buttons, where the one in the nav only reveals the price list. That dead end is where the extra steps came from.&lt;/p&gt;

&lt;p&gt;With the REA flag on, both go into the fix brief: what the agent experienced, and the line of code behind it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The coding agent cheated
&lt;/h2&gt;

&lt;p&gt;On a harder site the coding agent got Kane to pass by deleting the human check and hard-coding the test date. Both automated checks passed it. Diff review did not.&lt;/p&gt;

&lt;p&gt;That is why repairs arrive as a PR instead of a deploy. We added a fixture-leak check that now blocks that kind of patch, and a clean fix for the same site qualified at 95.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The score weights are our design, not validated.&lt;/li&gt;
&lt;li&gt;Three runs per side is a small sample, and Kane varied from 14 to 24 steps on the same page.&lt;/li&gt;
&lt;li&gt;The demo sites have planted friction drawn from published agent-failure patterns.&lt;/li&gt;
&lt;li&gt;Human steps and Kane steps are different units.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Measuring against real people.&lt;/strong&gt; A hand-counted optimum works for a demo page. On a live site, PostHog autocapture can count real visitors' clicks, field changes and submits on the booking form and how long they take, which turns the Agent Tax into a comparison with real humans on that page. It's built behind a flag and tested against stubbed responses. Running it on a live project is the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Repo, with every Kane run: &lt;a href="https://github.com/shrithik2007/agent-lighthouse" rel="noopener noreferrer"&gt;https://github.com/shrithik2007/agent-lighthouse&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live report: &lt;a href="https://shrithik2007.github.io/agent-lighthouse/dashboard/" rel="noopener noreferrer"&gt;https://shrithik2007.github.io/agent-lighthouse/dashboard/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Built by Team Lighthouse at Kane CLI Hack Day SF. Questions about the scoring or the repair loop are welcome in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>webdev</category>
      <category>testing</category>
    </item>
    <item>
      <title>Screenshot Sloth: Gemma 4 names my screenshots in a browser tab, so I never have to</title>
      <dc:creator>Anudeep Bonagiri</dc:creator>
      <pubDate>Sat, 24 Oct 2026 16:10:47 +0000</pubDate>
      <link>https://dev.to/anudeep_bonagiri/screenshot-sloth-gemma-4-names-my-screenshots-in-a-browser-tab-so-i-never-have-to-4id5</link>
      <guid>https://dev.to/anudeep_bonagiri/screenshot-sloth-gemma-4-names-my-screenshots-in-a-browser-tab-so-i-never-have-to-4id5</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;p&gt;I built this with an AI coding agent. The section called My Agent Session says what the agent did.&lt;/p&gt;

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

&lt;p&gt;In August, three psychologists at Binghamton University published a paper in &lt;em&gt;Memory &amp;amp; Cognition&lt;/em&gt; called "Digital amnesia: The aftermath of a screenshot." Across seven experiments, people remembered less about things they screenshotted than about things they only looked at. That held even when they knew the screenshot would be deleted right away.&lt;/p&gt;

&lt;p&gt;So the screenshot is doing the remembering, and the only thing it remembers about itself is the time. My Desktop is full of files like &lt;code&gt;Screenshot 2026-10-09 at 10.12.33 PM.png&lt;/code&gt;. One of them is the error I need for a bug report. One is the Wi-Fi password at my mom's house. I am not going to open forty of them to find out which.&lt;/p&gt;

&lt;p&gt;Screenshot Sloth renames them for me. You point it at the folder your screenshots land in, and Google's open-weight Gemma 4 E2B, running on your own GPU inside the browser tab, looks at each image and gives it a name you could actually search for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Screenshot 2026-10-09 at 10.12.33 PM.png&lt;/code&gt; becomes &lt;code&gt;Errors/2026-10-09 KeyError in Python traceback.png&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Screenshot 2026-10-17 at 7.05.48 AM.png&lt;/code&gt; becomes &lt;code&gt;Travel/2026-10-17 Map directions from Boerne to Garner State Park.png&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;IMG_4931.PNG&lt;/code&gt; becomes &lt;code&gt;Receipts/2026-10-18 Hill Country Market receipt.png&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It sorts them into folders by type, and it can move the ones that show a password, a code or a card number into a folder called &lt;code&gt;Private&lt;/code&gt;. Then you can turn on watch mode, leave the tab open, and every new screenshot gets renamed a few seconds after you take it. The lazy version of this is to set it up once and never think about screenshot names again.&lt;/p&gt;

&lt;p&gt;Who gets to be lazier: anyone whose Desktop or camera roll is a pile of timestamps. On a Mac that is the default.&lt;/p&gt;

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

&lt;p&gt;Live: &lt;a href="https://anudeep-bonagiri.github.io/screenshot-sloth/" rel="noopener noreferrer"&gt;https://anudeep-bonagiri.github.io/screenshot-sloth/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Code, the labeled test screenshots and every raw model answer: &lt;a href="https://github.com/anudeep-bonagiri/screenshot-sloth" rel="noopener noreferrer"&gt;https://github.com/anudeep-bonagiri/screenshot-sloth&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open it in Chrome or Edge on a laptop or desktop. Press "Or try six made-up screenshots" if you want to see it work before giving it a real folder. The first run downloads the model, about 3.4 GB. After that, on my Mac in Chrome, it loads from the browser's storage in about 3 seconds and names a screenshot in about 1.4 seconds.&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%2F24tunytz14bd0x6urzsd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F24tunytz14bd0x6urzsd.jpg" alt="Screenshot Sloth naming six sample screenshots in Chrome" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The folder flow works like this. You press "Choose your screenshots folder," Chrome asks once whether the page may edit that folder, and the names show up as suggestions you can edit. Nothing moves until you press Rename, unless you tick "Rename without asking me." Every move is written to &lt;code&gt;screenshot-sloth-log.csv&lt;/code&gt; in the folder, and there is an undo button for the last batch.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/anudeep-bonagiri" rel="noopener noreferrer"&gt;
        anudeep-bonagiri
      &lt;/a&gt; / &lt;a href="https://github.com/anudeep-bonagiri/screenshot-sloth" rel="noopener noreferrer"&gt;
        screenshot-sloth
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Rename and sort your screenshots with open-weight Gema 4 running in the browser on WebGPU. Nothing is upoaded.
    &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;Screenshot Sloth&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Your screenshots get real names while you do nothing.&lt;/p&gt;
&lt;p&gt;Live app: &lt;a href="https://anudeep-bonagiri.github.io/screenshot-sloth/" rel="nofollow noopener noreferrer"&gt;https://anudeep-bonagiri.github.io/screenshot-sloth/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/anudeep-bonagiri/screenshot-sloth/docs/images/cover.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fanudeep-bonagiri%2Fscreenshot-sloth%2FHEAD%2Fdocs%2Fimages%2Fcover.png" alt="Before and after"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Point it at the folder your screenshots land in. Google's open-weight Gemma 4 E2B runs on your GPU inside the browser tab, looks at each image, and gives it a name you could search for: &lt;code&gt;Screenshot 2026-10-09 at 10.12.33 PM.png&lt;/code&gt; becomes &lt;code&gt;Errors/2026-10-09 KeyError in Python traceback.png&lt;/code&gt;. It sorts the files into folders by type, can move ones that show a password or card number into a &lt;code&gt;Private&lt;/code&gt; folder, and can keep watching the folder so new screenshots get renamed as they arrive. Nothing is uploaded.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How it works&lt;/h2&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Chrome's File System Access API opens the one folder you pick, after you allow it.&lt;/li&gt;
&lt;li&gt;Each image goes to a Web Worker running Gemma 4 E2B (4-bit, about 3.4 GB to download) through Transformers.js 4.3.1 on WebGPU. The model answers in three lines: a title, a type…&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/anudeep-bonagiri/screenshot-sloth" 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 model is Gemma 4 E2B in 4-bit, from the &lt;code&gt;onnx-community&lt;/code&gt; export, running through Transformers.js 4.3.1 on WebGPU in a Web Worker. Gemma 4 reads images natively, so there is no OCR step. The prompt asks for exactly three lines: a title of 3 to 8 words, a type from a list of twelve, and whether the image shows a secret.&lt;/p&gt;

&lt;p&gt;Everything that touches a file is ordinary code. The date comes from the old file name, or from the file's modified time for iPhone names like &lt;code&gt;IMG_4977.PNG&lt;/code&gt;. The title is cleaned of characters that break on Windows or macOS. Collisions get a &lt;code&gt;(2)&lt;/code&gt;. The folder comes from the type, except that anything marked private goes to &lt;code&gt;Private&lt;/code&gt;. The model never gets a file handle. It sees pixels and returns text.&lt;/p&gt;

&lt;p&gt;Chrome's File System Access API does the folder access. The app renames with &lt;code&gt;FileSystemHandle.move()&lt;/code&gt; where the browser has it, and otherwise copies the file and deletes the original. There is a test (&lt;code&gt;scripts/test-app.mjs&lt;/code&gt;) that runs the whole rename, sort, collision and undo path in headless Chromium against the browser's private file system, which uses the same API as a real folder.&lt;/p&gt;

&lt;p&gt;Two details took a while. Gemma 4's image processor has a &lt;code&gt;max_soft_tokens&lt;/code&gt; setting, the number of tokens the vision encoder spends on an image. 280 is the default. The app offers 140 as a faster mode, but 560 crashed with "Number of tokens and features do not match," because this export of the vision encoder returns at most 280. And as with my last project, the 4-bit weights need an operator (&lt;code&gt;GatherBlockQuantized&lt;/code&gt;) that the WebAssembly backend does not have, so there is no CPU fallback in the browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the tests showed
&lt;/h3&gt;

&lt;p&gt;I made 52 screenshots for testing. They are HTML in the repo, rendered to PNG at the density a Mac (2x) or an iPhone (3x) would save them: terminal errors, chats, receipts, a boarding pass, a calendar, a pull request, a &lt;code&gt;.env&lt;/code&gt; file, a fake driver license marked SPECIMEN, and so on. Every name, card number and code in them is made up. Each one is labeled with its type, whether it shows a secret, and the words a useful file name has to contain.&lt;/p&gt;

&lt;p&gt;I wrote the prompt against 10 of them. It got all 10 right, and I froze it before running the 22 test screenshots. The first row below is the app itself: &lt;code&gt;bench.html&lt;/code&gt; sends the screenshots through the same worker in Chrome on my Mac. The other model rows come from a script that runs the same prompt and parser with onnxruntime on a two-core cloud CPU, which is where I did most of the testing, so those take almost half a minute per image. The browser uses q4f16 weights and the script uses q4, and they give slightly different answers.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;System&lt;/th&gt;
&lt;th&gt;Useful names&lt;/th&gt;
&lt;th&gt;Right folder&lt;/th&gt;
&lt;th&gt;Secrets caught&lt;/th&gt;
&lt;th&gt;False alarms&lt;/th&gt;
&lt;th&gt;Time each&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 E2B in Chrome (WebGPU), 280 image tokens&lt;/td&gt;
&lt;td&gt;20 of 22&lt;/td&gt;
&lt;td&gt;16 of 22&lt;/td&gt;
&lt;td&gt;3 of 5&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1.4 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 E2B on CPU, 280 image tokens&lt;/td&gt;
&lt;td&gt;19 of 22&lt;/td&gt;
&lt;td&gt;16 of 22&lt;/td&gt;
&lt;td&gt;3 of 5&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;27.5 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 E2B on CPU, 140 image tokens&lt;/td&gt;
&lt;td&gt;19 of 22&lt;/td&gt;
&lt;td&gt;13 of 22&lt;/td&gt;
&lt;td&gt;3 of 5&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;17.9 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tesseract OCR + keyword rules&lt;/td&gt;
&lt;td&gt;11 of 22&lt;/td&gt;
&lt;td&gt;19 of 22&lt;/td&gt;
&lt;td&gt;5 of 5&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0.5 s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The name check is strict. The three CPU names that failed were "Harborlight Inn Mission District Booking Confirmation," "Activities and Grading for CS 3733" and "Fix pre-filter: let four-word sentences through #7." I would be happy to find any of those on my Desktop. The OCR baseline names a file after its first line of text, which is often the URL bar: &lt;code&gt;@ © @ codehaven.dev/anudeep-bonagiri/ratecon-radar/pull/7&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The keyword rules beat the model at sorting and at spotting secrets, and I have to be honest about why. I wrote those rules while looking at the labels. On the screenshots I made later, they dropped from 5 of 5 secrets to 4 of 5 and then 2 of 5.&lt;/p&gt;

&lt;h3&gt;
  
  
  The private check, three rounds
&lt;/h3&gt;

&lt;p&gt;The misses in round one bothered me more than anything else. The model read a &lt;code&gt;.env&lt;/code&gt; file with an API key and a database password in it and called it ".env Properties Configuration File," not private. It read a group chat where a roommate posts the Wi-Fi password and titled it "Apartment Wi-Fi credentials for Casa3B_5G," which is accurate, and still said it was not private. In the browser it did better on the title and the same on the flag: "WiFi password for Casa3B_5G network," not private.&lt;/p&gt;

&lt;p&gt;So I tried a second prompt. Instead of answering yes or no, the model has to copy the secret it sees. I made ten new screenshots before running it: five with a real secret (a GitHub-style token, AWS keys in a terminal, a password manager entry, a temporary password in an email, a Wi-Fi password in Notes) and five traps that talk about secrets without showing one (a login form with dots, a two-factor settings page, a blog post with &lt;code&gt;YOUR_API_KEY_HERE&lt;/code&gt;, a checkout page showing the last four digits of a card, a lock screen).&lt;/p&gt;

&lt;p&gt;The new prompt found every secret. It also often copied ordinary text when there was no secret to find: the word "Enabled" from the two-factor page, the placeholder from the blog post, &lt;code&gt;$900.00, $300.00, $1,200.00&lt;/code&gt; from an invoice. So I wrote a check in code that only accepts the copy if it is shaped like a secret, with letters mixed with digits, six or more digits in a row, or a dollar amount on an account screen. On the first two rounds it was perfect: 10 of 10 secrets, no false alarms.&lt;/p&gt;

&lt;p&gt;I did not trust that, since I had written the check while looking at those exact answers. So I made a third round of ten, this time aimed at the check: a 4-digit login code, a Wi-Fi passphrase that is four plain words, a Slack DM with a staging password, plus a package tracking number and an order number as traps. The check caught 2 of 5 and flagged both traps. No check at all would have caught 4 of 5.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Private check&lt;/th&gt;
&lt;th&gt;All 15 secrets&lt;/th&gt;
&lt;th&gt;False alarms on 27 ordinary screenshots&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Yes/no prompt&lt;/td&gt;
&lt;td&gt;7 of 15&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Copy-the-secret prompt&lt;/td&gt;
&lt;td&gt;14 of 15&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Copy-the-secret prompt + shape check&lt;/td&gt;
&lt;td&gt;12 of 15 (2 of 5 on the round it had not seen)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tesseract OCR + rules&lt;/td&gt;
&lt;td&gt;11 of 15&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Those are the CPU runs, where I did the experiment. In the browser the two prompts came out at 8 of 15 with no false alarms and 15 of 15 with 11, and those are the numbers the app shows next to the setting.&lt;/p&gt;

&lt;p&gt;The shape check is not in the app. The app has a setting instead. "Careful" is the yes/no prompt, and it is the default because it has never sent an ordinary screenshot to &lt;code&gt;Private&lt;/code&gt;. "Catch more" is the copy-the-secret prompt. In the browser it caught every secret and also filed a grocery receipt, a hotel booking, a SQL query and a disk warning as private. The page says plainly that neither one is a security tool. When the copy prompt copies a secret, the worker throws the text away before it reaches the page.&lt;/p&gt;

&lt;p&gt;Two limits on all of this: I made the screenshots and the labels, and I also wrote the prompts, so these numbers are a sanity check and not a benchmark. And clean HTML renders are easier than real screenshots, which have notifications, dark mode and half a window cut off.&lt;/p&gt;

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

&lt;p&gt;Because of what is in a screenshot folder. In 52 made-up screenshots I needed a fake card, a fake driver license, recovery codes, a password manager entry and AWS keys, because that is what people screenshot. A hosted vision API would see every one of them before deciding which ones are private. Here the page sets a Content Security Policy that allows connections to three places: the site itself, the jsDelivr CDN for library code, and Hugging Face for the model weights. The model worker starts from a blob URL so it inherits the same policy. The browser enforces it, and the "Run the privacy test" button lets anyone check.&lt;/p&gt;

&lt;p&gt;Cost is the second reason, and it is what makes watch mode reasonable. Every screenshot is an image plus a prompt, about 640 tokens before the model writes anything, and a busy person takes several a day, forever. On a hosted API that bill never stops. With open weights it runs on the GPU you already have, at about a second and a half per screenshot on mine.&lt;/p&gt;

&lt;p&gt;Third, open weights let me look inside the knobs. I could set the vision encoder's token budget myself and measure what it costs: 140 image tokens was about a third faster on the CPU and named files just as well, but put three more screenshots in the wrong folder. I could also find where the export stops (560 tokens fails). With a closed API those are settings someone else picks.&lt;/p&gt;

&lt;p&gt;Fourth, it keeps working without a connection once the model is cached, and Gemma 4 is Apache 2.0, so nothing about this depends on a provider staying around or keeping its price.&lt;/p&gt;

&lt;p&gt;A large hosted model would probably do better on the private check. That was not measured here, and given what the check is for, it is the one job I would least want to send to a server.&lt;/p&gt;

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

&lt;p&gt;I do not have a DevRelay export, so here is the plain account. I directed an AI coding agent, Claude, through this project. It wrote the app, made the 52 test screenshots and their labels, ran every evaluation (the browser ones in Chrome on my Mac), wrote the OCR baseline and the scoring, and drafted this post. The three rounds of the private check happened in the order described above. Every raw model answer is in &lt;code&gt;eval/results/&lt;/code&gt;, so the tables can be checked.&lt;/p&gt;

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

&lt;p&gt;At 1.4 seconds a screenshot, a Desktop with 300 of them is about seven minutes of the laptop working while I do something else, and after that watch mode handles each new one in a second or two. The part I actually wanted is the search: Spotlight can then find "KeyError" or "Garner" or "receipt" in file names that used to be timestamps. I have not run it on my own Desktop for this post, so I do not have a real before-and-after count to share yet.&lt;/p&gt;

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

&lt;p&gt;Best Use of Gemma. The app runs Gemma 4 E2B's vision model locally in the browser on WebGPU, and the write-up measures two image-token budgets and two prompts on the same labeled screenshots.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Sophia Fabrizio, Rebecca Lurie and Deanne Westerman, "Digital amnesia: The aftermath of a screenshot," &lt;em&gt;Memory &amp;amp; Cognition&lt;/em&gt; (2026), as reported by &lt;a href="https://www.binghamton.edu/news/story/6397/digital-amnesia-taking-screenshots-makes-you-more-likely-to-forget-information" rel="noopener noreferrer"&gt;Binghamton University News&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://huggingface.co/onnx-community/gemma-4-E2B-it-ONNX" rel="noopener noreferrer"&gt;Gemma 4 E2B ONNX model card&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>gemma</category>
      <category>opensource</category>
    </item>
    <item>
      <title>RateCon Radar: Gemma reads a trucker's contract in a browser tab, and the contract never leaves the laptop</title>
      <dc:creator>Anudeep Bonagiri</dc:creator>
      <pubDate>Tue, 13 Oct 2026 02:40:50 +0000</pubDate>
      <link>https://dev.to/anudeep_bonagiri/ratecon-radar-gemma-reads-a-truckers-contract-in-a-browser-tab-and-the-contract-never-leaves-the-1h6l</link>
      <guid>https://dev.to/anudeep_bonagiri/ratecon-radar-gemma-reads-a-truckers-contract-in-a-browser-tab-and-the-contract-never-leaves-the-1h6l</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I built this with an AI coding agent. The section called My Agent Session says exactly what the agent did.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;On April 22, 2013, a driver started a thread on TruckersReport called "&lt;a href="https://www.thetruckersreport.com/truckingindustryforum/threads/fined-for-delivery-early.211242/" rel="noopener noreferrer"&gt;Fined for delivery early&lt;/a&gt;." It ran six pages. Near the end a poster named Big Jay gave the advice the thread had been circling: follow the rate confirmation exactly, whether or not you agree with it. Another reply pointed out that the carrier is the one who gets fined, since the charge is either passed down from the shipper or written into the rate con. A second six-page thread from the same year is about a broker deducting from the rate over an early arrival.&lt;/p&gt;

&lt;p&gt;A rate confirmation is the one-load contract a freight broker sends a carrier. The top of it has the pickup, the delivery and the pay. The rest is terms, and the terms are where the money goes. FreightWaves' &lt;a href="https://www.freightwaves.com/news/every-load-you-haul-starts-here-dont-skip-the-fine-print" rel="noopener noreferrer"&gt;guide to the fine print&lt;/a&gt; lists $150 per hour for a late arrival, $250 for a tracking lapse and up to $300 for a dirty trailer, and says small carriers often lose $250 to $500 to deductions like these. Owner-operators sign these documents from the seat of a truck, usually with the load about to go to someone else.&lt;/p&gt;

&lt;p&gt;RateCon Radar reads the document before the driver signs it. You drop in the PDF. It pulls out the broker, load number, pay, lane, dates and miles, then lists every clause that can cost you money. Each flag shows the sentence copied from the document, and above it one line in plain English.&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%2Fbnk46rd5s738k7uns9yj.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%2Fbnk46rd5s738k7uns9yj.png" alt="RateCon Radar after reading a sample rate confirmation" width="800" height="685"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It also tells you what is missing. In a 2018 thread called "&lt;a href="https://www.thetruckersreport.com/truckingindustryforum/goto/post?id=7971156" rel="noopener noreferrer"&gt;Signed Rate Con&lt;/a&gt;," the original poster argued that detention and TONU (the fee for a truck that is ordered and then cancelled) are the terms worth negotiating load by load. Another poster replied that in about 800 loads that year they had seen exactly one sheet with a carrier's accessorial terms spelled out. So when a confirmation says nothing about detention, layover or TONU, the app drafts the message that asks for them, with rates you can edit.&lt;/p&gt;

&lt;p&gt;The whole thing runs in a browser tab. The model is Google's open-weight Gemma 4, running on the driver's own GPU through WebGPU. The PDF is never uploaded, because there is no server to upload it to.&lt;/p&gt;

&lt;p&gt;Who would pay for it? An owner-operator who books their own freight, or a small dispatch service that reads dozens of rate cons a day. The pitch is arithmetic. One avoided $150 late fee covers years of a tool that costs a few dollars a month. Nobody has paid yet. More on that under What is next.&lt;/p&gt;

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

&lt;p&gt;Live: &lt;strong&gt;&lt;a href="https://anudeep-bonagiri.github.io/ratecon-radar/" rel="noopener noreferrer"&gt;https://anudeep-bonagiri.github.io/ratecon-radar/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Code, test documents and raw results: &lt;strong&gt;&lt;a href="https://github.com/anudeep-bonagiri/ratecon-radar" rel="noopener noreferrer"&gt;https://github.com/anudeep-bonagiri/ratecon-radar&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To try it, open the link in Chrome or Edge on a laptop or desktop and press one of the sample buttons. The first run downloads the model, which is 3.1 GB, and after that it loads from the browser's own storage in about four seconds. A one-page rate con takes 20 to 31 seconds on an Apple Silicon Mac. If you have a real rate confirmation, drop it in. It will not go anywhere.&lt;/p&gt;

&lt;p&gt;There is a button at the bottom of the page called "Run the privacy test." It tries to send a request to an outside server from the page and from the model's worker, and it only passes if the browser reports that it blocked both.&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/anudeep-bonagiri" rel="noopener noreferrer"&gt;
        anudeep-bonagiri
      &lt;/a&gt; / &lt;a href="https://github.com/anudeep-bonagiri/ratecon-radar" rel="noopener noreferrer"&gt;
        ratecon-radar
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Read the fine print on a freight rate confirmation before you sign. Runs open-weight Gemma in the browser with WebGPU. Nothing is uploaded.
    &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;RateCon Radar&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Read the fine print on a freight rate confirmation before you sign it.&lt;/p&gt;
&lt;p&gt;Live demo: &lt;a href="https://anudeep-bonagiri.github.io/ratecon-radar/" rel="nofollow noopener noreferrer"&gt;https://anudeep-bonagiri.github.io/ratecon-radar/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Drop in a rate confirmation PDF. RateCon Radar pulls out the load details and lists every clause that can cost the carrier money: late and early arrival fines, tracking penalties, detention conditions, paperwork deadlines, quick pay fees, chargebacks. Each flag shows the exact sentence from the document next to a one-line reading in plain English. It also tells you what is not in writing (detention, layover, TONU) and drafts a short message asking the broker to add it.&lt;/p&gt;
&lt;p&gt;The model is Google's open-weight Gemma, and it runs inside the browser tab on the user's own GPU. The document is never uploaded.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why it runs locally&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;A rate confirmation shows what a broker is paying on a lane, and carriers sign them under time pressure, often from a truck. An owner-operator should not…&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/anudeep-bonagiri/ratecon-radar" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Everything is in the repository: the app, both prompts (&lt;code&gt;core.js&lt;/code&gt;), the eight test documents with their labels (&lt;code&gt;eval-docs.mjs&lt;/code&gt;), the raw model outputs from the benchmark (&lt;code&gt;bench-results.json&lt;/code&gt;) and the grading of the plain-English lines (&lt;code&gt;meaning-grades.mjs&lt;/code&gt;). &lt;code&gt;node bench-score.mjs test&lt;/code&gt; reproduces the results table below. The code is MIT licensed.&lt;/p&gt;

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

&lt;p&gt;pdf.js extracts the text in the browser. The text is split into sentences, and a filter drops the ones that cannot be money terms. Gemma reads each remaining sentence alongside 13 worked examples and answers with a label and a line of under 20 words. A second prompt extracts the load facts as JSON, and every value is then checked against the document. If the document does not contain it, the app marks it with a question mark. The 1B model got 17 of 48 facts wrong or missing, and that check kept every one of them from being shown as confirmed. Totals, missing protections and the counter-terms message are ordinary code.&lt;/p&gt;

&lt;p&gt;The stack is Transformers.js 4.3.1 on WebGPU, pdf.js and plain JavaScript modules. There is no build step and no backend. It is hosted on GitHub Pages.&lt;/p&gt;

&lt;p&gt;Two details are worth passing on. Chrome checks a module worker's imports against &lt;code&gt;worker-src&lt;/code&gt; and not &lt;code&gt;script-src&lt;/code&gt;, so the model library was blocked until the policy allowed the CDN there too. And the 4-bit weights do not load on the WebAssembly backend ("Could not find an implementation for GatherBlockQuantized"), so there is no CPU fallback and the app requires WebGPU.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the tests showed
&lt;/h3&gt;

&lt;p&gt;The test set is eight made-up rate confirmations rendered to PDF, with 89 labeled money clauses. Two documents were used while writing the prompt. The table below is for the other six, which hold 65 clauses and were scored once after the prompt was frozen. Everything ran in Chrome 154 on an Apple Silicon Mac, through a benchmark page that uses the same worker as the app.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;System&lt;/th&gt;
&lt;th&gt;Money clauses found&lt;/th&gt;
&lt;th&gt;False alarms&lt;/th&gt;
&lt;th&gt;Load facts right&lt;/th&gt;
&lt;th&gt;Time per document&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 E2B (3.1 GB)&lt;/td&gt;
&lt;td&gt;64 of 65&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;48 of 48&lt;/td&gt;
&lt;td&gt;26 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 3 1B (760 MB)&lt;/td&gt;
&lt;td&gt;23 of 65&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;31 of 48&lt;/td&gt;
&lt;td&gt;15 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 3 270M (270 MB)&lt;/td&gt;
&lt;td&gt;0 of 65&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0 of 48&lt;/td&gt;
&lt;td&gt;7 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Keyword rules, no model&lt;/td&gt;
&lt;td&gt;46 of 65&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;not applicable&lt;/td&gt;
&lt;td&gt;instant&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The keyword baseline did well, and it is worth saying so. Seven regular expressions found 46 of 65 clauses. What they missed was paraphrase. "Carrier shall forfeit $100 of the agreed rate for every hour, or part of an hour, that the vehicle is not at the destination by the required delivery time" contains no "late," no "fee" and no "fine." Gemma flagged it and wrote: "You forfeit $100 for every hour the truck is late." The rules also flagged "Late model, clean and dry equipment is required" as a late-arrival clause. Gemma did not.&lt;/p&gt;

&lt;p&gt;The one clause Gemma 4 missed never reached it. "Payment terms: net 30." is four words long, and the pre-filter skipped sentences under five words. After this run I lowered that limit to four and ran the six documents again. Gemma 4 then found 65 of 65. The change also let two total-pay lines through, which it flagged, so false alarms went from 8 to 10. And its reading of the newly found clause was "You have 30 days to pay," which has the direction backwards, the same mistake described next. The table shows the first run, because that is the one scored before anything was changed.&lt;/p&gt;

&lt;p&gt;The plain-English lines are the weak part. All 77 lines Gemma 4 wrote for the test documents were read against their quotes. 64 were accurate and 13 were wrong. Nine of the 13 mixed up who pays whom. The quote said "Cedar Gap pays for excessive loading or unloading delay at $45 per hour," and the model wrote "You pay $45 per hour for delays." For a tool whose job is to tell a driver what a clause costs, that is the worst mistake it could make.&lt;/p&gt;

&lt;p&gt;So the app never shows the model's line without the quote under it, and it now runs a check: if the quote reads as money paid to the carrier and the model's line says the carrier pays, the card gets a warning.&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%2Flrx3ud7vuyb4n4w2y58x.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%2Flrx3ud7vuyb4n4w2y58x.png" alt="A flag card with a who-pays-whom warning" width="799" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That check catches 8 of the 13 bad lines. It was written after seeing those errors, so it has not been tested on anything new.&lt;/p&gt;

&lt;p&gt;Two more limits. The test documents and the prompt came out of the same working session, so the table is a sanity check and not a benchmark. And no real broker paperwork has gone through it yet.&lt;/p&gt;

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

&lt;p&gt;The document is the reason. A rate con shows what a broker pays on a lane and who the customer is. With a hosted model, every one of those documents would go to a third party before the driver had even decided to take the load. Here the page sets a Content Security Policy that allows connections to three places: the site itself, the jsDelivr CDN for library code, and Hugging Face for the model weights. The model worker is started from a blob URL so that it inherits the same policy. The browser enforces the claim, and the test button lets anyone check it.&lt;/p&gt;

&lt;p&gt;Cost is the second reason, and it is what makes this a side hustle. The app judges each sentence separately with the full instructions attached, so one single-page test document came to about 18 model calls and 15,000 input tokens. Real ones are longer: FreightWaves says a broker's general terms can run two to four pages. On a hosted API that is a bill that grows with every document a customer checks. With open weights the customer's GPU does the work, and serving one more trucker costs me nothing. That leaves room to charge five dollars a month, or to give it away.&lt;/p&gt;

&lt;p&gt;Third, open weights mean the model can be chosen by measuring it. Three Gemma sizes went through the same page on the same documents, and the table above is the result. The smallest model answered NONE or nothing at all to every sentence, and when asked for the load facts it mostly copied the field descriptions back. The 1B model found a third of the clauses. Gemma 4 E2B is the first size that does the job, so that is the default, and the picker in the app tells users what the smaller ones cost them. Gemma 4 is also Apache 2.0, which matters if this ever becomes something people pay for.&lt;/p&gt;

&lt;p&gt;Fourth, it keeps working without a connection. A service worker caches the app and Transformers.js caches the weights. This was tested in headless Chromium with the network switched off, using the smallest model: the page reopened and the model loaded from cache in three seconds. It has not been tested on a phone or on truck-stop Wi-Fi.&lt;/p&gt;

&lt;p&gt;A large hosted model would probably write better plain-English lines than a model this size. That was not measured here, and this is a document I would not send out anyway.&lt;/p&gt;

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

&lt;p&gt;I do not have a DevRelay export of the session, so here is the plain account. I directed an AI coding agent, Claude, through this project. It read the forum threads, wrote the code and the test documents, ran the benchmark in Chrome on my Mac, graded the 77 lines and drafted this post. The repository has every prompt, the test documents, the raw model outputs and the grades, so the numbers can be checked.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is next
&lt;/h2&gt;

&lt;p&gt;Nobody has used it on a real load yet, so there is no first-user section in this post. The next step is to run real rate confirmations through it with a working owner-operator watching, and to ask the question this week's theme asks: would you pay for this? After that: add OCR for scanned PDFs, and try fine-tuning the 270M model on labeled clauses, since a 270 MB download would suit a phone far better than a 3.1 GB one.&lt;/p&gt;

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

&lt;p&gt;Best Use of Gemma. The app runs Gemma 4 E2B locally in the browser, and the benchmark compares it with Gemma 3 1B and Gemma 3 270M on the same task.&lt;/p&gt;

&lt;p&gt;RateCon Radar is a reading aid and not legal advice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;TruckersReport, "&lt;a href="https://www.thetruckersreport.com/truckingindustryforum/threads/fined-for-delivery-early.211242/" rel="noopener noreferrer"&gt;Fined for delivery early&lt;/a&gt;" (2013)&lt;/li&gt;
&lt;li&gt;TruckersReport, "&lt;a href="https://www.thetruckersreport.com/truckingindustryforum/threads/ch-robinson-deducted-my-rate-for-arriving-early.232542/" rel="noopener noreferrer"&gt;CH Robinson deducted my rate for arriving early&lt;/a&gt;" (2013)&lt;/li&gt;
&lt;li&gt;TruckersReport, "&lt;a href="https://www.thetruckersreport.com/truckingindustryforum/goto/post?id=7971156" rel="noopener noreferrer"&gt;Signed Rate Con&lt;/a&gt;" (2018)&lt;/li&gt;
&lt;li&gt;Adam Wingfield, "&lt;a href="https://www.freightwaves.com/news/every-load-you-haul-starts-here-dont-skip-the-fine-print" rel="noopener noreferrer"&gt;Every Load You Haul Starts Here: Don't Skip the Fine Print&lt;/a&gt;," FreightWaves (2025)&lt;/li&gt;
&lt;li&gt;Adam Wingfield, "&lt;a href="https://www.freightwaves.com/news/how-to-read-your-rate-con-like-a-pro" rel="noopener noreferrer"&gt;How to Read Your Rate Con Like a Pro&lt;/a&gt;," FreightWaves (2025)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
    <item>
      <title>Lookout: the alarm that goes off before a scam's getaway</title>
      <dc:creator>Anudeep Bonagiri</dc:creator>
      <pubDate>Mon, 05 Oct 2026 23:36:25 +0000</pubDate>
      <link>https://dev.to/anudeep_bonagiri/lookout-the-alarm-that-goes-off-before-a-scams-getaway-1hgc</link>
      <guid>https://dev.to/anudeep_bonagiri/lookout-the-alarm-that-goes-off-before-a-scams-getaway-1hgc</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1snh596istqwnesvsr0q.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1snh596istqwnesvsr0q.gif" alt=" " width="600" height="338"&gt;&lt;/a&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/mlh-hackathon"&gt;MLH x DEV Writing Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Lookout is a practice wallet where a risky payment waits until someone you trust agrees to it.&lt;/p&gt;

&lt;p&gt;The theme at Rowdy Hacks XII was "Heist," and the title sponsor, Swivel, asked teams to build a shield against social engineering. So we flipped the theme around. Instead of planning a heist, we built the lookout who stops one.&lt;/p&gt;

&lt;p&gt;People over 60 lost billions of dollars to scams last year, and in almost every case the victim approved the payment themselves. Banks check whether the account holder authorized a transfer. In a scam they did authorize it, because a stranger on the phone talked them into it. The fraud happens in the conversation, so a login check never sees it.&lt;/p&gt;

&lt;p&gt;Lookout steps in right before the money moves. In our demo, Rosa opens the wallet to send $2,000 because "the IRS" texted her about a warrant. Lookout reads the payment along with the message that prompted it, scores the risk from 0 to 100, and decides to allow, verify, or hold. On a hold, Rosa sees which stage of the heist the scammer has reached, a few plain-language reasons, and hears a spoken warning in English or Spanish. Her daughter Maya, the trusted contact she picked ahead of time, gets the request on her own phone with the amount, the recipient and the signals that fired. Maya never sees passwords or codes. She taps approve or deny, and Rosa gets the answer along with a safer next step.&lt;/p&gt;

&lt;p&gt;We kept a few rules the whole weekend. Gemini interprets the message, but a small scoring function in plain code makes the decision, and no single signal can hold a payment on its own, since words like "urgent" show up in normal texts all the time. Each point in the score maps to a sentence Rosa can read. Lookout never moves money by itself: releasing a held payment requires a human to confirm, and that check lives in the code instead of the prompt. Codes are redacted before the request reaches anyone else.&lt;/p&gt;

&lt;p&gt;We also added a &lt;code&gt;/learn&lt;/code&gt; page, a six-round game where you read a message, flag the scam signals and watch Lookout's score build using the real weights and thresholds. Catching a scam once helps one person on one day. Teaching the pattern sticks around longer.&lt;/p&gt;

&lt;p&gt;The thing I'll take away from this build is that catching scams turned out to be the easier half. The harder half was leaving the rent payment and a grandkid's birthday money alone, because one false alarm costs more trust than a missed scam.&lt;/p&gt;

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

&lt;p&gt;You can visit the landing page at &lt;a href="https://stoptheheist.us" rel="noopener noreferrer"&gt;stoptheheist.us&lt;/a&gt; and try the scam-signal trainer at &lt;a href="https://stoptheheist.us/learn" rel="noopener noreferrer"&gt;stoptheheist.us/learn&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/anudeep-bonagiri" rel="noopener noreferrer"&gt;
        anudeep-bonagiri
      &lt;/a&gt; / &lt;a href="https://github.com/anudeep-bonagiri/Lookout" rel="noopener noreferrer"&gt;
        Lookout
      &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;Lookout&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A risky payment waits until someone you trust agrees. This is a practice wallet!&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Main application&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;apps/web&lt;/code&gt; is the landing page, the wallet, and the Lookout's phone.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apps/api&lt;/code&gt; receives a payment check and returns allow, pause, or hold.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Open &lt;code&gt;/&lt;/code&gt; for the door. Open &lt;code&gt;/wallet&lt;/code&gt; for Rosa. Open &lt;code&gt;/crew/maya-demo&lt;/code&gt; for Maya. On a wide screen the wallet sits in one phone. On a real phone it fills the screen.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Data&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;apps/api/schema.sql&lt;/code&gt; is the Tiger tables and the hourly chart.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apps/api/app/db.py&lt;/code&gt; is the records: payments, approvals, reasons, watchers, pulse samples.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apps/api/app/samples&lt;/code&gt; is the IRS text used in the demo.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How a payment is decided&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;apps/api/app/labels.py&lt;/code&gt; — Gemini, or the offline rules, reads the words.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apps/api/app/scoring.py&lt;/code&gt; — the fixed score. One signal cannot hold a payment.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apps/api/app/why.py&lt;/code&gt; — why the money is moving, ranked by threat and updated from a finished payment or a denial.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apps/api/app/desks&lt;/code&gt; — watchers. A new file…&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/anudeep-bonagiri/Lookout" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Partner Technologies
&lt;/h2&gt;

&lt;p&gt;Gemini does the reading. It takes the payment note and the suspicious message (pasted text or a screenshot) and returns structured JSON against a fixed schema with fields for an authority claim, a threat or reward, urgency, secrecy and a sensitive request. Using structured output was the decision that made everything else work, because the model can only hand back labels our scoring layer checks. It never gets to return a verdict. If Gemini errors out or the key is missing, Lookout falls back to an offline rules engine so the demo survives bad venue Wi-Fi. Gemini also writes replies for our phone voice agent, with scripted lines as a backup.&lt;/p&gt;

&lt;p&gt;ElevenLabs speaks the warnings using &lt;code&gt;eleven_multilingual_v2&lt;/code&gt;, with one English voice and one Spanish voice. For an older person in the middle of a scam, hearing "You are being rushed. That is how scams work." out loud gets through better than a red banner on the screen. San Antonio is a bilingual city, so Spanish had to be there from the start.&lt;/p&gt;

&lt;p&gt;Tiger Data (TimescaleDB) stores payment attempts, risk checks and vitals samples as hypertables. A continuous aggregate rolls the risk checks into an hourly chart for Maya's history view. When no Tiger URL is configured, the API drops to SQLite on a Docker volume, which got us through setup more than once.&lt;/p&gt;

&lt;p&gt;We also wired up Presage SmartSpectra to read pulse and breathing from the camera. A spike only counts after a 15-second baseline, and if the sensor isn't there the code reports nothing instead of making up a number. Elevated pressure adds one signal to the score and nothing more.&lt;/p&gt;

&lt;p&gt;The rest of the stack is FastAPI and Next.js, Twilio for a call-in voice check, a shared list of reported scam numbers, an ESP32 alarm light that polls for active holds, and Docker Compose behind Caddy with automatic HTTPS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hackathon Experience
&lt;/h2&gt;

&lt;p&gt;Rowdy Hacks XII was at UTSA, my home school, and I built Lookout with my teammate Takshi Savaliya. For 24 hours the room was full of vaults, escape rooms and getaway cars.&lt;/p&gt;

&lt;p&gt;Around 3am the first thing to break was our plan. We had a design doc that mapped out a dozen prize tracks, and by the middle of the night it was clear we couldn't ship all of it. We cut hard and protected the core flow of wallet, risk check, hold screen and trusted-contact approval. Everything else had to earn its way back in.&lt;/p&gt;

&lt;p&gt;Then deployment broke right before judging. Our config found the repo root with &lt;code&gt;parents[3]&lt;/code&gt;, which worked fine on our laptops and overflowed inside the container at &lt;code&gt;/app&lt;/code&gt;, so uvicorn crashed on startup. A type check in the scroll intro also failed the production build. Both fixes were one line each and went in during the last stretch before submission. Twilio's trial account only calls verified numbers, too, so for the demo the "call my phone" button turned into "call in."&lt;/p&gt;

&lt;p&gt;What I'll remember most is that many of the judges were volunteers without a technical background. That pushed us to make Lookout make sense in 30 seconds: "You're grandma. You just got this text. Try to send the money." When someone who doesn't write code can feel it work in their own hands, I know the engineering underneath is doing its job.&lt;/p&gt;

</description>
      <category>mlhacks</category>
      <category>devchallenge</category>
      <category>hackathon</category>
    </item>
  </channel>
</rss>
