<?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: Encrypted</title>
    <description>The latest articles on DEV Community by Encrypted (@encrypted_0cce738af39fba7).</description>
    <link>https://dev.to/encrypted_0cce738af39fba7</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%2F4156040%2F6c3bfeec-d881-4adb-92e6-335fc50bb4b0.png</url>
      <title>DEV Community: Encrypted</title>
      <link>https://dev.to/encrypted_0cce738af39fba7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/encrypted_0cce738af39fba7"/>
    <language>en</language>
    <item>
      <title>NoticeCatcher: Qwen3-8B Finds the Deadlines in a WhatsApp Group, and Plain Code Picks the Dates</title>
      <dc:creator>Encrypted</dc:creator>
      <pubDate>Sun, 25 Oct 2026 09:33:01 +0000</pubDate>
      <link>https://dev.to/encrypted_0cce738af39fba7/noticecatcher-qwen3-8b-finds-the-deadlines-in-a-whatsapp-group-and-plain-code-picks-the-dates-d7f</link>
      <guid>https://dev.to/encrypted_0cce738af39fba7/noticecatcher-qwen3-8b-finds-the-deadlines-in-a-whatsapp-group-and-plain-code-picks-the-dates-d7f</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;Every class has &lt;em&gt;that&lt;/em&gt; WhatsApp group. 300 messages a day, memes, "ok sir", "who has the notes?" and somewhere in the middle, one message with the exam date. I mute the group to stay sane, and then I'm the one who misses the deadline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NoticeCatcher&lt;/strong&gt; is my lazy fix. You export the group chat as a .txt file, and it reads the whole thing for you. It pulls out only the notices that matter (exams, deadlines, workshops, cancellations) and writes a calendar file (.ics) you can open on your phone.&lt;/p&gt;

&lt;p&gt;On the built-in fake chat from "Demo College" (40 messages), it found &lt;strong&gt;4 events&lt;/strong&gt;, noticed &lt;strong&gt;1 cancellation&lt;/strong&gt;, and set &lt;strong&gt;1 vague notice aside&lt;/strong&gt; for me to check instead of guessing a date.&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/ADD_SCREENSHOT_1" 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/ADD_SCREENSHOT_1" alt="The 4 found notices"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/ADD_SCREENSHOT_2" 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/ADD_SCREENSHOT_2" alt="Cancelled notice, "&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;There is no live demo link. The page runs on my own computer with &lt;code&gt;python serve.py&lt;/code&gt; and only processes the built-in fake sample chat. The screenshots above are from a real run of the real model.&lt;/p&gt;

&lt;p&gt;The main way to use it is the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python cli.py samples/sample_android.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Real output from my run:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Events: 4, Cancelled: 1, Needs Check: 1
Event: Final Exam for CS301 | Start: 2026-10-28 10:00:00
Event: Submit Assignment 2 | Start: 2026-10-20 23:59:00
Event: Project demo | Start: 2026-10-15 14:00:00
Event: Workshop on Cloud Computing | Start: 2026-10-19 10:00:00
Cancelled: Guest lecture on Robotics
Needs Check: annual sports day | Reason: Unclear date: 'sometime next month'
Seconds taken: 68.52
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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/DkHrR" rel="noopener noreferrer"&gt;
        DkHrR
      &lt;/a&gt; / &lt;a href="https://github.com/DkHrR/noticecatcher" rel="noopener noreferrer"&gt;
        noticecatcher
      &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;NoticeCatcher&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;Extracts notices, deadlines, exam dates, and cancellations from WhatsApp group chat exports into standard iCalendar (.ics) files.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What It Does&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;NoticeCatcher parses exported WhatsApp group conversations (Android or iPhone format), identifies announcements with dates or deadlines, resolves dates deterministically, and writes valid &lt;code&gt;.ics&lt;/code&gt; calendar events.&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;p&gt;NoticeCatcher uses a hybrid architecture: &lt;strong&gt;the model proposes, plain code decides&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Parser (&lt;code&gt;parser.py&lt;/code&gt;)&lt;/strong&gt;: Reads raw text exports, handles Android (&lt;code&gt;DD/MM/YYYY, h:mm am/pm - Sender: Text&lt;/code&gt;) and iPhone (&lt;code&gt;[DD/MM/YY, h:mm:ss PM] Sender: Text&lt;/code&gt;) formats in 12h/24h time, preserves multi-line notices, and filters out system notifications and media lines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model Extraction (&lt;code&gt;engine.py&lt;/code&gt;)&lt;/strong&gt;: Sends chunked messages to an open LLM (Qwen/Qwen3-8B) with strict instructions treating chat text as untrusted data. The model proposes candidates with exact date/time words copied verbatim from the text without attempting date math.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic Resolver (&lt;code&gt;resolver.py&lt;/code&gt;)&lt;/strong&gt;…&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/DkHrR/noticecatcher" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;MIT licensed. 32 tests pass.&lt;/p&gt;
&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;The one rule I followed: &lt;strong&gt;the model proposes, plain code decides.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Parser (plain code).&lt;/strong&gt; Reads both Android and iPhone export formats (DD/MM dates), joins multi-line messages, and skips system and media lines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model (Qwen3-8B through Tinker).&lt;/strong&gt; Reads the messages in chunks of about 25 and returns JSON: a title, the date words &lt;em&gt;copied exactly as written&lt;/em&gt; (like "next Monday"), and a time. It is told never to turn those words into a real date. The chat text goes into the prompt marked as data, not as instructions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resolver (plain code).&lt;/strong&gt; This is where dates are decided. "Tomorrow" counts from the date of the message it was written in, not from today. It also checks that the source message really exists. Anything it can't pin down goes to "Needs your check" and is never guessed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;.ics writer (plain code).&lt;/strong&gt; Writes the calendar file in the Asia/Kolkata timezone. Cancelled notices never become events.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why split it like this? A language model is bad at "what date is next Monday?" but good at "is this message an announcement?" So the model only does the second job, and ordinary code does the first.&lt;/p&gt;

&lt;p&gt;I checked two dates by hand against the sample chat:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Project demo tomorrow" was written on 14 Oct 2026, and it resolved to &lt;strong&gt;15 Oct&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;"Workshop is next Monday" was written the same day (a Wednesday), and it resolved to &lt;strong&gt;19 Oct&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What went wrong:&lt;/strong&gt; my first prompt told the model to skip vague dates. The result was "Needs Check: 0", which meant the review list could never show anything. I changed the prompt so the model includes vague notices with their original words, and the resolver now refuses to guess them. The annual sports day ("sometime next month") now lands in the check list, which is where it belongs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Timing:&lt;/strong&gt; the command-line run took 68.52 s for 40 messages, including model startup. Through the local web page it took 40.43 s. These are single runs, not benchmarks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I did not do:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Calendar events get a default length of 1 hour, so "Submit Assignment 2" ends at 00:59 the next day.&lt;/li&gt;
&lt;li&gt;I only tested on fake chats, never on a real group in this post.&lt;/li&gt;
&lt;li&gt;I did not test whether a chat message containing instructions can trick the model.&lt;/li&gt;
&lt;li&gt;I did not host it. The page is local only.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;A class group chat is private: names, plans, half-finished conversations. So it matters to me &lt;em&gt;which&lt;/em&gt; model reads it.&lt;/p&gt;

&lt;p&gt;With an open-weight model, the model is one line in a settings file (&lt;code&gt;MODEL&lt;/code&gt; in &lt;code&gt;.env&lt;/code&gt;). I can swap it for another one without rewriting anything, and I could point the same code at a smaller model running on my own machine. Qwen3-8B is the one I used here.&lt;/p&gt;

&lt;p&gt;Here is the honest limit: &lt;strong&gt;in this version, the chat text is sent to the Tinker API, so it does not stay on my device.&lt;/strong&gt; My laptop has 4 GB of RAM, so I did not run a local model, and I did not compare against a closed model. What open models gave me in this project is the freedom to switch and to see how the pieces work together, not a privacy guarantee.&lt;/p&gt;

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

&lt;p&gt;I did not save a DevRelay session for this project. Claude planned the project and drafted the prompts, Antigravity (Gemini) wrote the code, and I ran everything step by step and checked the output myself.&lt;/p&gt;

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

&lt;p&gt;I haven't had a classmate use it yet, so I won't pretend it saved anyone hours. What I can say honestly: on a 40-message chat it finishes in about a minute, and it did not guess a single date. The one notice it couldn't date came back to me as a question, and that is the kind of laziness I trust.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>RuleFit: an open model rewrites messy product titles, and plain code decides if they pass</title>
      <dc:creator>Encrypted</dc:creator>
      <pubDate>Sun, 18 Oct 2026 13:29:34 +0000</pubDate>
      <link>https://dev.to/encrypted_0cce738af39fba7/rulefit-an-open-model-rewrites-messy-product-titles-and-plain-code-decides-if-they-pass-3j6k</link>
      <guid>https://dev.to/encrypted_0cce738af39fba7/rulefit-an-open-model-rewrites-messy-product-titles-and-plain-code-decides-if-they-pass-3j6k</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;RuleFit cleans up messy product titles so they follow a store platform's rules. You upload a CSV, pick the title column, and download a CSV with a rewritten title, a status (PASS, FIXED or FLAGGED) and the reasons for any failure.&lt;/p&gt;

&lt;p&gt;The first rule pack is Google Shopping titles. Google's &lt;a href="https://support.google.com/merchants/answer/6324415?hl=en" rel="noopener noreferrer"&gt;title docs&lt;/a&gt; set a 150 character limit and say products can be disapproved for things like promotional text or all-caps titles. A store with hundreds of messy titles would otherwise fix them by hand.&lt;/p&gt;

&lt;p&gt;The open model rewrites each title. Then plain Python checks the rewrite: max 150 characters, one line, no promotional phrases, no ALL-CAPS words unless they were in the original, not mostly capitals, no emoji, symbols or HTML, and no new numbers or sizes. A failing row gets one retry with the exact reasons. If it still fails, it is flagged and your original is kept. &lt;strong&gt;The model never decides what passes. The code does.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Who would pay? I think small store owners, or freelancers who clean product feeds for them. That is a guess. I have not found a paying customer, and I did not check whether people already sell this on freelance sites. Bigger feed tools like Feedonomics exist, and I did not compare prices.&lt;/p&gt;

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

&lt;p&gt;There is no live link. I tried Render's free tier and the service kept restarting (details below). This screenshots is from RuleFit running on my laptop with the real model. The header shows Engine: Tinker / Qwen/Qwen3-8B.&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%2Fd74nzl9s7i86eaxlxrhd.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%2Fd74nzl9s7i86eaxlxrhd.png" alt="RuleFit results page: 3 titles rewritten by Qwen3-8B, all PASS" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Real output:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;NIKE AIR ZOOM PEGASUS 40 RUNNING SHOES MENS SIZE 10 FREE SHIPPING!!!&lt;/code&gt; became &lt;code&gt;Nike Air Zoom Pegasus 40 Running Shoes Men's Size 10&lt;/code&gt; (PASS)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Cotton Bath Towels 6 Pack Soft Absorbent Quick Dry 50% off Today Only&lt;/code&gt; became &lt;code&gt;Cotton Bath Towels 6 Pack Soft Absorbent Quick Dry&lt;/code&gt; (PASS)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Blue Denim Shirt Size M Slim Fit Long Sleeve&lt;/code&gt; stayed the same (PASS)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All three passed on the first try, so the retry and FLAGGED paths did not run in this test.&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/DkHrR" rel="noopener noreferrer"&gt;
        DkHrR
      &lt;/a&gt; / &lt;a href="https://github.com/DkHrR/rulefit" rel="noopener noreferrer"&gt;
        rulefit
      &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;RuleFit&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;RuleFit rewrites e-commerce product titles to adhere to catalog rules using a dual-engine architecture: an open language model hosted by Tinker generates candidate rewrites, and deterministic Python validators enforce the rules.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How It Works&lt;/h2&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Model Draft:&lt;/strong&gt; The model drafts an initial rewrite of each title.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic Check:&lt;/strong&gt; Plain code checks the draft against catalog rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One Retry Loop:&lt;/strong&gt; If any rule check fails, the model is invoked once more with the specific failure reasons.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safety Fallback:&lt;/strong&gt; Rows that still fail after retry are marked as &lt;code&gt;FLAGGED&lt;/code&gt;, and your original title is kept.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Rules (&lt;code&gt;packs/google_shopping_titles.json&lt;/code&gt;)&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;max_chars&lt;/code&gt;: Maximum 150 characters.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;not_empty_single_line&lt;/code&gt;: Title must be a single non-empty line.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;banned_phrases&lt;/code&gt;: No promotional phrases ("free shipping", "sale", "best price", "buy now", "limited time", "discount", "cheap", "% off", "today only", "limited offer", "clearance", "hot deal").&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;no_caps_words&lt;/code&gt;: No ALL-CAPS words (4+ letters) unless already present in the original…&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/DkHrR/rulefit" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;MIT licensed, with 67 automated tests. The tests use a stub in place of the model, so they never call it.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model:&lt;/strong&gt; Qwen/Qwen3-8B through Tinker's sampling client (inference only). Thinking is turned off with the &lt;code&gt;qwen3_disable_thinking&lt;/code&gt; renderer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rule packs:&lt;/strong&gt; each platform is one JSON file, so a new niche means a new file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;App:&lt;/strong&gt; Flask. Each upload runs as a background job that the page polls. Results live in memory and expire after 15 minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design:&lt;/strong&gt; Google Stitch. &lt;strong&gt;Code:&lt;/strong&gt; Antigravity (Gemini).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI disclosure:&lt;/strong&gt; Claude helped me plan the project, wrote the prompts I gave Antigravity, and drafted this post. Antigravity wrote the code. I ran the app, checked its outputs and reports, and fixed what they showed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What went wrong&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Antigravity first passed &lt;code&gt;enable_thinking=False&lt;/code&gt; to &lt;code&gt;SamplingParams&lt;/code&gt;. The SDK shows only one generic &lt;code&gt;data&lt;/code&gt; field there, and Tinker picks thinking through the renderer. I found it by inspecting the SDK before trusting the report.&lt;/li&gt;
&lt;li&gt;Two threads importing &lt;code&gt;tinker&lt;/code&gt; at once caused a circular-import crash. Top-level imports fixed it.&lt;/li&gt;
&lt;li&gt;My rules had a loophole: an unchanged ALL-CAPS title would pass, because caps words were allowed if they appeared in the original. I added a "mostly caps" rule.&lt;/li&gt;
&lt;li&gt;Stitch invented a "zero data retention guarantee" badge, an account icon and other fake features. I removed them and added tests that fail if those words come back.&lt;/li&gt;
&lt;li&gt;Twice, Antigravity gave me two different versions of the same test run in one report. After that I only trusted output I could check.&lt;/li&gt;
&lt;li&gt;My first API key never saved because I closed the editor without pressing Ctrl+S.&lt;/li&gt;
&lt;li&gt;On Render's free tier (512 MB) the service restarted about every two minutes, starting shortly after the model warm-up. I suspect memory, but I did not confirm it in Render's metrics, so I can't say that is the cause.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What I did not do&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I have no paying customer and no first user.&lt;/li&gt;
&lt;li&gt;I did not compare against a closed model.&lt;/li&gt;
&lt;li&gt;The rules check form, not meaning. In a test with a fake mock engine, a title cut off mid-word still passed.&lt;/li&gt;
&lt;li&gt;I only tested English product titles.&lt;/li&gt;
&lt;li&gt;RuleFit does not certify anything for Google. The page says "passes RuleFit checks" and nothing stronger.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Because the rules live in code, I don't need the smartest model. I need a cheap one I can call twice on a bad row. An open 8B model fits that. The model name is a single setting, though a different model family would also need its own renderer, so swapping is not completely free. Later I could fine-tune on rows that failed the rules, but I have not done that.&lt;/p&gt;

&lt;p&gt;I did not benchmark a closed API, so I can't say it would do worse. One honest limit: rows go to Tinker, so nothing stays on the user's machine. Open weights would let a store run the same model locally, but I have not built or tested that.&lt;/p&gt;

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

&lt;p&gt;I did not save a DevRelay session. Antigravity (Gemini) wrote the code from prompts I wrote with Claude's help, and I checked each of its reports against raw test output before moving on.&lt;/p&gt;

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

&lt;p&gt;I don't have a first user. Nobody but me has run RuleFit, and nobody has paid for it.&lt;/p&gt;

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

&lt;p&gt;Tinker, for the inference behind Qwen/Qwen3-8B.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>weekendchallenge</category>
    </item>
    <item>
      <title>I built an AI that invents a playground game, then locks my phone so I'd go play it</title>
      <dc:creator>Encrypted</dc:creator>
      <pubDate>Sun, 11 Oct 2026 16:45:25 +0000</pubDate>
      <link>https://dev.to/encrypted_0cce738af39fba7/i-built-an-ai-that-invents-a-playground-game-then-locks-my-phone-so-id-go-play-it-4ol</link>
      <guid>https://dev.to/encrypted_0cce738af39fba7/i-built-an-ai-that-invents-a-playground-game-then-locks-my-phone-so-id-go-play-it-4ol</guid>
      <description>&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Most "touch grass" apps want you to look at them. I wanted one that wants you to stop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Playground Game Maker&lt;/strong&gt; takes a few facts (how many players, their ages, the stuff you have, the space, the minutes) and an open-weight model invents a game for exactly that mix. You tap &lt;strong&gt;Start playing&lt;/strong&gt;, the screen locks behind a countdown, and the phone goes in your pocket.&lt;/p&gt;

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

&lt;p&gt;Live: &lt;a href="https://playground-game-maker.onrender.com/" rel="noopener noreferrer"&gt;https://playground-game-maker.onrender.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is a public demo on Render's free tier, running the real model (&lt;code&gt;Qwen/Qwen3-8B&lt;/code&gt; through Tinker). The free tier sleeps when idle, so the first load can be slow, and the first game after waking can take up to 90 seconds. To protect my credits it allows 5 games per visitor per hour and 100 per day, and it does not save stats online (the stats page and CSV only work in the local version). The screenshots below are from my own computer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhjphb8akemdztk32cphs.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%2Fhjphb8akemdztk32cphs.png" alt="The Make Game form with player count, age, gear, zone and minutes" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The form: who is playing, what you have, how much space and time. The gear box takes free text.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6h22mx2v10extlb64u6a.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%2F6h22mx2v10extlb64u6a.png" alt="A game card made by Qwen3-8B, Tennis Toss Tag, for 4 players aged 7 to 10" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A real game from Qwen3-8B ("Tennis Toss Tag"). It used only the chalk, cones and tennis balls I listed.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fko45oeb9ti46vv6xugoj.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%2Fko45oeb9ti46vv6xugoj.png" alt="Lock screen with a 43:40 countdown, 01:20 elapsed and 97% left" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The phone locks behind a countdown. Elapsed and remaining always add up to the total.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;GitHub: &lt;a href="https://github.com/DkHrR/playground-game-maker" rel="noopener noreferrer"&gt;https://github.com/DkHrR/playground-game-maker&lt;/a&gt; (MIT)&lt;/p&gt;

&lt;p&gt;To run it locally: &lt;code&gt;python app.py&lt;/code&gt;, then put your own model key in &lt;code&gt;.env&lt;/code&gt;.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Flask backend and one HTML page. No accounts, no names, no location, no tracking. In the local version everything is saved in a SQLite file on my computer. Game prompts go to Tinker, so nothing here is "offline".&lt;/li&gt;
&lt;li&gt;The model returns JSON: name, setup, up to 6 rules, how to win, a safety note.&lt;/li&gt;
&lt;li&gt;The lock screen runs on the real clock, so a sleeping screen does not break the countdown.&lt;/li&gt;
&lt;li&gt;The app counts screen seconds next to minutes outside. Outside minutes are self-reported by the player.&lt;/li&gt;
&lt;li&gt;Code written with Antigravity. The interface was designed in Google Stitch (not open source). The games come from Qwen3-8B, served through Tinker's sampling client (inference only, no fine-tuning).&lt;/li&gt;
&lt;li&gt;Hosting: Flask with gunicorn on Render's free tier. The model call goes out to Tinker. Keys live only in Render's environment settings, never in the repo. On my laptop the app used about 350 MB after warm-up and one game (peak 362 MB), which fits Render's 512 MB free tier.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why an Open Model Mattered
&lt;/h2&gt;

&lt;p&gt;A fixed list of games cannot cover "4 kids, two tennis balls, a small yard, 30 minutes". A model can. An open-weight 8B model also means no per-game price and no closed model deciding what is safe for kids. It also let me see exactly where a small model is weak, which led to the most useful part of the project: the safety rules live in code, not in the prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Went Wrong
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The model invents items.&lt;/strong&gt; In my first 3-game check it added things I never listed: a plastic knife, a bucket, a finish line, foam. Telling it "use only the listed items" in the prompt did not fix it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt rules are not safety.&lt;/strong&gt; So the code removes unsafe items from what the player types before the model sees them (knife, scissors, matches, glass, rope and similar). The game card says "Removed unsafe item". The code also scans the model's reply and retries once, and it always adds "Tell a parent or adult where you are playing", because the model only sometimes remembered.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It is not 100% reliable.&lt;/strong&gt; In my real-model check scripts, between 70% and 80% of generations passed (7 of 9, 7 of 10 and 8 of 10 in three runs). Some failed and I do not know why. Once warm, most games took 5 to 17 seconds. The first game after starting the server took 30 to 90 seconds, and a few took close to a minute.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Empty replies.&lt;/strong&gt; Some calls ended with "No JSON object found". The most likely cause: Qwen3-8B "thinks" before it answers, and my 1,000-token limit could run out before the JSON started. I raised the limit to 2,500. I did not re-run my full check afterwards, so I cannot say it fixed every case.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The games are playable, not great.&lt;/strong&gt; One game's rules were three half-ideas that did not fit together: run to the center, pass the ball, bounce it over cones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A bug in the design code.&lt;/strong&gt; The lock-screen countdown flipped between two numbers. I recorded my screen and found a hardcoded sample timer from the Stitch design running next to the real one. Deleting it fixed it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Another leftover.&lt;/strong&gt; After tapping an age chip, the age box showed the icon name ("All agescheck_cir..."). My screenshots use the default age.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A fake test result.&lt;/strong&gt; My last scripted 20-call test hung, and Antigravity then ran it against my mock engine: 20 of 20 "passes" in 0.00 seconds. I threw those results away because they came from a fake model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free credits.&lt;/strong&gt; Backboard's free credit could not pay for chat models, so I moved to Tinker.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F00pm2t5l1ojwzr7mtmjw.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%2F00pm2t5l1ojwzr7mtmjw.png" alt="Game rules and a safety note that starts with Removed unsafe item" width="799" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The code removed the unsafe items I typed (jump rope, knife, air gun) before the model saw them, and it added the parent reminder. The rules and note still mention a chalkboard and foam balls.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Did Not Do
&lt;/h2&gt;

&lt;p&gt;I did not field-test this outside with other people, so I have no play data, ratings, or "minutes outside" to report. The checks above are lab tests on my own laptop.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tinker:&lt;/strong&gt; the games are generated by Qwen3-8B on Tinker, inference only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Render:&lt;/strong&gt; the demo runs as a Render free-tier web service. &lt;code&gt;render.yaml&lt;/code&gt; is in the repo.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  AI Disclosure
&lt;/h2&gt;

&lt;p&gt;Code built with Antigravity, interface designed with Google Stitch, games generated by Qwen3-8B, and this post drafted with Claude and edited by me.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>OneInbox: a fine-tuned 4B model that reads my inbox so I don't have to</title>
      <dc:creator>Encrypted</dc:creator>
      <pubDate>Sun, 04 Oct 2026 14:58:29 +0000</pubDate>
      <link>https://dev.to/encrypted_0cce738af39fba7/oneinbox-a-fine-tuned-4b-model-that-reads-my-inbox-so-i-dont-have-to-23k7</link>
      <guid>https://dev.to/encrypted_0cce738af39fba7/oneinbox-a-fine-tuned-4b-model-that-reads-my-inbox-so-i-dont-have-to-23k7</guid>
      <description>&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;OneInbox is a daily email digest that sorts my inbox into four buckets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Action required:&lt;/strong&gt; needs a reply, or has a deadline within 7 days&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Worth a look:&lt;/strong&gt; useful, but nothing to do&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FYI:&lt;/strong&gt; receipts, confirmations, security notices&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Noise:&lt;/strong&gt; promos, newsletters, social&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The idea came from a complaint in a hackathon Discord about how tiring it is to keep checking inboxes. I have the same problem, so I built it for my own inbox.&lt;/p&gt;

&lt;p&gt;The core is a LoRA fine-tune of Qwen3.5-4B (Apache 2.0). Each morning it reads the last 24 hours of mail and produces a page I can read on my phone in under a minute. Every item has buttons to mark it Accurate or Wrong, silence the sender, or always show it.&lt;/p&gt;

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

&lt;p&gt;Live: &lt;a href="https://oneinbox-web.onrender.com/digest?token=hacktober2026" rel="noopener noreferrer"&gt;https://oneinbox-web.onrender.com/digest?token=hacktober2026&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It runs in &lt;strong&gt;demo mode&lt;/strong&gt; on 25 synthetic emails, classified by the fine-tuned model. The first load can take about 30 seconds, because Render's free tier sleeps when idle. Due dates are in September because the sample emails are synthetic, and timestamps are UTC.&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%2Fbs9yd9mj8cuqoaxlrdsy.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%2Fbs9yd9mj8cuqoaxlrdsy.png" alt="OneInbox digest page showing Action Required, Worth a Look and FYI sections" width="800" height="1040"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/DkHrR/oneinbox" rel="noopener noreferrer"&gt;https://github.com/DkHrR/oneinbox&lt;/a&gt; (MIT)&lt;/li&gt;
&lt;li&gt;Model: &lt;a href="https://huggingface.co/dKhRr/oneinbox-qwen3.5-4b-lora" rel="noopener noreferrer"&gt;https://huggingface.co/dKhRr/oneinbox-qwen3.5-4b-lora&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Data.&lt;/strong&gt; I didn't want to put a real inbox into a hackathon project, so I generated 600 synthetic emails (150 per label) with Qwen3.6-35B-A3B on Tinker. Sender names match the type of mail, deadlines are computed from each email's received date, and a second pass checks every email. I audited the set: no deadline mismatches, and very few subjects shouting "URGENT". I split it into 540 train and 60 validation emails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Training.&lt;/strong&gt; A Tinker LoRA fine-tune of Qwen3.5-4B on the full JSON answer (label, summary, deadline). Training cost about $0.19 to $0.31.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Results&lt;/strong&gt; on the 60 held-out synthetic emails:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variant&lt;/th&gt;
&lt;th&gt;Labels correct&lt;/th&gt;
&lt;th&gt;Macro-F1&lt;/th&gt;
&lt;th&gt;Deadline match&lt;/th&gt;
&lt;th&gt;Cost / 1k emails&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Base 4B, zero-shot&lt;/td&gt;
&lt;td&gt;52/60&lt;/td&gt;
&lt;td&gt;0.86&lt;/td&gt;
&lt;td&gt;23/28&lt;/td&gt;
&lt;td&gt;$0.157&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Base 4B, 3-shot&lt;/td&gt;
&lt;td&gt;56/60&lt;/td&gt;
&lt;td&gt;0.93&lt;/td&gt;
&lt;td&gt;25/28&lt;/td&gt;
&lt;td&gt;$0.278&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fine-tuned 4B&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;58/60&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.97&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;25/28&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0.141&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Base 35B-A3B, zero-shot&lt;/td&gt;
&lt;td&gt;51/60&lt;/td&gt;
&lt;td&gt;0.85&lt;/td&gt;
&lt;td&gt;25/28&lt;/td&gt;
&lt;td&gt;$0.229&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;What this shows, and what it doesn't:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The fine-tune beats 3-shot prompting by two emails. That is a small gain, not a landslide. The bigger point is that it needs no prompt examples, so it costs about half as much per 1,000 emails.&lt;/li&gt;
&lt;li&gt;It is &lt;strong&gt;not faster&lt;/strong&gt;: p50 latency is about 2.85s, against 2.55s for 3-shot.&lt;/li&gt;
&lt;li&gt;Deadline accuracy is tied with 3-shot.&lt;/li&gt;
&lt;li&gt;The test set is synthetic, and its gold labels came from the generator, not from a human. I reviewed the fine-tuned model's mistakes: some were real misses (an off-by-one bank deadline, a missed hospital deadline) and some were debatable labels. Treat these numbers as a sanity check, not a real-world accuracy claim.&lt;/li&gt;
&lt;li&gt;Pricing uses Tinker's published base-model rates, because I found no separate rate for fine-tuned sampling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Memory (Backboard).&lt;/strong&gt; Sender preferences like "always show" and "silence" are stored as Backboard memories and applied by simple code rules each run. I use Backboard only for memory. Accurate/Wrong feedback is logged there but &lt;strong&gt;does not change filtering yet&lt;/strong&gt;. It is saved for future retraining.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hosting (Render + GitHub Actions).&lt;/strong&gt; The digest page is a small Flask service on Render's free tier. The daily run is a GitHub Actions workflow at 07:00 IST, and it posts the finished digest to the service. Render cron needs a paid plan, so I moved the schedule to GitHub Actions to keep the project at $0 to run. The web service keeps nothing on disk, so the digest is saved in Backboard memory and survives restarts.&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%2Fgipyr5azcvsju3vlcfmw.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%2Fgipyr5azcvsju3vlcfmw.png" alt="GitHub Actions run of the daily digest, all steps green" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd Fix Next
&lt;/h2&gt;

&lt;p&gt;No outside person has tried OneInbox yet, so I had an AI reviewer play a first-time user and tell me what felt wrong. This is not user feedback, but its points matched gaps I could already see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No way to open the original email.&lt;/strong&gt; The digest tells you what needs action, but you still have to go find the email yourself. In IMAP mode I can link each item to a mail search for that sender and subject. The demo can't, because its emails are synthetic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accurate / Wrong buttons don't change anything yet.&lt;/strong&gt; They only log feedback, as noted above. Next step is to use that log to adjust sender rules, or to feed it into a retraining run. Until then they are a data-collection tool, not a control.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sender names can hide the real address.&lt;/strong&gt; The full address is only in a tooltip, which doesn't work on a phone. Showing the domain in small text under the name matters for security alerts, where spoofed senders are the whole risk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trusting an AI with deadlines.&lt;/strong&gt; A wrong date on a bill is worse than no digest. The fine-tuned model matched 25/28 deadlines in my test, not 28/28, so I want the original email one tap away, which brings back the first point.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Open Innovation Matters
&lt;/h2&gt;

&lt;p&gt;An inbox is some of the most private text a person has, so I didn't want a closed model deciding what matters in it. With an open-weight 4B model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The weights, my LoRA adapter, and the code are public, and the base model is Apache 2.0. Anyone can inspect, fork, or retrain them.&lt;/li&gt;
&lt;li&gt;A small model is cheap enough to run daily without a subscription.&lt;/li&gt;
&lt;li&gt;My feedback buttons are designed to feed a future fine-tune on someone's own corrections.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tinker:&lt;/strong&gt; generated the dataset, fine-tuned, and evaluated everything on Tinker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Render:&lt;/strong&gt; the digest page runs as a Render free-tier web service. &lt;code&gt;render.yaml&lt;/code&gt; is in the repo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backboard:&lt;/strong&gt; sender preferences, feedback logs, and digest persistence use Backboard memory.&lt;/li&gt;
&lt;/ul&gt;

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