<?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: Muhammad Murtuza Hussain</title>
    <description>The latest articles on DEV Community by Muhammad Murtuza Hussain (@muhammadmurtuzahussain).</description>
    <link>https://dev.to/muhammadmurtuzahussain</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%2F4154813%2F86752f9a-5229-4b61-9e04-390216e7c845.jpg</url>
      <title>DEV Community: Muhammad Murtuza Hussain</title>
      <link>https://dev.to/muhammadmurtuzahussain</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/muhammadmurtuzahussain"/>
    <language>en</language>
    <item>
      <title>Job hunting became my side hustle, so I built Deis (Gemma 4) Tinder for jobs: swipe right, Gemma tailors your CV</title>
      <dc:creator>Muhammad Murtuza Hussain</dc:creator>
      <pubDate>Sun, 18 Oct 2026 20:56:01 +0000</pubDate>
      <link>https://dev.to/muhammadmurtuzahussain/job-hunting-became-my-side-hustle-so-i-built-deis-gemma-4-tinder-for-jobs-swipe-right-gemma-3jcm</link>
      <guid>https://dev.to/muhammadmurtuzahussain/job-hunting-became-my-side-hustle-so-i-built-deis-gemma-4-tinder-for-jobs-swipe-right-gemma-3jcm</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;My contract ended on Wednesday. By then I had tailored 83 CVs by hand this autumn: one per job, each one rewritten to the job ad's own words, each one checked so it didn't claim anything I couldn't defend in an interview. Most early-career people I know are doing the same thing, alone, at night.&lt;/p&gt;

&lt;p&gt;There are AI tools for this. The best known charge per application: reviews put AI Apply's auto-apply credits at about 32 cents to a dollar each, on top of a monthly plan. When you're applying to 500 jobs, that's a few hundred euro you don't have, spent on applications that a model wrote and you never read.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Deis&lt;/strong&gt;. It's Irish for &lt;em&gt;opportunity&lt;/em&gt;, and it's said "desh".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR.&lt;/strong&gt; Deis is a swipe-to-apply job app for early-career people in Ireland. It shows you jobs filtered for your level, your languages and your right to work. Swipe right and open-weight &lt;strong&gt;Gemma 4&lt;/strong&gt; writes a CV, a cover letter and form answers tailored to the job. Every line on that CV points to a fact you confirmed, and code removes anything Gemma can't back up. It runs on your own model: on your laptop through Ollama (with the Wi-Fi off, if you like), on your free Google AI Studio key, or on a server you rent. An application costs about €0. The app is €9.99 once, and the code is open source.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9cxib3x4gcfkfjpqd1pq.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%2F9cxib3x4gcfkfjpqd1pq.gif" alt="Swiping through real Irish jobs in Deis" width="600" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A 90-second check-in.&lt;/strong&gt; Where in Ireland you'd work, how far along you are, whether you can work here now (EU, Stamp 4, Stamp 1G or needing a permit), the kinds of work you want, and any languages besides English.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A profile of small, true facts.&lt;/strong&gt; Upload your CV and Gemma splits it into facts you tick off one by one. LinkedIn won't let apps read your profile, but it will give you your own data: Deis turns LinkedIn's data export into facts without any AI at all.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A deck of real Irish jobs.&lt;/strong&gt; About 300 live early-career jobs at a time, 70 to 100 in a typical deck once your filters run. Deis reads 55 employers' public job boards and shared Google Jobs searches. Then code, not the model, hides what you can't or won't take: roles asking for 3+ years, roles that need German or Turkish, postings that rule out your visa. Every card quotes the posting's own words: "asks for 2+ years of B2B sales experience", "unable to offer visa sponsorship".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swipe right, two ways.&lt;/strong&gt; &lt;em&gt;Quick&lt;/em&gt; builds the kit (fit check, CV, letter, draft answers) in the background while you keep swiping. &lt;em&gt;Careful&lt;/em&gt; shows you the fit first and asks about your gaps: "The role asks for SQL. Where have you used it?" Your answer becomes a proposed fact, you approve it, and every application after that is stronger.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paste a job you found elsewhere.&lt;/strong&gt; It goes through the same code as the boards and lands on top of the deck, offline too.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You apply.&lt;/strong&gt; Download the CV as Word or PDF, copy the answers, open the posting. Deis never applies for you. Auto-apply tools hit account walls and CAPTCHAs, break LinkedIn's terms, and send the same weak application to 500 places. In a hiring market as small as Ireland's, that follows you around.&lt;/li&gt;
&lt;/ol&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%2F397gx10x34xgfg42e774.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%2F397gx10x34xgfg42e774.jpg" alt="The finished kit: the tailored CV next to the fit check" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why not just paste it into ChatGPT?&lt;/strong&gt; You can, and for one application it's fine. For forty it isn't. You paste your CV again every time, the chat forgets which facts you confirmed, and nothing stops it writing "3 years of experience" or "no sponsorship needed" in a confident voice you'll sign. It doesn't know which Irish jobs you can't get, so you find out after the letter is written. Deis keeps your facts in one place, hides those jobs before you see them, checks every line against what you said, and shows you what it removed. And it runs on a model you can keep on your own laptop, so your CV isn't training anybody's next model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who pays?&lt;/strong&gt; Graduates and early-career people in Ireland who are applying to dozens of jobs, and especially international master's graduates on Stamp 1G. Many postings quietly rule them out, and finding that out after writing a cover letter hurts. €9.99 once is less than one month of the subscription tools, and about the price of a takeaway. The first person to really use it paid for it on the call, and the second sale came from someone I've never met. Both stories are below.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Try it:&lt;/strong&gt; &lt;a href="https://deiscareers.tech" rel="noopener noreferrer"&gt;deiscareers.tech&lt;/a&gt;. Choose &lt;em&gt;Try as Aoife&lt;/em&gt; or &lt;em&gt;Try as Rahul&lt;/em&gt;: two fictional graduates, applying for real Irish jobs. The web demo takes no real CV. Your own CV is read in the desktop app, on your computer, so the hosted demo never receives it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Desktop app:&lt;/strong&gt; macOS, Windows and Linux installers, with a 14-day free trial, then €9.99 once. &lt;a href="https://deiscareers.tech/checkout?products=fb94fe7f-d0f8-49a0-8854-4bbe41f25496" rel="noopener noreferrer"&gt;Buy a key here&lt;/a&gt;. Until the end of October, the code &lt;code&gt;hacktoberfest2026&lt;/code&gt; takes 80% off and is applied for you at checkout, so it's €2. The app isn't signed by Apple yet, so macOS asks you to open it once from Privacy &amp;amp; Security. The &lt;a href="https://deiscareers.tech/download" rel="noopener noreferrer"&gt;download page&lt;/a&gt; shows the steps. On a phone, the free Android app and iPhone home screen app run the same demo as the website. Questions, or a key that won't work? Email &lt;a href="mailto:hello@deiscareers.tech"&gt;hello@deiscareers.tech&lt;/a&gt;.&lt;/p&gt;

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


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/MuhammadMurtuzaHussain" rel="noopener noreferrer"&gt;
        MuhammadMurtuzaHussain
      &lt;/a&gt; / &lt;a href="https://github.com/MuhammadMurtuzaHussain/deis" rel="noopener noreferrer"&gt;
        deis
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Swipe-to-apply job app for early-career people in Ireland. Open-weight Gemma tailors your CV and cover letter to each job, and every line traces back to something you told it.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;
  &lt;a href="https://youtu.be/LXKSvYJGxeA" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FMuhammadMurtuzaHussain%2Fdeis%2FHEAD%2Fdocs%2Fpost%2Fyoutube-thumbnail.jpg" alt="Deis: jobs you can actually get. Watch the one-minute film." width="100%"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;b&gt;Jobs you can actually get.&lt;/b&gt; A swipe-to-apply job app for early-career people in Ireland, where open-weight &lt;b&gt;Gemma 4&lt;/b&gt; tailors your CV and code removes anything it can't back up
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://deiscareers.tech" rel="nofollow noopener noreferrer"&gt;&lt;b&gt;Try the web demo&lt;/b&gt;&lt;/a&gt; ·
  &lt;a href="https://youtu.be/LXKSvYJGxeA" rel="nofollow noopener noreferrer"&gt;Watch the film (1 min)&lt;/a&gt; ·
  &lt;a href="https://dev.to/muhammadmurtuzahussain" rel="nofollow"&gt;DEV post&lt;/a&gt; ·
  &lt;a href="https://github.com/MuhammadMurtuzaHussain/deis#download" rel="noopener noreferrer"&gt;Download&lt;/a&gt; ·
  &lt;a href="mailto:hello@deiscareers.tech"&gt;hello@deiscareers.tech&lt;/a&gt; ·
  Built for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12" rel="nofollow"&gt;DEV Hacktoberfest Open-Source AI Challenge, Week 2: Side Hustle&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://github.com/MuhammadMurtuzaHussain/deis/releases/latest/download/Deis-mac-arm64.dmg" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/bd537da53ab21bcd8c5dff6a96b1aec626f4e0391cba163386158e9fb19a5ded/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6d61634f532d4170706c6525323073696c69636f6e2d3042304230433f7374796c653d666f722d7468652d6261646765266c6f676f3d6170706c65266c6f676f436f6c6f723d7768697465" alt="Download for macOS, Apple silicon"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/MuhammadMurtuzaHussain/deis/releases/latest/download/Deis-mac-x64.dmg" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e3380fac074d7b0a38a1ce97cc17528ab769025d933c6674e33411c42b1b14f8/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6d61634f532d496e74656c2d3042304230433f7374796c653d666f722d7468652d6261646765266c6f676f3d6170706c65266c6f676f436f6c6f723d7768697465" alt="Download for macOS, Intel"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/MuhammadMurtuzaHussain/deis/releases/latest/download/Deis-windows-x64.exe" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f942d26375dc6d01901adf5cce0fdb86c84c210a695e7abc3e7b07b1ffc2e03c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f57696e646f77732d36342d2d6269742d3042304230433f7374796c653d666f722d7468652d6261646765266c6f676f3d77696e646f7773266c6f676f436f6c6f723d7768697465" alt="Download for Windows"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/MuhammadMurtuzaHussain/deis/releases/latest/download/Deis-linux-x86_64.AppImage" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/bc2cfbefd0d5c9a541a85a26d2ac1c4d4c2fb4fa8796451bf40af55e10ef1225/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c696e75782d417070496d6167652d3042304230433f7374796c653d666f722d7468652d6261646765266c6f676f3d6c696e7578266c6f676f436f6c6f723d7768697465" alt="Download for Linux"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/MuhammadMurtuzaHussain/deis/releases/latest/download/Deis-android.apk" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4a631ef8c5839ca6003ff606f33188218c05caa478b4093a7533a225c37e5dea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f416e64726f69642d64656d6f2d3042304230433f7374796c653d666f722d7468652d6261646765266c6f676f3d616e64726f6964266c6f676f436f6c6f723d7768697465" alt="Download the Android demo"&gt;&lt;/a&gt;
  &lt;br&gt;
  &lt;a href="https://deiscareers.tech/checkout?products=fb94fe7f-d0f8-49a0-8854-4bbe41f25496" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/cc090a539f4904519371dc9dfe72095d6a926b1fb30706f4572efbf23d6588f7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f427579253230612532306b65792d254532253832254143392e39392532306f6e63652d4338463033433f7374796c653d666f722d7468652d6261646765266c6162656c436f6c6f723d304530463130" alt="Buy a licence key, 9.99 euro once"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/MuhammadMurtuzaHussain/deis/docs/post/gif-deck-swipe-hd.gif"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2FMuhammadMurtuzaHussain%2Fdeis%2FHEAD%2Fdocs%2Fpost%2Fgif-deck-swipe-hd.gif" alt="Swiping through real Irish jobs: every card is a job you can actually get" width="760"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Deis&lt;/em&gt; (said "desh") is Irish for opportunity.&lt;/p&gt;

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

&lt;p&gt;I tailored 83 CVs by hand this autumn: one per job, each rewritten to the job ad's own words and checked so it didn't claim anything I couldn't defend in an interview. Most early-career people I know do the same thing, alone, at night. The AI tools that do it for you charge per application and write things you'd never sign: "3 years of experience", "no sponsorship needed".&lt;/p&gt;

&lt;p&gt;Deis keeps your facts in one place, hides the Irish jobs you can't get before…&lt;/p&gt;&lt;/div&gt;


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


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

&lt;h3&gt;
  
  
  Gemma judges, code guarantees
&lt;/h3&gt;

&lt;p&gt;A tailored CV that invents a certificate, or a total years of experience, can cost someone the job. So Gemma decides what to say, and code decides what stays.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every CV line has to cite the facts it came from. Code drops lines with no real facts behind them, and checks each sentence: any number, tool or certificate it mentions has to be in the cited facts.&lt;/li&gt;
&lt;li&gt;Code never lets a model state a total years of experience, write "currently studying" about a finished degree, or say anything about visas, stamps or sponsorship. That last rule came from testing: Gemma 4 26B wrote that my Stamp 1G persona was "eligible to work in Ireland without sponsorship".&lt;/li&gt;
&lt;li&gt;Employers, job titles, dates and education are copied from your facts, never rewritten.&lt;/li&gt;
&lt;li&gt;Job postings are data, not instructions. Hidden text and sentences addressed to AI tools are stripped before Gemma reads a posting and shown to you on the card. Real postings already contain them.&lt;/li&gt;
&lt;li&gt;Everything the guard removed is on the kit's &lt;strong&gt;Checks&lt;/strong&gt; tab, and one switch shows the source facts under every CV line.&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/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjd0810s555rikurokw1r.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%2Fjd0810s555rikurokw1r.gif" alt="Gemma writes the kit; every line links back to a fact you gave" width="600" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I measured it. On eight kits written by &lt;strong&gt;Gemma 4 E4B on my MacBook&lt;/strong&gt; (fit check, CV, letter and answers):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Run&lt;/th&gt;
&lt;th&gt;Sentences kept&lt;/th&gt;
&lt;th&gt;Removed by the guard&lt;/th&gt;
&lt;th&gt;Untraceable claims left&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;First run (13 Oct)&lt;/td&gt;
&lt;td&gt;210&lt;/td&gt;
&lt;td&gt;56&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;After fixing what the first run showed (13 Oct)&lt;/td&gt;
&lt;td&gt;261&lt;/td&gt;
&lt;td&gt;11 (4%)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Current guard, CV, letter and answers all checked (16 Oct)&lt;/td&gt;
&lt;td&gt;196&lt;/td&gt;
&lt;td&gt;11 (5.3%)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I read every removal of the last run by hand. About half were real: a test persona's finished MSc written as "current", a company's own pitch copied into a letter, an empty heading. The other half were true lines the guard was too strict about. I'd rather it erred that way. A full kit takes about 46 seconds on the laptop (median of 8).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F25g4s96a77tv4te4pbmp.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%2F25g4s96a77tv4te4pbmp.gif" alt="What it can't prove, it cuts" width="720" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhqk1mmygw56qmzez7sl1.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%2Fhqk1mmygw56qmzez7sl1.jpg" alt="The Checks tab: what the guard removed from a real kit, and why" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first run taught me something about small models: Gemma never invented a fact id. Instead it cited facts by quoting them or by their label, and my guard threw those good lines away. Now quotes and labels are matched back to the facts they name. What's left for the guard to remove are real over-claims: tools I never used, "currently" studying a degree I'd finished, a number from nowhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  The deck is code, not AI
&lt;/h3&gt;

&lt;p&gt;I hand-labelled 81 real Irish postings as &lt;em&gt;show&lt;/em&gt;, &lt;em&gt;stretch&lt;/em&gt; or &lt;em&gt;hide&lt;/em&gt; and tuned the filter on them (86% before, 100% after). Then I labelled 52 postings it had never seen, without looking at what it decided: &lt;strong&gt;51 of 52 right on the first run&lt;/strong&gt;. The one miss hid a &lt;em&gt;Trainee Accountant&lt;/em&gt; job because "complete the ACA qualification over a period of 3 to 4 years" looked like an experience requirement. A graduate or trainee title now needs a line that really says "experience" before Deis hides it. The details are in &lt;code&gt;eval/RESULTS.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Gemma never reads a job you won't see, which is what keeps it cheap.&lt;/p&gt;

&lt;h3&gt;
  
  
  Your model
&lt;/h3&gt;

&lt;p&gt;Every AI call goes through a per-request chain of models built with &lt;a href="https://mastra.ai" rel="noopener noreferrer"&gt;Mastra&lt;/a&gt;: one agent per job (card, fit, CV, letter, answers, coach), and the kit is a Mastra workflow that writes the CV, letter and answers in parallel. The chain is whatever the user chose (Ollama, an AI Studio key, any OpenAI-compatible server), with fallbacks.&lt;/p&gt;

&lt;p&gt;That turned out to matter on day two. Google AI Studio's Gemma 4 returned errors for hours, and some requests hung for over 90 seconds. The hosted demo now gives cloud calls a deadline and probes AI Studio, and while it's failing it asks a second Gemma host first: Gemma 4 26B on OpenRouter.&lt;/p&gt;

&lt;p&gt;It also matters when there's no network. With Gemma on your laptop, File &amp;gt; Work offline turns on an egress guard that refuses every connection that isn't to your own computer. The deck shows the jobs it saved, you can paste a job, and the kit still builds. I tried it with the Wi-Fi off: a pasted job still built a full kit on Gemma on the laptop. The guard has its own tests in &lt;code&gt;tests/offline.test.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4zda0ocw4ct51azjzh4t.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%2F4zda0ocw4ct51azjzh4t.gif" alt="It runs on your laptop" width="600" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The bug I shipped and fixed
&lt;/h3&gt;

&lt;p&gt;The hosted demo counted all of a person's AI calls against one limit. Browsing cards used it up, so after about 20 calls in an hour your next kit was told to come back later. Worse, the counter trusted the first address in a header the client controls, so changing that header reset it. Now each step has its own allowance per person, a person has a total across all steps, and the whole demo has an hourly budget. The address comes from Cloudflare's own header and is validated before it's counted.&lt;/p&gt;

&lt;h3&gt;
  
  
  The rest
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Jobs:&lt;/strong&gt; &lt;a href="https://serpapi.com" rel="noopener noreferrer"&gt;SerpApi&lt;/a&gt; Google Jobs, one shared search per role family for all of Ireland, refreshed about once a week, so one search serves every user. (The Google Jobs engine rejects &lt;code&gt;gl=ie&lt;/code&gt;; the location alone works.) Plus 55 employers' public boards on Greenhouse, Ashby, Lever and SmartRecruiters, refreshed every six hours.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Desktop:&lt;/strong&gt; Electron around the same Next.js server, running on &lt;code&gt;127.0.0.1&lt;/code&gt; behind a host check, at a stable &lt;code&gt;deis://app&lt;/code&gt; origin so your profile survives restarts. Installers for all three systems come from GitHub Actions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tracing:&lt;/strong&gt; &lt;a href="https://sentry.io" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt; agent tracing: a span per workflow step and per Gemma call with tokens, and an issue for every guard rule that fires, tagged with the model. Never a CV, a prompt or a key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hosting:&lt;/strong&gt; &lt;a href="https://render.com" rel="noopener noreferrer"&gt;Render&lt;/a&gt; web service and Key Value in Frankfurt for the demo, the shared job feed and the demo key's rate limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design:&lt;/strong&gt; Bricolage Grotesque for the big type, Geist for everything else, light and dark. Swipe, buttons or arrow keys. One accent, a lime highlighter, which only ever means &lt;em&gt;go&lt;/em&gt; or &lt;em&gt;proven&lt;/em&gt;: select a fact and it draws behind every CV line that cites it, and when a kit finishes the CV writes itself line by line while the sentences the guard removed flash past struck through. All of it stops under reduced motion.&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%2F2zuk59beb1dcsc3uofub.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%2F2zuk59beb1dcsc3uofub.jpg" alt="Sentry: one kit on a real visitor's session, the CV, letter and answers in parallel on Gemma 4 26B with one call on the second host; and one issue per guard rule" width="800" height="668"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4loxp1o0zkoa5asrqfi0.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%2F4loxp1o0zkoa5asrqfi0.jpg" alt="Render: the deis web service on Starter, deploying main to deiscareers.tech after CI passes" width="800" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv2h76ncqdefom3ib6ugs.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%2Fv2h76ncqdefom3ib6ugs.jpg" alt="Select a fact and the highlighter follows it into every CV line that cites it" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Because the business only works if the model is free to run.&lt;/strong&gt; Here is one application, measured:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Per application&lt;/th&gt;
&lt;th&gt;500 applications&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pay-per-application auto-apply (AI Apply credit packs, 2026 reviews)&lt;/td&gt;
&lt;td&gt;about $0.32 to $1.00, plus a monthly plan&lt;/td&gt;
&lt;td&gt;about $160 to $500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deis with Gemma 4 E4B on your laptop&lt;/td&gt;
&lt;td&gt;€0 (about 46 seconds)&lt;/td&gt;
&lt;td&gt;€0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deis with your free Google AI Studio key&lt;/td&gt;
&lt;td&gt;€0&lt;/td&gt;
&lt;td&gt;€0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deis on a paid Gemma 4 host (reseller price)&lt;/td&gt;
&lt;td&gt;about $0.0013&lt;/td&gt;
&lt;td&gt;about $0.65&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;With a closed API, I'd either have to charge a subscription to cover tokens or ration your applications. With open weights I can sell the app once and get out of the way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And the €9.99 has to pay for something.&lt;/strong&gt; The hosted demo and the shared job feed run on Render: a Starter web service ($7 a month) and Key Value ($10 a month). That's about two sales a month to break even. The tokens cost nothing extra because each person brings their own model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Because a CV is private.&lt;/strong&gt; On the desktop app your profile, your applications and, with Ollama, the model all stay on your computer. There's no Deis account and no server copy of your CV.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Because nobody can take it away.&lt;/strong&gt; When AI Studio went down, Deis switched host. If I disappear, the code is AGPL: build it yourself, free, forever. The €9.99 pays for the signed app, updates and the daily Irish job feed, not for permission.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where a closed model would be better:&lt;/strong&gt; the writing. A frontier model would write livelier CVs and need fewer rewrites. It would still need the same guard, because the guard is what stops a confident model from inventing a sponsorship claim. Open weights cost you a 6.6 GB download and a laptop that can run it. I think that's a fair trade for something that handles your CV, but you should weigh it yourself.&lt;/p&gt;

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

&lt;p&gt;I shared Deis while it was still a prototype: on LinkedIn, on Instagram, in my class's WhatsApp groups and in a group of builders who ship things. Eight people were on a waitlist by the time it was polished, and when deiscareers.tech went live this week I sent it to all of them, with a few reels and posts.&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%2Fw58ez7dvhlhgfzllz59n.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%2Fw58ez7dvhlhgfzllz59n.jpg" alt="Where I shared it: the LinkedIn launch post, an Instagram reel and the first story, from 13 October" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Plenty of people replied. Almost nobody downloaded it. I had pictured them running Gemma on their own laptops; instead everyone tried the web demo on the shared AI Studio key, it hit its rate limit, and Sentry showed me exactly where. So I changed the shape of the product: the web is now a demo with two sample graduates, and your own CV only goes into the desktop app, which has a 14-day free trial.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Agent Session &amp;amp; How I Built It With Claude Code
&lt;/h2&gt;

&lt;p&gt;I built Deis in a week, from 13 to 18 October, across 18 sessions with Claude Code. I made the decisions: the idea, what to cut, what my first user needed, when the UI wasn't good enough. Claude Code wrote most of the code, ran the tests and evals, and checked its own work against the live demo.&lt;/p&gt;

&lt;p&gt;The session below is the short version: 24 messages, one per turning point, in my words and its answers. A few moments worth looking for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The first message&lt;/strong&gt; is my unedited brain dump: "something like AI Apply, in a Tinder format where you swipe". The core rule, &lt;em&gt;Gemma judges, code guarantees&lt;/em&gt;, came out of the first day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Studio going down&lt;/strong&gt; on day two, and how the demo got deadlines, a health probe and a second Gemma host.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"I hate the UI and UX"&lt;/strong&gt;, and the Highlighter design that came out of it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;My first user's feedback&lt;/strong&gt; turning into code the same day: career stages up to 7+ years, tax and accounting roles, and job postings that keep their bullet points.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A re-review that caught three bugs before users did&lt;/strong&gt;, including a checkout link that sent buyers to the server's internal address.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the end of the week: 89 commits, 364 tests, installers for three systems, and two sales.&lt;/p&gt;


&lt;div class="ltag-agent-session"&gt;
  &lt;div class="agent-session-header"&gt;
    
    &lt;span class="agent-session-tool-icon-badge" title="Claude Code"&gt;
&lt;/span&gt;
    &lt;span class="agent-session-title"&gt;Building Deis with Claude Code: a week from a Tinder-for-jobs brain dump to two paid sales&lt;/span&gt;
  &lt;/div&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Look into the Week 2 challenge brief, then get back to me when you've understood what needs to be done. I have an idea similar to AI Apply but in an open-source way: an agentic workflow, free of cost, cost-efficient as much as we can. Here's my unedited brain dump: something like AI Apply, in a Tinder format where you swipe.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Day 1 (13 Oct): the core idea became 'Gemma judges, code guarantees'. Code decides which Irish jobs you see (seniority, right to work, languages). Gemma writes the CV, and a guard drops any line that doesn't cite a confirmed fact.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-gitcommit"&gt;git commit&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Start Deis: job filters, fact ledger and CV guard&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Start Deis: job filters, fact ledger and CV guard&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;First commit; then 'Right to work is code's job; guard tolerates real model output' and a guard eval runner&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;DigitalOcean is taking time to sort a payment issue, so let's keep moving with Google AI Studio meanwhile. Sentry DSN made with a new project.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;AI Studio's Gemma 4 returned 500s for hours and some calls hung past 90 seconds. So every cloud call got a deadline, the demo got a health probe, and a second Gemma host became the fallback. Sentry got one issue per guard rule, by name only: never a CV, a prompt or a key.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Keys are in on Render, test the live demo. And prep it for OpenRouter: the CV output does not give a good CV and no career objective.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Gemma 4 26B on OpenRouter is now the demo's second host. The CV follows the layout of the author's own hand-tailored CVs: a professional summary ending in a career objective, labelled competencies, and 3 to 5 bullets per main job.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Let's finalise the infrastructure and output quality, and make a fully offline running mode for the app. Also audit the app and tell me how we're doing.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Ran a seven-part audit (infrastructure, output quality, offline, UI, security, code health, launch). Fixed the top of it: per-route and demo-wide rate limits keyed on Cloudflare's header, a feed that never wipes the deck on a failed refresh, and an offline mode with an egress guard on every socket plus paste-a-job.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;pnpm test &amp;amp;&amp;amp; pnpm lint &amp;amp;&amp;amp; tsc&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ pnpm test &amp;amp;&amp;amp; pnpm lint &amp;amp;&amp;amp; tsc&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;75 tests at the audit; tests, lint and types now run in CI on every push&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;I hate the UI and UX. We don't just need a modern UI with colours and fonts, we need an actual overhaul with magic: more dynamic, more animations, it should feel crazy premium.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;The 'Highlighter' design: one lime accent that only means go or proven. A physical swipe deck with fly-to-tab, and a kit that writes itself line by line while removed sentences flash past struck through. Select a fact and the highlighter draws to every CV line that cites it. All of it stops under reduced motion.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;How will people download it? We also need an update mechanism, and people should be able to set their own SerpApi key, because mine will run out soon.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Desktop installers for macOS, Windows and Linux built and smoke-tested in GitHub Actions, published on each v* tag. deiscareers.tech is the home. Windows and Linux update themselves; the Mac points to the download page. SerpApi can use your own key.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-gittag"&gt;git tag&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;v0.1.1 ... v0.1.5&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;v0.1.1 ... v0.1.5&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Five releases on 16 Oct, including the Android APK and 'Gemma on your computer in one click'&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;I just connected Entire to the CLI. And for Sentry: are we using it well? It has logged 12 issues but I can't recall the last time one was picked up. How are we using Mastra?&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Sentry now separates the demo, desktop and development environments, with the task in guard issue titles and alerts for model errors. Mastra traces go to Mastra Platform with prompts and outputs stripped, and pure-code scorers grade every hosted kit.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Make it clear in the app that they should use local models for the best results, maybe a one-click installation.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;The desktop app links Ollama's installer for your OS, checks every 4 seconds until it's running, then downloads Gemma in one click with live progress. The web demo says so on the hero and in its rate-limit messages.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;We need a feature for people with 5 to 7 years of experience, and more career fields: it's all tech right now. Add tax, accounting, management, with a search. Address everything from studying to 7+ years.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;This came from the first real user: an MBA student with ten years in tax. The check-in now goes from studying to 7+ years, with 25 kinds of work and a search.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-gitcommit"&gt;git commit&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Stages from studying to 7 or more years; Kinds of work: tax, accounting, mana...&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Stages from studying to 7 or more years; Kinds of work: tax, accounting, management and more, with search&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;17 Oct&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Where are we standing, what's left, how do we bring it to a close? Maybe we don't allow people to put their profile in on the web demo, only in the app. Let's focus on quality.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;The web demo now runs two fictional graduates only, and the server refuses a real CV, so no CV reaches the hosted model. A re-review caught three bugs before users did: a checkout redirect to the proxy's internal address, a page that broke the build, and wrong copy for returning visitors. CI's checksPass meant the broken build never deployed.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;My first user said when they expand a job description, the bullet points from the actual JD became paragraphs. Not easy to read.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Google Jobs postings (44% of the deck) arrive with list items as bare lines. A new parser rebuilds headings, paragraphs and lists, and rejoins sentences split around bold words. Measured on all 340 live postings: Google Jobs postings with real lists went from 4 of 151 to 123.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Just got a new purchase from someone I have no idea who it is. I think the product is finding its market through word of mouth! Also add the support email &lt;span class="agent-session-redacted"&gt;[REDACTED]&lt;/span&gt; to the website.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Two sales on Polar: the first user bought it on the call, and the second came from a stranger. The October code is applied at checkout, and the support inbox is on the site and in the desktop licence screen. 89 commits and 364 tests by the end of the week.&lt;/p&gt;

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

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


&lt;p&gt;&lt;strong&gt;My first real user wasn't who I built it for.&lt;/strong&gt; I expected a recent tech graduate. A friend forwarded Deis to her MBA class, and the person who got on a call with me was one of her classmates: an international student with ten years of experience, looking for tax and accountancy roles. Deis only really knew early-career tech jobs. So that week it grew career stages from 3 to 5 years up to 7 or more, and kinds of work beyond tech, from tax and accounting to management, with a search so anyone can find their own field.&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%2Flmx1zs0vq0d9ijwcok2w.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%2Flmx1zs0vq0d9ijwcok2w.jpg" alt="The check-in my first user needed: career stages up to 7 or more years, and tax, accounting and finance" width="800" height="275"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What they told me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;They read the job description before they swipe.&lt;/strong&gt; I'd assumed people glance at a card and swipe. They opened every posting, and the posting's own bullet points had turned into a wall of paragraphs. The full posting now keeps its lists and headings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;They said the price was too low, and then they bought it.&lt;/strong&gt; An MBA student telling me to charge more was not what I expected. What sold them was swiping and getting a CV, a cover letter and form answers where every line is backed by something they said. They bought it on the call with the October code: Deis's first sale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ollama needed a human the first time.&lt;/strong&gt; Their first question was "why am I installing Ollama?" Once I explained that it runs the AI on their own laptop, they switched to it and kept going.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;They liked that Deis never applies for them.&lt;/strong&gt; They're graduating this month, and every time they open the app there are about 250 jobs that fit, instead of a blank scroll through LinkedIn or Indeed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The posting they were reading, before and after their feedback:&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%2Fxgc3vtwt46nwyv6x8rkv.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%2Fxgc3vtwt46nwyv6x8rkv.jpg" alt="The same posting before and after their feedback: the lists are lists again" width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the sales. The first came on that call. The second came in on the day I wrote this post, from someone I've never met: nobody I know, nobody I sent it to. Deis is starting to travel by word of mouth.&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%2F1dded6yvd1bozlw9p1l6.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%2F1dded6yvd1bozlw9p1l6.jpg" alt="The first sale after the call on WhatsApp, and Polar showing two sales" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;People outside Ireland wrote back too. A friend in Germany asked for a German version, a friend in Australia sent a voice note about the swipe, and a friend in India wants it for remote roles in Ireland, which the check-in's remote and right-to-work questions already cover. Still, I'm keeping Deis to Ireland for now, on purpose. It's the job market I know from the inside, and every country does this differently: CV styles, languages, what employers expect to see. Other countries can come later. For now I'd rather build something that really helps people in Ireland than something for everyone that helps no one.&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%2F1ememd71vapoxoso1w9q.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%2F1ememd71vapoxoso1w9q.jpg" alt="Replies: a friend sharing it with her MBA cohort, and friends in Australia, India and Germany (names and faces blurred)" width="800" height="786"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also showed it to people at a networking event recently. The question I heard most was why I'd open-source it and charge so little. My answer: €9.99 pays for the server and the job feed, and the code stays open because a tool for people looking for work shouldn't be something anyone can take away from them.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma:&lt;/strong&gt; Gemma 4 E4B on the laptop and Gemma 4 26B/31B in the cloud do every AI job in the app, measured and guarded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Render:&lt;/strong&gt; the hosted demo and the shared Irish job feed, with Key Value for the cache and rate limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of SerpApi:&lt;/strong&gt; Google Jobs as a shared, cached feed for early-career roles across Ireland.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Sentry Agent Tracing:&lt;/strong&gt; traces of every workflow step and Gemma call, and one issue per guard rule, tagged by model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Mastra:&lt;/strong&gt; per-request model chains with fallbacks, one agent per task, and a parallel kit workflow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of a .tech Domain:&lt;/strong&gt; &lt;a href="https://deiscareers.tech" rel="noopener noreferrer"&gt;deiscareers.tech&lt;/a&gt; is Deis's home: the web demo, the download page, checkout, and the shared job feed the desktop app reads.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;I drafted this post with Claude Code and edited it myself. The code, the tests and the evals in the repo are the same ones I ran for the numbers above.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>gemma</category>
      <category>opensource</category>
    </item>
    <item>
      <title>"Is AI going to replace me?" I built Droichead on Gemma 4 in one day, then pitched it with a flip chart</title>
      <dc:creator>Muhammad Murtuza Hussain</dc:creator>
      <pubDate>Mon, 12 Oct 2026 08:18:38 +0000</pubDate>
      <link>https://dev.to/muhammadmurtuzahussain/is-ai-going-to-replace-me-i-built-droichead-on-gemma-4-in-one-day-then-pitched-it-with-a-flip-4k6p</link>
      <guid>https://dev.to/muhammadmurtuzahussain/is-ai-going-to-replace-me-i-built-droichead-on-gemma-4-in-one-day-then-pitched-it-with-a-flip-4k6p</guid>
      <description>&lt;p&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;p&gt;The announcer struggled with the name. &lt;em&gt;Droichead&lt;/em&gt; is Irish for "bridge", and it's not an easy word to read out cold. I was standing next to my friend Nithin, telling him the technical track was his. Then they read out mine.&lt;/p&gt;

&lt;p&gt;I asked three more times whether they really meant me.&lt;/p&gt;

&lt;p&gt;I've never taken a single technical module. I studied business and maths, and my master's is in cybersecurity risk management, which is governance, not code. I'd started LeetCode four days earlier. Everything I know about building software I learned at hackathons, and on Saturday 3 October, at Hacktoberfest Hack Day Dublin x The AI Collective, that classroom gave me a prize: &lt;strong&gt;Best Open-Source AI Project&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This post is the build behind it: what Droichead does, how an open-weight model runs it without being allowed to make things up, and what I did while the AI was writing the code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR.&lt;/strong&gt; Droichead is a calm, private career navigator for people whose work is being reshaped by AI, built for Ireland's multilingual workforce. A 90-second check-in gives you roles to grow into, an honest gap analysis, and a dated week-by-week plan that links only to real courses, preferring free and government-funded Irish programmes. It runs entirely on Google's open-weight &lt;strong&gt;Gemma 4&lt;/strong&gt;: in the cloud, or fully offline on a laptop through Ollama. It works in seven languages, with no accounts and no database. I built it solo in one four-hour Claude Code session, and I pitched it with a flip chart.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;h3&gt;
  
  
  The question on the board
&lt;/h3&gt;

&lt;p&gt;The organisers set out five tracks. With ten minutes left to choose, I was standing in front of the &lt;strong&gt;Job Displacement&lt;/strong&gt; board, and I didn't need to go and interview anyone: my own role ends on 14 October. I was applying for everything, including jobs I'd never trained for, and asking the exact question the track was asking. &lt;em&gt;Is AI going to replace me?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So I wrote a persona. &lt;strong&gt;Eva&lt;/strong&gt; is a software engineer in Dublin. She keeps hearing about a role called &lt;strong&gt;Forward Deployed Engineer&lt;/strong&gt;, a client-facing engineer who applies technology in the field, and wonders whether it's her way forward. She just doesn't know how to get there. Her pain points were mine:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The job market is tough.&lt;/li&gt;
&lt;li&gt;Certificates are expensive.&lt;/li&gt;
&lt;li&gt;In Ireland, a lot of hiring runs through referrals.&lt;/li&gt;
&lt;li&gt;When you're applying for everything, it's hard to know which role is the right fit.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And in Ireland it's harder if you work in a second language. A big part of the workforce does: large Polish and Ukrainian communities, and the international staff who keep Dublin's tech and finance sectors running. The advice they get is generic, English-only and often fear-based. Meanwhile Ireland funds excellent upskilling through Springboard+, Skillnet Ireland and SOLAS eCollege, but most people never connect those programmes to a concrete next role.&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%2F2tr9srkvst45xlnayvvb.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%2F2tr9srkvst45xlnayvvb.jpg" alt="Droichead landing page: " width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A 90-second check-in.&lt;/strong&gt; Tap-first and skippable: role, industry, experience, the skills you enjoy, how you feel about AI, and the hours you can give each week. You can dictate the answers, or drop in a PDF CV, which is read in your browser and never uploaded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pulse.&lt;/strong&gt; Real articles from the last seven days (RTÉ, Silicon Republic, the Irish Times, the Guardian, TechCrunch), each with one line on what it means &lt;em&gt;for you&lt;/em&gt;, next to live &lt;strong&gt;CSO Ireland&lt;/strong&gt; unemployment figures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Roles to grow into.&lt;/strong&gt; Emerging roles like Forward Deployed Engineer, AI Solutions Engineer or AI-enabled Finance Analyst, ranked by how close they are to what you already do.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A gap analysis that leads with what you have.&lt;/strong&gt; Then what's partly there, then what to build, with a time estimate at your hours per week, and a Listen button that reads it aloud.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bridge the gap.&lt;/strong&gt; Pick a goal date and get a phased, week-by-week plan with a portfolio project. Every course comes from a human-checked catalogue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;My plan.&lt;/strong&gt; A timeline with a weekly streak, an &lt;code&gt;.ics&lt;/code&gt; calendar export, a &lt;strong&gt;printable wall planner&lt;/strong&gt; with QR codes that open each course from the paper, live job openings with how long ago each was posted, LinkedIn post drafts, local events, and a weekly check-in that re-plans around a bad week without guilt.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of it works in &lt;strong&gt;English, Gaeilge, Polski, Українська, Español, Deutsch and Français&lt;/strong&gt;: the interface, the AI's answers, read-aloud and dictation.&lt;/p&gt;

&lt;p&gt;The idea behind it fits on a napkin, and it's the scroll animation on the landing page. Wanting to switch jobs is a wish. Give it a deadline and it's a goal. Put a plan behind the goal and you have a strategy. Act on it every week and that's success.&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%2F6gprf3jbwxhv5xcmtt04.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%2F6gprf3jbwxhv5xcmtt04.jpg" alt="Scroll-drawn bridge on the landing page: Wish, Goal, Strategy, Action light up in turn as an arc draws itself" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

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

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

&lt;p&gt;&lt;strong&gt;Try it:&lt;/strong&gt; &lt;a href="https://droichead.onrender.com" rel="noopener noreferrer"&gt;droichead.onrender.com&lt;/a&gt;. It's on Render's free tier, so the first load after a quiet spell takes a little while to wake up. Tap &lt;strong&gt;Try a demo&lt;/strong&gt; for one of two personas: &lt;strong&gt;Aoife&lt;/strong&gt;, a software developer in Dublin (English), or &lt;strong&gt;Оксана&lt;/strong&gt;, an accountant in Cork (Ukrainian). Or do the check-in as yourself.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pulse: roles to grow into&lt;/th&gt;
&lt;th&gt;News for you, plus live CSO data&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&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%2Fu73h107fsjl33q5bm2hg.jpg" alt="Pulse page: strongest fit and roles to grow into, ranked by match" width="800" height="500"&gt;&lt;/td&gt;
&lt;td&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%2Fipfhz4hl46n16i56zy8s.jpg" alt="Industry pulse with real articles from the last 7 days and live CSO Ireland unemployment figures" width="800" height="500"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Gap analysis&lt;/th&gt;
&lt;th&gt;My plan&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&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%2F389n0pr5bnmb93ii0wbl.jpg" alt="Gap analysis: you already have, partly there, to build" width="800" height="500"&gt;&lt;/td&gt;
&lt;td&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%2Fs17gmrpcpybcswg3pztj.jpg" alt="My plan: phased timeline, portfolio project, print and calendar export" width="800" height="500"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Printable wall planner&lt;/th&gt;
&lt;th&gt;One QR code per course&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&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%2Ffo4ux6xj8u7174nht47q.jpg" alt="Printable A4 goal poster" width="800" height="500"&gt;&lt;/td&gt;
&lt;td&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%2F95inggnssrap050e5b5c.jpg" alt="Printable sheet of QR codes, one per course or programme" width="800" height="500"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The wall planner is my favourite part. A plan that only lives in a browser tab is easy to close. A plan on your fridge, where you can scan the next course with your phone, is harder to ignore.&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/MuhammadMurtuzaHussain" rel="noopener noreferrer"&gt;
        MuhammadMurtuzaHussain
      &lt;/a&gt; / &lt;a href="https://github.com/MuhammadMurtuzaHussain/Droichead" rel="noopener noreferrer"&gt;
        Droichead
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Droichead is a calm, private career navigator for people whose work is being reshaped by AI. It runs on open-weight Gemma 4 and works in seven languages. 
    &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;Droichead&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Bridge the gap to the job that's coming.&lt;/strong&gt; &lt;em&gt;Droichead&lt;/em&gt; (DRUH-hed) is Irish for "bridge".&lt;/p&gt;
&lt;p&gt;Droichead is a calm, private career navigator for people whose work is being reshaped by AI. It runs on open-weight Gemma 4 and works in seven languages. It was built in Dublin in one day for &lt;strong&gt;Hack for Humanity&lt;/strong&gt; (Hacktoberfest Hack Day Dublin x The AI Collective), on the job-displacement track: &lt;em&gt;help people navigate changing roles, skills, opportunities and economic security.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://droichead.onrender.com" rel="nofollow noopener noreferrer"&gt;https://droichead.onrender.com&lt;/a&gt; &amp;nbsp;·&amp;nbsp; &lt;strong&gt;Licence:&lt;/strong&gt; MIT&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/MuhammadMurtuzaHussain/Droichead/docs/screenshots/01-landing.jpg"&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%2FMuhammadMurtuzaHussain%2FDroichead%2FHEAD%2Fdocs%2Fscreenshots%2F01-landing.jpg" alt="Droichead landing page: &amp;quot;The work is changing. So can you.&amp;quot; over the Samuel Beckett Bridge in Dublin"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A wish to switch jobs is a fantasy. Give it a deadline and it becomes a goal. Put a plan behind the goal and you have a strategy. Act on the strategy consistently and that is success.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/MuhammadMurtuzaHussain/Droichead/docs/screenshots/02-bridge-story.jpg"&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%2FMuhammadMurtuzaHussain%2FDroichead%2FHEAD%2Fdocs%2Fscreenshots%2F02-bridge-story.jpg" alt="Scroll-drawn bridge: Wish, Goal, Strategy, Action"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;The problem, locally&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;AI anxiety is real, and it is not evenly spread. In Ireland, a big share of the workforce works in a second language. That includes large Polish and…&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/MuhammadMurtuzaHussain/Droichead" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser: Next.js 16, React 19, Tailwind v4, Motion
  IndexedDB (Dexie): profile, plans, check-ins      pdf.js: CV read in the browser
        │  profile sent per request, never stored
        ▼
Stateless route handlers
  /api/pulse    RSS feeds + CSO PxStat ─► Gemma: roles, "what it means for you", economy
  /api/gap      Gemma: have / partly there / to build
  /api/plan     Gemma picks from a 32-item course catalogue ─► code schedules the weeks
  /api/replan   code reschedules ─► Gemma writes one kind sentence and one tiny next step
  /api/jobs     Arbeitnow + Remotive, matched to the target role
  /api/posts    Gemma: LinkedIn drafts
        │
        ▼
Gemma 4: Google AI Studio (26B-A4B) │ Ollama on a laptop (12B) │ any OpenAI-compatible endpoint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  The model picks, the code owns the facts
&lt;/h3&gt;

&lt;p&gt;Career advice is a bad place for a model to improvise. A made-up course link wastes someone's evening, and a made-up deadline wastes their month. So I split the work the way I'd split it with a colleague I trusted but checked:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Gemma decides&lt;/th&gt;
&lt;th&gt;Code guarantees&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Which roles fit, and why&lt;/td&gt;
&lt;td&gt;Every news item is a real article from a real feed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What you already have, what's partly there, what to build&lt;/td&gt;
&lt;td&gt;Unemployment figures come straight from the CSO API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phases, tasks and minutes for each task&lt;/td&gt;
&lt;td&gt;Every course link is one a human checked, picked by id&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Which catalogue resource fits each task&lt;/td&gt;
&lt;td&gt;The dates: weeks are computed from the goal date and your hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A warm, specific line of encouragement&lt;/td&gt;
&lt;td&gt;Re-planning: nothing stays overdue, and each week fits your hours&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The model never writes a URL. It gets a catalogue of 32 resources (Springboard+, Skillnet Ireland, eCollege, Cyber Skills and more), each with an id, and it's told it may only use those ids. Then the server checks anyway. An id Gemma invents simply disappears:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/api/plan/route.ts: an id that isn't in the human-checked catalogue is dropped&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resourceId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resourceId&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;RESOURCE_BY_ID&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resourceId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resourceId&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Every response is validated against a zod schema. If it doesn't validate, Gemma gets the validation error back and one more try:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/llm.ts&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxTokens&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;temperature&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;extractJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`That did not validate (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;). Reply again with ONLY the corrected JSON object.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And if the model is unreachable altogether, the demo personas fall back to pre-written content. A live demo in a room with shaky wifi should never dead-end.&lt;/p&gt;

&lt;p&gt;The weekly check-in follows the same rule. When you tell it you're "a bit behind" or "way behind", plain code moves the tasks so nothing stays overdue and each week's load fits the hours you say you have. Gemma only writes the encouragement and one tiny next step. Rescheduling has to be right every time. Kindness is where a model earns its place.&lt;/p&gt;

&lt;p&gt;There's one more guard in the system prompt: news text and CVs are treated as untrusted data, and the model is told never to follow instructions found inside them. A CV is exactly the kind of document someone could slip a prompt into.&lt;/p&gt;
&lt;h3&gt;
  
  
  One model family, three places
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Where&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The live demo&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt; on Google AI Studio&lt;/td&gt;
&lt;td&gt;Fast enough to pitch with&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A laptop, offline&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;gemma4:12b&lt;/code&gt; on Ollama&lt;/td&gt;
&lt;td&gt;Your answers never leave your machine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anywhere else&lt;/td&gt;
&lt;td&gt;Any OpenAI-compatible endpoint (DigitalOcean Inference, vLLM, Groq)&lt;/td&gt;
&lt;td&gt;Swap providers with environment variables&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I measured both main setups on the day, on the same calls:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Call&lt;/th&gt;
&lt;th&gt;Laptop: Gemma 4 12B on Ollama&lt;/th&gt;
&lt;th&gt;Cloud: Gemma 4 26B-A4B on AI Studio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gap analysis&lt;/td&gt;
&lt;td&gt;~9 s&lt;/td&gt;
&lt;td&gt;~4 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Roles&lt;/td&gt;
&lt;td&gt;~28 s&lt;/td&gt;
&lt;td&gt;~9 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;News commentary&lt;/td&gt;
&lt;td&gt;~21 s&lt;/td&gt;
&lt;td&gt;~8 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;26-week plan&lt;/td&gt;
&lt;td&gt;~42 s&lt;/td&gt;
&lt;td&gt;~23 s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two things I learned the hard way, both visible in the agent session below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gemma 4 thinks at length by default, and it can spend the whole budget doing it.&lt;/strong&gt; My first call to the 26B took 17 seconds and returned no answer at all, just thoughts. Setting &lt;code&gt;thinkingLevel&lt;/code&gt; to &lt;code&gt;minimal&lt;/code&gt; through Google's native API brought it to about 5 seconds, with valid JSON in Irish.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemma on Google's API has no system role.&lt;/strong&gt; So the system prompt is folded into the first user turn:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/llm.ts: Gemma on Google's API has no system role&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;turns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;model&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="nl"&gt;generationConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;maxOutputTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;maxTokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;thinkingConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;thinkingLevel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;minimal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A local model also handles one request at a time, and React's dev mode fires effects twice. So identical requests in flight share one generation, and when everyone waiting on a generation has gone away, it's cancelled so it stops blocking the queue.&lt;/p&gt;
&lt;h3&gt;
  
  
  Private by design
&lt;/h3&gt;

&lt;p&gt;There are no accounts, no database and no tracking. Your profile and plan live in your browser's IndexedDB, with one-tap export and delete. The server routes are stateless: your profile is sent with each request and never stored. Your CV is read on your device with pdf.js. On the laptop setup, nothing leaves your machine at all.&lt;/p&gt;
&lt;h3&gt;
  
  
  An Agent Skill other agents can reuse
&lt;/h3&gt;

&lt;p&gt;The method itself is packaged as &lt;a href="https://github.com/MuhammadMurtuzaHussain/Droichead/blob/main/skills/bridge-the-gap/SKILL.md" rel="noopener noreferrer"&gt;&lt;code&gt;skills/bridge-the-gap/SKILL.md&lt;/code&gt;&lt;/a&gt;, so any agent can run the same gap analysis and planning without Droichead's UI. Its rules are the app's rules: lead with strengths, prefer free and funded programmes, never invent URLs, treat CVs as data, and never post on the person's behalf.&lt;/p&gt;
&lt;h3&gt;
  
  
  The build, by commit
&lt;/h3&gt;

&lt;p&gt;Seventeen commits, all on the day (Irish time):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Commit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;11:32&lt;/td&gt;
&lt;td&gt;Initial commit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11:44&lt;/td&gt;
&lt;td&gt;Skeleton: survey, pulse, gap analysis, planner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11:56&lt;/td&gt;
&lt;td&gt;Redesign, real photography, RSS news&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12:01&lt;/td&gt;
&lt;td&gt;Six more languages, with a check that every locale has every key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12:03&lt;/td&gt;
&lt;td&gt;The Agent Skill&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12:25&lt;/td&gt;
&lt;td&gt;AI moves to open-weight Gemma 4 on Ollama, locally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12:57&lt;/td&gt;
&lt;td&gt;Gemma 4 on Google AI Studio, the scroll-drawn bridge, the wall planner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13:05&lt;/td&gt;
&lt;td&gt;Render Blueprint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13:29 to 13:43&lt;/td&gt;
&lt;td&gt;Social preview, QR codes, streaks, voice, CV upload, live CSO data, live jobs, weekly re-plan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14:35&lt;/td&gt;
&lt;td&gt;README with screenshots&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;On Lighthouse it scored 93 for performance, 89 for accessibility, 100 for best practices and 100 for SEO.&lt;/p&gt;
&lt;h2&gt;
  
  
  Partner Technologies
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Gemma 4 (open-weight, from Google)
&lt;/h3&gt;

&lt;p&gt;Gemma does every AI job in the app: roles, news commentary, gap analysis, plans, check-in messages and LinkedIn drafts. Open weights matter for this product in three ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy.&lt;/strong&gt; A career plan is built from your work history and your worries. On Ollama it never leaves your laptop, and the code to do that is the same code the live demo runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost.&lt;/strong&gt; People looking for their next role are often the people least able to pay for another subscription. A local model costs nothing per plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Control.&lt;/strong&gt; Because Gemma runs inside my own pipeline, every answer passes through code I wrote before anyone sees it: schemas, the id check, deterministic scheduling. I could also swap sizes and providers and measure the difference, which is how I picked 26B-A4B for the demo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It handled Ukrainian, Polish and Irish JSON well enough to ship. The one honest caveat: a native speaker hasn't reviewed the Gaeilge yet.&lt;/p&gt;
&lt;h3&gt;
  
  
  Google AI Studio
&lt;/h3&gt;

&lt;p&gt;I'd used AI Studio for the first time the day before, building &lt;a href="https://dev.to/muhammadmurtuzahussain/pizhu-pi-zhu-a-writing-tutor-that-never-rewrites-your-essay-built-for-my-friend-joy-gemma-4-2n6e"&gt;Pīzhù&lt;/a&gt; for a DEV weekend challenge. That practice run turned out to be the best preparation I could have done, because at noon on hack day I needed a plan B fast. The native API was the key: it's the only route where I could turn Gemma's thinking down to &lt;code&gt;minimal&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Render
&lt;/h3&gt;

&lt;p&gt;The whole deployment is one &lt;code&gt;render.yaml&lt;/code&gt; Blueprint: a free Node service in Frankfurt (the closest region to Dublin), built with &lt;code&gt;npm ci &amp;amp;&amp;amp; npm run build&lt;/code&gt;, a health check on &lt;code&gt;/api/health&lt;/code&gt;, and a redeploy on every push to &lt;code&gt;main&lt;/code&gt;. Render asks for the AI Studio key when you create the Blueprint, so the key never touches the repo. The one thing to know: the free tier sleeps after about 15 minutes idle, so I opened the site a couple of minutes before my pitch.&lt;/p&gt;
&lt;h3&gt;
  
  
  DigitalOcean (the plan A that didn't happen)
&lt;/h3&gt;

&lt;p&gt;DigitalOcean was the diamond sponsor, and I wanted to build on it. Joanna, one of the organisers, spent time getting my credits through, but the billing set-up wouldn't accept either of my cards, and without billing I couldn't generate a key for DigitalOcean's Inference. I'm including it because the code still carries it: there's a &lt;code&gt;.do/app.yaml&lt;/code&gt; App Platform spec in the repo, and &lt;code&gt;lib/llm.ts&lt;/code&gt; talks to any OpenAI-compatible endpoint, with DigitalOcean Inference as the default base URL. Pointing Droichead back at DigitalOcean is a matter of setting a key and a model name.&lt;/p&gt;

&lt;p&gt;The detour took less than half an hour, and it made the product better. Discovering that my laptop already had Gemma 4 on Ollama is why "your answers can stay on your computer" is a feature and not a slogan.&lt;/p&gt;
&lt;h2&gt;
  
  
  Hackathon Experience
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Getting there
&lt;/h3&gt;

&lt;p&gt;At 00:33 I was wrapping meal prep for the week. By six I was on a bus from Galway to Dublin. The event had two names, Hacktoberfest Hack Day Dublin x The AI Collective Dublin Chapter on MLH and Hack for Humanity: Dublin on Luma, and I was on Luma's waiting list, so I didn't know where the venue was. I picked a direction and walked for twenty minutes. It was the wrong one. A taxi later I was one of the first people through the door at Dogpatch Labs, and Ashley, one of the organisers, turned my morning from lost to ready within a few minutes of chatting.&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%2Fxiiqwz1dm1brgucgo4en.jpeg" 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%2Fxiiqwz1dm1brgucgo4en.jpeg" alt="The welcome screen at Dogpatch Labs: " width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Seven tables, all full. Around 45 people in roughly 15 teams, from Ireland, Brazil, Poland, Ukraine, India and elsewhere in Asia. While everyone else talked architecture, I stood in a corner with Avi from Give a Go, who told me I had a voice for radio. It was exactly what I needed to hear.&lt;/p&gt;
&lt;h3&gt;
  
  
  Twenty minutes with nothing to build
&lt;/h3&gt;

&lt;p&gt;I went outside and recorded a voice note: what the product should do, what the agent workflow should look like, and where AI should earn its place rather than replace a simple calculation. Then I handed it to Claude Code. That voice note is the first message in the session below.&lt;/p&gt;

&lt;p&gt;While the first build ran, I had twenty minutes with nothing to do, and that's the part that catches people out. You can't interrupt the build without slowing it down. So I asked a different question: &lt;strong&gt;what can Claude not do that I can?&lt;/strong&gt; The answer was pitching.&lt;/p&gt;

&lt;p&gt;There was a flip chart in the corner. I tore off a sheet and split it into four quadrants: Eva and her thought bubble, "Is AI going to replace me?"; &lt;strong&gt;FDE&lt;/strong&gt;, covered with sticky notes I could peel back with the audience; the pain points; and how Droichead answers each one. Then I thought about latency. A model takes several seconds to answer, which is a long time in a three-minute pitch, so I put the project name, a tagline and the tech stack on sticky notes to give the audience something to read while Gemma worked.&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%2Fhpnr44e0a2s2xxwdwew4.jpeg" 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%2Fhpnr44e0a2s2xxwdwew4.jpeg" alt="An illustration of the flip chart, redrawn from my description: Eva in Dublin asking " width="800" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;An illustration, redrawn from my description. The real one had more marker and fewer straight lines.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Three minutes, one flip chart
&lt;/h3&gt;

&lt;p&gt;Most teams had slick slides. I dragged in a stand with a folded sheet of paper and started talking with my laptop still unplugged: &lt;em&gt;"Hi folks, I'm Muhammad Murtuza from Galway, and Galway people are known to be a bit crazy, so what you're about to hear is a crazy guy's storytelling. Let's meet Eva."&lt;/em&gt; By the time I reached her pain points, I'd plugged in and gone live.&lt;/p&gt;

&lt;p&gt;For the live demo I picked a volunteer: Nithin, who has years in offensive security and had no idea what I was about to do. I pasted his LinkedIn profile into Droichead. On the venue wifi the model took about twelve seconds, so I walked the room through Eva's plan while it worked, then came back to his result. The role it suggested was one he said he actually wanted: &lt;em&gt;"that's the role I want."&lt;/em&gt; A real reaction, live, is hard to fake on a slide.&lt;/p&gt;

&lt;p&gt;I ran out of time before the languages, the accessibility work or the live Irish data. I finished on the clock anyway, on the Lighthouse scores and a QR code to the live site.&lt;/p&gt;
&lt;h3&gt;
  
  
  Waiting to lose
&lt;/h3&gt;

&lt;p&gt;Every other team had a back-and-forth with the three judges. I got one question from one judge: &lt;em&gt;what's the human element?&lt;/em&gt; I said Droichead sends you out of the app, to events and to people on LinkedIn, because referrals matter in Ireland. Then I sat down certain I'd lost. I'd given them a person, a feeling and a solution, and in a room full of builders that felt like too little.&lt;/p&gt;

&lt;p&gt;It was enough. Droichead won Best Open-Source AI Project. Congratulations to Moldmate by Christopher Svitok and team, who won the non-technical Build Without Code track. The prize was €25 and three sessions with Andrei, a Head of AI, which could not have come at a better moment for someone looking for their next role in AI and security.&lt;/p&gt;
&lt;h3&gt;
  
  
  What I'll remember
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;When the AI is building, ask what only you can do.&lt;/strong&gt; Claude writes code faster than I ever will. It can't read a room, choose a volunteer, or cover twelve seconds of silence. Those twenty minutes were the most valuable of my day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start with a problem you live.&lt;/strong&gt; Eva was a version of me, and I think the room could tell.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pitch for the room, not the rubric.&lt;/strong&gt; The flip chart wasn't a gimmick. It was me being myself, and it gave people something to read while the model thought.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't read the judges by the number of questions.&lt;/strong&gt; I was sure one question meant I'd lost.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rule that came out of that day, &lt;em&gt;the model picks and the code owns the facts&lt;/em&gt;, became how I build. I used it the day before in Pīzhù without a name for it, and again the week after in &lt;a href="https://dev.to/muhammadmurtuzahussain/i-walked-an-hour-for-30-cents-gemma-plans-litter-walks-that-end-at-a-deposit-machine-4ih9"&gt;Return Route&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  What It Can't Do Yet
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Gaeilge needs a native speaker's review.&lt;/strong&gt; The Irish interface was written with AI help and checked by script, not by a fluent speaker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The match percentages are Gemma's estimates.&lt;/strong&gt; They rank roles sensibly, but they aren't a validated score, and the app shouldn't pretend otherwise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The catalogue is 32 hand-picked resources.&lt;/strong&gt; That's enough to be useful and small enough to check by hand. It needs to grow, and to be maintained.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live jobs come from Arbeitnow and Remotive,&lt;/strong&gt; which skew towards Germany, the UK and remote roles. Irish job boards are next.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It answers the judge's question only halfway.&lt;/strong&gt; It sends you to events and drafts your LinkedIn posts, but it doesn't introduce you to anyone yet. Partnering with Skillnet Ireland, Intreo or community groups that support Polish and Ukrainian workers would.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It needs a signal.&lt;/strong&gt; An offline-first PWA, for people with patchy data, is on the list.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;I built Droichead with Claude Code in one session on hack day, from the voice note to the README. This is a curated version: my prompts lightly trimmed, Claude's turns summarised, and the tool calls and their outputs real. It includes the moment DigitalOcean's billing fell through, the benchmark that found Gemma 4 on my laptop, and the thinking-budget fix.&lt;/p&gt;


&lt;div class="ltag-agent-session"&gt;
  &lt;div class="agent-session-header"&gt;
    
    &lt;span class="agent-session-tool-icon-badge" title="Claude Code"&gt;
&lt;/span&gt;
    &lt;span class="agent-session-title"&gt;Building Droichead with Claude Code at a Dublin hack day: from a voice note to a winning open-weight career bridge&lt;/span&gt;
  &lt;/div&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div&gt;
                  &lt;div class="agent-session-text agent-session-text-collapse"&gt;
                    &lt;p&gt;[11:25 Dublin time. Dictated as a voice note outside the venue, lightly trimmed.]&lt;/p&gt;

&lt;p&gt;Project idea. I don't have the name in my mind, but I want a platform where users can... oh, you know what, actually, not use a login. Let's keep it safe, secure, and very much browser side data storing. Users put in what they do, their employment history, their preferences, in a very quick, playful survey that is not boring. Then the platform tells them the current news, what's happening in the industry, how the roles are changing, how the economic times are changing, and how people can adapt. AI gives anxiety to everyone that it will replace people, but I suppose the correct answer is that it will ask people to upgrade a bit, with AI-enabled tools.&lt;/p&gt;

&lt;p&gt;Now here comes the wow part. I don't want just an overview, Google News can do that. The person clicks one of the top roles, say forward deployed engineer, and it shows how they can bridge the gap from their current profile. When they hit "I want to bridge the gap", the AI makes them a custom planner: certifications, a calendar, job alerts posted in the past 48 hours, LinkedIn post recommendations so they can be visible, and events nearby.&lt;/p&gt;

&lt;p&gt;Because just thinking about switching a job is a fantasy. Having a deadline with what you want is a goal. A plan with a deadline and a goal is a strategy. And consistent actions are success.&lt;/p&gt;

&lt;p&gt;Let's plan this, with an Irish palette for the UI, and a multilingual UI in Irish, Polish, Ukrainian, Spanish, German and French.&lt;/p&gt;

                  &lt;/div&gt;
                  Show more
                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Found your event: Hacktoberfest Hack Day Dublin x The AI Collective. It ends at 16:00 Dublin time today, which leaves about 4 hours of build time.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-mcpdevrelaygatewaygetmlhevent"&gt;mcp__devrelay-gateway__get_mlh_event&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Hacktoberfest Hack Day Dublin x The AI Collective Dublin Chapter&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Hacktoberfest Hack Day Dublin x The AI Collective Dublin Chapter&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Ends 16:00 IST. Tracks include Job Displacement. Prize category: Best Open-Source AI Project (open-source or open-weight AI as a real part of the product, public GitHub repo).&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;What the event details change:&lt;br&gt;
- The theme fits. Your idea lands squarely on the Job Displacement track, and the event asks for a local problem, so the pitch is "built for Ireland's workforce, in the languages Ireland actually speaks": large Polish and Ukrainian communities, and international tech workers in Dublin.&lt;br&gt;
- Courses should point at Irish public programmes: Springboard+, Skillnet Ireland, SOLAS eCollege, Intreo.&lt;br&gt;
- For the open-source AI prize, the model has to be open-weight and the repo public and licensed.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Scaffolding Next.js, then the data model (IndexedDB, no accounts), zod schemas for every model output, a human-checked course catalogue the model can only reference by id, and four API routes. The first build passes.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Add DO spec, MIT license, commit and push&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Add DO spec, MIT license, commit and push&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;[main e22f68a] Droichead skeleton: survey, pulse, gap analysis, planner on DO Gradient&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;The news API I planned on (GDELT) is timing out from here, so I'm testing RSS feeds instead:&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Debug the GDELT fetch timing and response&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Debug the GDELT fetch timing and response&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;TypeError: fetch failed. ConnectTimeoutError (attempted address: api.gdeltproject.org:443, timeout: 10000ms)&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Test candidate news RSS feeds for speed&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Test candidate news RSS feeds for speed&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;200 0.18s rte.ie business, 40 items
200 0.26s irishtimes.com business, 100 items
200 0.24s techcrunch.com AI, 20 items
200 0.43s theguardian.com AI, 20 items&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;RSS is faster and gives real Irish headlines (RTÉ, the Irish Times, Silicon Republic). Switching.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Redesign with the design-taste skill: Geist (it covers Irish, Polish and Ukrainian characters), Phosphor icons, real photos of the Samuel Beckett Bridge in Dublin and the Brian Boru Bridge in Cork (credited), dark mode. Then all 7 locales, with a script that checks every locale has every key and no dashes.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Add and run i18n key parity check&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Add and run i18n key parity check&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;en, ga, pl, uk, es, de, fr: all keys present, 0 dashes&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Next, the README (judges read it) and a small Agent Skill, skills/bridge-the-gap/SKILL.md, that packages the gap-analysis method so any agent can run it. Pushed. The flow works end to end, but only on demo data: the AI isn't connected yet.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;ol&gt;
&lt;li&gt;i cant find the .env.local and from which section in DO shall i grab the key from&lt;/li&gt;
&lt;li&gt;let's come to this when 1 is done, because i did not understand this.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;the credits are in DO so let's use it if needed&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;You couldn't find .env.local because it didn't exist yet, and dotfiles are hidden in Finder. I've created it, and it's already in .gitignore, so the key will never be pushed.&lt;/p&gt;

&lt;p&gt;DigitalOcean renamed the product: it's now Inference (it used to be Gradient). Control panel, INFERENCE, Manage, Create model access key, All models, No VPC network, then copy the key right away: it's only shown once.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;the digital ocean is giving me issues with payment information and stuff i dont think i can get a key, can we do alternative plan?&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Good news: Ollama is already installed on your Mac, with open-weight models downloaded.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;List local Ollama models&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ List local Ollama models&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;gemma4:12b 11.9B Q4_K_M 8.0 GB
gemma4:e4b 7.5B Q4_K_M 6.6 GB&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Benchmark Gemma 4 12B speed and Ukrainian JSON output&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Benchmark Gemma 4 12B speed and Ukrainian JSON output&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;gemma4:12b 30.7s (includes loading) 21.2 tok/s
{"have": ["Глибоке розуміння фінансової звітності", "Досвід аудиту та аналізу даних", ...], "weeksEstimate": 18, ...}&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Benchmark Gemma 4 E4B and warm 12B&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Benchmark Gemma 4 E4B and warm 12B&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;gemma4:e4b 11.7s 43.4 tok/s
gemma4:12b 15.0s 23.6 tok/s (warm)&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Gemma 4 12B writes good Ukrainian. I'm making Ollama the default backend, keeping the OpenAI-compatible path for DigitalOcean if billing ever works, and adding a warm-up call so the first real request is fast.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;A local model handles one request at a time, so: identical in-flight requests now share one generation, abandoned ones are cancelled when the user navigates away, and the pulse is split into two requests so roles show up before the news.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Time live news and gap calls&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Time live news and gap calls&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;roles ~28 s, news ~21 s (real Irish headlines with a 'for you' line), gap ~9 s&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;We don't need DigitalOcean at all. All the AI now runs on your laptop on open-weight Gemma 4, so "your answers never leave your computer" is literally true. Pushed.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;okay great! let's make the Ui much better more interactive i suppose and makes it look wow, you know like an amazing Ui/UX, at the moment it looks like a government website got modernized with AI slop. source more skills and improve the UI.&lt;/p&gt;

&lt;p&gt;Also, do you think we can deploy this? I can grab keys from google Ai studio and stuff if needed. let;s polish it to the best extent we can and make this an actual wow&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Adding a Google AI Studio provider (it serves the open-weight Gemma family), then checking the key against the model list. I won't print the key.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Benchmark Gemma 4 models on Google API&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Benchmark Gemma 4 models on Google API&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;gemma-4-26b-a4b-it 200 17.1s 0 tok &amp;lt;thought&amp;gt; ...
gemma-4-31b-it 200 48.1s 74 tok &amp;lt;thought&amp;gt; ...&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Both models think at length by default, and it eats the whole token budget. Testing whether thinking can be turned down through the native API:&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Test thinkingLevel options for Gemma 4&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Test thinkingLevel options for Gemma 4&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;minimal: gemma-4-26b-a4b-it 200 5.3s, valid Irish JSON {"have": ["Taithí mór i gcúrsaí airgeadais", ...]}
low: 400 "Thinking level is not supported for this model."&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Benchmark Gemma 4 31B with minimal thinking&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Benchmark Gemma 4 31B with minimal thinking&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;gemma-4-31b-it 500 34.2s INTERNAL&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Gemma 4 26B-A4B with thinkingLevel minimal: 5 seconds, valid output. The 31B errors, so 26B-A4B it is. Gemma on this API also has no system role, so the system prompt gets folded into the first user turn.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Test Google-backed routes on prod server&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Test Google-backed routes on prod server&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;{"ok":true,"ai":{"provider":"google","model":"gemma-4-26b-a4b-it"}}
gap: real 4.20 s
pulse roles: real 9.42 s&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Roughly 4 times faster than local. Now the redesign: dark emerald theme, a floating glass nav, the hero photo of the bridge, a scroll-drawn arc where Wish, Goal, Strategy and Action light up in turn, and a printable A4 wall planner.&lt;/p&gt;

&lt;p&gt;One honesty fix before deploying: the landing page says the AI runs "on this computer", which won't be true on a server. Rewording it in all 7 languages so it's true for both setups.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;we are going with render for deployment, so will it be a blueprint or something else&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;A Blueprint: a render.yaml in the repo that describes the service, so Render sets it up the same way every time and asks you for the secret key. Free Node service in Frankfurt (the closest region to Dublin), npm ci &amp;amp;&amp;amp; npm run build, health check on /api/health, auto-deploy on push. Added and pushed. Paste your AI Studio key as GOOGLE_API_KEY when Render asks, and send me the URL when it's live.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;&lt;a href="https://droichead.onrender.com/" rel="noopener noreferrer"&gt;https://droichead.onrender.com/&lt;/a&gt; here you go, suggest me ideas on how we can improve the project or polish it more.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Smoke-test live Render deployment APIs&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Smoke-test live Render deployment APIs&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;gap: real 3.80 s
news: real 8.00 s, 4 stories
- irishtimes.com | Use of AI on the rise in workplaces, says PwC
- irishtimes.com | Workday to cut jobs in Dublin HQ but will press on with AI
- techcrunch.com | The rise of the GTM engineer&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div&gt;
                  &lt;div class="agent-session-text agent-session-text-collapse"&gt;
                    &lt;p&gt;The live site works. It's 13:23, so about 2.5 hours left. Ranked by how much they help against the effort:&lt;br&gt;
1. MLH submission and a demo script. 2. A 60-second backup video. 3. Make the 23-second plan wait feel intentional.&lt;br&gt;
4. QR codes on the printed wall planner. 5. Live CSO Ireland figures. 6. Read-aloud and voice answers in all 7 languages. 7. Celebrate progress, with a weekly streak.&lt;br&gt;
8. Weekly check-in and re-plan. 9. Real job listings. 10. CV upload, read in the browser.&lt;br&gt;
Also: ask an Irish speaker at the venue to check the Gaeilge, and open the site 2 minutes before judging, because Render's free tier sleeps.&lt;/p&gt;

                  &lt;/div&gt;
                  Show more
                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;okay let's do , 3, 4, 5, 6, 7. 8, 9, 10&lt;/p&gt;

&lt;p&gt;i will work on 1 and 2 after we have done the above task. can you add the social preview image btw?&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Quickest first: the social preview, then 3, 4, 7, 6, 10, 5, 9 and 8, committing as I go.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Add CSO unemployment fetcher and test it&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Add CSO unemployment fetcher and test it&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;{ month: '2026 September', rate: 5, prev: 5, youth: 12.5 }&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Test live jobs endpoint for several roles&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Test live jobs endpoint for several roles&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;== Forward Deployed Engineer (3 in the last 48h)
  7 h | Arbeitnow | Forward Deployed Engineer | Tacto | Munich
  9 h | Arbeitnow | Forward Deployed Engineer | Flow Engineering | London&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;All eight features plus the social preview are built, pushed and confirmed on the live site: the staged plan loading, a QR sheet with one code per course, confetti and a weekly streak, dictation and Listen buttons, PDF CVs read in the browser with pdf.js, live CSO figures (5.0% unemployment, 12.5% for under-25s), live jobs with how long ago each was posted, and a weekly check-in that reschedules without guilt.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;ol&gt;
&lt;li&gt;you make the mlh submission thing, i will look at it and submit&lt;/li&gt;
&lt;li&gt;i will do that&lt;/li&gt;
&lt;/ol&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Verify no secrets in git; get commit time range&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Verify no secrets in git; get commit time range&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;0 matches of key in git history (should be 0)
2026-10-03 11:32:45 +0100 Initial commit from Create Next App
2026-10-03 13:43:40 +0100 (latest)
16 commits&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;The draft is in SUBMISSION.md. I haven't created or submitted anything on MLH. Checked against the rules and the Best Open-Source AI Project challenge: built today (16 commits, 11:32 to 13:43), public repo with an MIT licence, Gemma 4 does all the AI work, the Agent Skill follows the open standard, no secrets in the history, and an AI disclosure section that names Gemma 4 at runtime and Claude Code while building.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;everything is done, i have submitted, just update the read me, add screenshots if needed and push to github&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Capturing 2x screenshots of the live site with headless Chrome, reviewing each one, retaking the two where the floating nav covered a heading, then compressing them to JPEG.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Commit README and screenshots, push to GitHub&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Commit README and screenshots, push to GitHub&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;[main b2023c8] README: full feature tour with screenshots, open-source AI, privacy, deploy and AI disclosure
11 screenshots, about 1.9 MB&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;The README is pushed with all 11 screenshots, the architecture, the open-source AI setup, privacy, how to deploy, and the AI disclosure.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;quick question which model is faster at responses, the local or cloud one&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;The cloud one, by about 3 to 5 times. What we measured today:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Call&lt;/th&gt;
&lt;th&gt;Local, Gemma 4 12B on Ollama&lt;/th&gt;
&lt;th&gt;Cloud, Gemma 4 26B-A4B on Google AI Studio&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gap analysis&lt;/td&gt;
&lt;td&gt;~9 s&lt;/td&gt;
&lt;td&gt;~4 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Roles&lt;/td&gt;
&lt;td&gt;~28 s&lt;/td&gt;
&lt;td&gt;~9 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;News commentary&lt;/td&gt;
&lt;td&gt;~21 s&lt;/td&gt;
&lt;td&gt;~8 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;26-week plan&lt;/td&gt;
&lt;td&gt;~42 s&lt;/td&gt;
&lt;td&gt;~23 s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The cloud model is bigger, but it's a mixture of experts, so only about 4B parameters work on each token. The local model's advantage is privacy and resilience: answers never leave your machine, and it works without internet. That's a good backup if the venue wifi drops during the demo.&lt;/p&gt;

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

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



&lt;h2&gt;
  
  
  Thank You
&lt;/h2&gt;

&lt;p&gt;To Ashley, Joanna and Andrei from The AI Collective's Dublin chapter, to Avi from Give a Go, and to Major League Hacking for running the day. Joanna, thank you for sorting out my DigitalOcean credits. Nithin, thank you for being the best volunteer anyone could ask for.&lt;/p&gt;

&lt;p&gt;If you're nearby, I'm hosting a Hacktoberfest Fest in Galway on 29 or 30 October with the University of Galway Cybersecurity Society. Come and build something. And if you're a non-coder wondering whether to walk into a room like that one: go. Bring what you're good at, and let the AI do what it does best.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://droichead.onrender.com" rel="noopener noreferrer"&gt;droichead.onrender.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code (MIT):&lt;/strong&gt; &lt;a href="https://github.com/MuhammadMurtuzaHussain/Droichead" rel="noopener noreferrer"&gt;github.com/MuhammadMurtuzaHussain/Droichead&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MLH submission:&lt;/strong&gt; &lt;a href="https://www.mlh.com/events/hacktoberfest-hack-day-dublin-x-the-ai-collective-dublin-chapter/submissions/01a101f0-2777-41dd-c875-9b261ee51119" rel="noopener noreferrer"&gt;Droichead on MLH&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The longer story of the day:&lt;/strong&gt; &lt;a href="https://medium.com/@muhammadmurtuzahussain/i-never-studied-code-i-still-won-the-technical-track-aa0bb7613493" rel="noopener noreferrer"&gt;I Never Studied Code. I Still Won the Technical Track.&lt;/a&gt; on Medium&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Photos of the Samuel Beckett Bridge (DXR) and the Brian Boru Bridge (Joachim Kohler-HB) are from Wikimedia Commons, CC BY-SA 4.0. Unemployment data from CSO Ireland (MUM01).&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with AI assistance (Claude Code) on the day, and written up with AI help. Gemma 4 generates the advice inside the app. The product decisions, the pitch and the flip chart were mine, and I reviewed and edited everything here.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mlhacks</category>
      <category>devchallenge</category>
      <category>hackathon</category>
      <category>ai</category>
    </item>
    <item>
      <title>I walked an hour for 30 cents: Gemma plans litter walks that end at a deposit machine</title>
      <dc:creator>Muhammad Murtuza Hussain</dc:creator>
      <pubDate>Sun, 11 Oct 2026 23:13:59 +0000</pubDate>
      <link>https://dev.to/muhammadmurtuzahussain/i-walked-an-hour-for-30-cents-gemma-plans-litter-walks-that-end-at-a-deposit-machine-4ih9</link>
      <guid>https://dev.to/muhammadmurtuzahussain/i-walked-an-hour-for-30-cents-gemma-plans-litter-walks-that-end-at-a-deposit-machine-4ih9</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05"&gt;Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At 18:27 on Sunday, a machine at Lidl in Galway printed me a voucher for €0.30: two cans at 15 cents each. It's the first deposit I've claimed in two years of living in Ireland. I don't buy drinks. I carry water in a flask.&lt;/p&gt;

&lt;p&gt;The cans weren't mine. I picked them up on a walk that an open-weight model planned for me, along with six other bits of litter that paid nothing at all.&lt;/p&gt;

&lt;p&gt;There's a story going round 9GAG about someone in Germany who paid for a PS5 with deposit bottles. I couldn't verify it. My number is easier to check, and I kept the voucher.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR.&lt;/strong&gt; Return Route plans a walk through the spots where cans and bottles get left behind, and ends it at a deposit return machine. When you get back, one photo of your haul and Gemma counts it. The refund comes from the deposit table, never from the model. Gemma can run in the cloud, on your laptop, or (untested yet) in your phone's browser. I took it on a real walk in Galway: about an hour outside, 8 pieces of litter picked up, 2 that paid, €0.30. You can keep the money or give it away.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Ireland has had a deposit return scheme, Re-turn, since February 2024. A can or a small bottle carries 15c, a big bottle 25c, and you get it back from a machine at the supermarket. So every can in a hedge is a refund nobody claimed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Return Route&lt;/strong&gt; turns that into a reason to go outside:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pick how long you've got:&lt;/strong&gt; 30 minutes, an hour, 90 minutes or your own time. You can add a note like "finish at Tesco, stay off the main road".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemma plans a loop&lt;/strong&gt; through the places where drinks get left behind (picnic tables, pitches, viewpoints, benches near an off-licence) and finishes at a return machine. You get a range for what you might make, never a promise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Put the phone away.&lt;/strong&gt; The route goes to Google Maps, and a short briefing is read aloud: where you're going, what to look for, one safety tip.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Back home, take one photo.&lt;/strong&gt; Gemma counts the containers, says which ones the machine will refuse (crushed, damaged, no deposit mark) and prints an itemised voucher. Then you keep the money, or switch on &lt;strong&gt;Walk for a cause&lt;/strong&gt;: the app turns green, the refund goes to a cause you name, and Gemma drafts a post to get others walking.&lt;/li&gt;
&lt;/ol&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%2F2ui7bwo4c4ffdto5wr16.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%2F2ui7bwo4c4ffdto5wr16.png" alt="Four phone screens from the live app: pick your time on yellow waymark signs, a planned loop on a dark map with three stops and an estimate of €1.22 to €4.02, an itemised voucher for a photographed haul totalling €1.05, and a green thank-you screen for €1.05 given to the local food bank" width="799" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Screens from the live site: a real plan from Terryland Forest Park on Gemma 26B, then the app's sample haul photo. That photo is generated, with deposit stickers added so the marks are readable.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The screen is on at the start and at the end. In between, it's Google Maps in your pocket and your eyes on the ground. That was the rule I designed around: the app's job is to get you out the door and then get out of the way.&lt;/p&gt;

&lt;p&gt;It's for people who walk anyway and would like the walk to do something: dog walkers, students, anyone who joins a local cleanup. I volunteer on weekend cleanups in Terryland Forest Park, which is why the demo starts there.&lt;/p&gt;

&lt;p&gt;It covers Ireland's Re-turn and 18 other European deposit schemes, each with its own rates and rules. Return Route is unofficial and not affiliated with Re-turn or any scheme operator.&lt;/p&gt;

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

&lt;p&gt;The full walk, from planning at home to the voucher, filmed on Ray-Ban Meta glasses and my phone (12 minutes, with chapters):&lt;/p&gt;

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

&lt;p&gt;The one-minute version:&lt;/p&gt;


&lt;div&gt;
    &lt;iframe src="https://www.youtube.com/embed/PUGyHXOnkZs" width="315" height="560"&gt;
    &lt;/iframe&gt;
  &lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Try it:&lt;/strong&gt; &lt;a href="https://return-route.onrender.com" rel="noopener noreferrer"&gt;return-route.onrender.com&lt;/a&gt;. It runs on Render's free tier, so the first load after a quiet spell takes about 50 seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not in Europe?&lt;/strong&gt; Open &lt;a href="https://return-route.onrender.com/?demo" rel="noopener noreferrer"&gt;return-route.onrender.com/?demo&lt;/a&gt;, or tap the demo button on the home screen. The guided demo plans a real walk from Terryland Forest Park with Gemma, plays it on the map, then shows the actual haul from my walk and the voucher it earned. It never touches your own totals.&lt;/p&gt;

&lt;h2&gt;
  
  
  I took it outside
&lt;/h2&gt;

&lt;p&gt;Sunday 11 October, east Galway, 15°C and overcast. Times are Irish time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;17:26:&lt;/strong&gt; Planned a 90-minute walk at home, with Gemma 4 26B in the cloud. The app's guess: &lt;strong&gt;€1.05 to €3.85&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;17:30:&lt;/strong&gt; Out the door. No gloves. (Bring gloves.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Before I'd left the house:&lt;/strong&gt; a Monster can with the Re-turn logo, not crushed. 15c.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On the road:&lt;/strong&gt; a crushed can (the machine refuses crushed ones, but it's still litter, so it went in the bag), a wrapper, and an off-licence the planner had scored as a hotspot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stop 1, the park:&lt;/strong&gt; spotless. I did find a playground five minutes from home I'd never seen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Between stops:&lt;/strong&gt; a big bottle, damaged, so it pays nothing. Then a Strong Power can in a hedge: the first real score of the day. A squashed Coca-Cola can and a carton.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stop 2, the skate park:&lt;/strong&gt; busy with kids, so I left it to them. A glass bottle stayed in the bush: glass isn't in Re-turn, and it's not something to handle bare-handed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stop 3:&lt;/strong&gt; Google Maps led me to a college fence with no way in. It was getting dark and the last stop was far, so I headed for Lidl. My guess on camera: "about 30 cents".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;18:19:&lt;/strong&gt; I photographed the haul. The laptop tier failed first, because the laptop was at home. The cloud tier read it: 2 cans, deposit mark not visible, the crushed cans and the bottle struck off. &lt;strong&gt;€0.00 for sure, up to €0.30.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;18:27:&lt;/strong&gt; The Re-turn machine took 2 cans. &lt;strong&gt;Voucher: €0.30.&lt;/strong&gt; The top of Gemma's range, exactly my guess, and well below the app's estimate.&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%2Fyajw8zkif3qvi4rz3k09.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%2Fyajw8zkif3qvi4rz3k09.jpg" alt="Four frames from the walk: a can pulled from a hedge, a fence around a college with no way in, the haul in a black bag, and Gemma's reading on the phone: €0.00 for sure, up to €0.30" width="798" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1kejwmrp2xbt41uejiez.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%2F1kejwmrp2xbt41uejiez.jpg" alt="The Re-turn machine's screen at Lidl: 2 containers, deposit total €0.30, with paper voucher, digital voucher and donation buttons" width="800" height="1067"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What I said outside Lidl, unscripted: &lt;em&gt;"the open source project that I just made is working very well … we touched grass, I hope that counts."&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What the walk taught me
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;My neighbourhood is cleaner than the planner thought.&lt;/strong&gt; It guessed €1.05 to €3.85 and I made €0.30. I'll take that as good news about east Galway. It's also exactly what the app's hotspot history is for: every logged walk shifts the estimate for the stops you visited.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The stops were the quietest part.&lt;/strong&gt; The cans were in hedges, on walls and along the road near the off-licence, not at the picnic tables. The planner's starting scores favour parks, and on a clean Sunday the park was clean.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A stop behind a fence is a dead end.&lt;/strong&gt; The map said there was something worth visiting; it didn't say you can't get in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Photo close, labels up.&lt;/strong&gt; From above, in a bag, Gemma couldn't confirm the small Re-turn logos. The + button fixed the count by hand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crushed doesn't pay.&lt;/strong&gt; Pick them up anyway.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bring gloves.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What I changed after the walk
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;No more stops behind a school gate.&lt;/strong&gt; Pitches and picnic tables inside school or childcare grounds, and anything mapped as private, are no longer stops, unless the map marks that pitch as open to the public. University campuses stay in, because they're usually open. When I checked the map data for east Galway afterwards, 17 pitches and 6 picnic tables were inside school grounds; the city snapshot had 51 more school pitches and a school playground. They're gone now.&lt;/p&gt;

&lt;p&gt;The first version still leaked 6 pitches when the map came from vector tiles. A place near the edge of a tile also appears in the next tile's margin, and that tile only carries a sliver of the school's outline, so the check passed. Each place is now read only from the tile it's actually in.&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/MuhammadMurtuzaHussain" rel="noopener noreferrer"&gt;
        MuhammadMurtuzaHussain
      &lt;/a&gt; / &lt;a href="https://github.com/MuhammadMurtuzaHussain/return-route" rel="noopener noreferrer"&gt;
        return-route
      &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&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/MuhammadMurtuzaHussain/return-route/docs/post/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%2FMuhammadMurtuzaHussain%2Freturn-route%2FHEAD%2Fdocs%2Fpost%2Fcover.png" alt="Return Route. An hour's walk, €0.30. Gemma plans the litter loop, code counts the money. A real walk in Galway, and the Lidl deposit voucher to prove it." width="100%"&gt;&lt;/a&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Return Route&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;A walk that pays.&lt;/strong&gt; Gemma plans a loop through the spots where cans and bottles get left behind,&lt;br&gt;and ends it at a deposit return machine. Keep the refund, or give it away.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://return-route.onrender.com" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/cc7146c13fff32aca1ea68b62b77407f2ad13ea908409f93fbffa100c95bb999/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6976655f6170702d72657475726e2d2d726f7574652e6f6e72656e6465722e636f6d2d6538626234353f7374796c653d666c61742d737175617265266c6162656c436f6c6f723d313231323130" alt="Live app"&gt;&lt;/a&gt;
&lt;a href="https://return-route.onrender.com/?demo" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/55afb685743d6dfec8470726faf3df129a5775b6a4884d836009a48cad751368/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6775696465645f64656d6f2d25324625334664656d6f2d3566643339613f7374796c653d666c61742d737175617265266c6162656c436f6c6f723d313231323130" alt="Guided demo"&gt;&lt;/a&gt;
&lt;a href="https://youtu.be/NBnc0FkvwoU" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/abe1d379a656595a6ff58bc52941a1b93cd74147513720198f09c0b0ca52b514/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7468655f77616c6b2d31325f6d696e5f766964656f2d6563656365363f7374796c653d666c61742d737175617265266c6162656c436f6c6f723d313231323130266c6f676f3d796f7574756265266c6f676f436f6c6f723d7768697465" alt="Full walk video"&gt;&lt;/a&gt;
&lt;a href="https://github.com/MuhammadMurtuzaHussain/return-route/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f603c0711ca93c6ce654deedd55c0e9f937a7b683040092e0c1384d0714512ac/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d6563656365363f7374796c653d666c61742d737175617265266c6162656c436f6c6f723d313231323130" alt="MIT"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://ai.google.dev/gemma" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/23637b5aa6ad98666ee0cfdcd7db5071f917910ef8070b91bd4a6709a58c6255/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f47656d6d615f342d4532425f2543322542375f4534425f2543322542375f3236422d3261326132363f7374796c653d666c61742d737175617265266c6f676f3d676f6f676c65266c6f676f436f6c6f723d7768697465" alt="Gemma 4"&gt;&lt;/a&gt;
&lt;a href="https://mastra.ai" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/688f529fc744f834594999d9d4c3974c0ac040441d8d7ee9e3aca9bae5593a4e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4d61737472612d776f726b666c6f772d3261326132363f7374796c653d666c61742d737175617265" alt="Mastra"&gt;&lt;/a&gt;
&lt;a href="https://render.com" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/364998165524f1ad7a5abb251ed746a6667b0ebc18be0e14fd7655da0f05b982/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f52656e6465722d426c75657072696e745f2532425f4b65795f56616c75652d3261326132363f7374796c653d666c61742d737175617265266c6f676f3d72656e646572266c6f676f436f6c6f723d7768697465" alt="Render"&gt;&lt;/a&gt;
&lt;a href="https://sentry.io" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/cb71a67511e56710998a93b65a6c946008583bab9d5c4ac1f0042d05e95f7c59/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f53656e7472792d6167656e745f74726163696e672d3261326132363f7374796c653d666c61742d737175617265266c6f676f3d73656e747279266c6f676f436f6c6f723d7768697465" alt="Sentry"&gt;&lt;/a&gt;
&lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/02195319df322716bea6443edee04d6ed435646716ed5f1b2ce0ffc5df15244f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4861636b746f626572666573742d5765656b5f312533415f546f7563685f47726173732d3261326132363f7374796c653d666c61742d737175617265" alt="Hacktoberfest"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Ireland's Re-turn scheme pays 15c for a can or a small bottle and 25c for a big one, so every can in a hedge is a refund nobody claimed. Return Route turns that into a reason to go outside. Tell it how long you've got. It plans a walk past picnic tables, pitches and viewpoints near off-licences, gives you an honest range for what you might make, hands the route to Google Maps, and then gets out of your way.&lt;/p&gt;
&lt;p&gt;When you're back, take one photo of your haul. Gemma counts the containers, flags the ones the machine will refuse and works out your refund from the deposit table. Keep the money, or switch to…&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/MuhammadMurtuzaHussain/return-route" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;MIT licensed, built during the challenge week, with 54 tests. If you only read six files, read these:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/MuhammadMurtuzaHussain/return-route/blob/main/src/lib/ai/guard.ts" rel="noopener noreferrer"&gt;&lt;code&gt;src/lib/ai/guard.ts&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Every rule Gemma can't break: real stops only, no money talk, no bins&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/MuhammadMurtuzaHussain/return-route/blob/main/src/lib/countries.ts" rel="noopener noreferrer"&gt;&lt;code&gt;src/lib/countries.ts&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;19 deposit schemes, and the only place money comes from&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/MuhammadMurtuzaHussain/return-route/blob/main/src/mastra/workflows/planWalk.ts" rel="noopener noreferrer"&gt;&lt;code&gt;src/mastra/workflows/planWalk.ts&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The planning workflow, with map, weather and events in parallel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/MuhammadMurtuzaHussain/return-route/blob/main/src/lib/plan/overpass.ts" rel="noopener noreferrer"&gt;&lt;code&gt;src/lib/plan/overpass.ts&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;OpenStreetMap places, minus anything behind a school gate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/MuhammadMurtuzaHussain/return-route/blob/main/src/lib/ai/edge.worker.ts" rel="noopener noreferrer"&gt;&lt;code&gt;src/lib/ai/edge.worker.ts&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Gemma 4 E2B in the browser on WebGPU (untested on a phone)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/MuhammadMurtuzaHussain/return-route/blob/main/src/lib/privacy.ts" rel="noopener noreferrer"&gt;&lt;code&gt;src/lib/privacy.ts&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;What Sentry never sees: coordinates, IPs, cache keys&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Run it on your own laptop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama pull gemma4:e4b
git clone https://github.com/MuhammadMurtuzaHussain/return-route &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="nt"&gt;-route&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pnpm &lt;span class="nb"&gt;install
cp&lt;/span&gt; .env.example .env.local   &lt;span class="c"&gt;# MODEL_PROVIDER=ollama&lt;/span&gt;
pnpm dev                     &lt;span class="c"&gt;# http://localhost:3100&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Gemma judges, code guarantees
&lt;/h3&gt;

&lt;p&gt;A small model will sometimes invent a park, promise you a fiver, or tell you to go through the bins. So I split the work. Gemma does the parts that need judgement. Plain code owns everything that has to be right, and Gemma can't override it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Gemma decides&lt;/th&gt;
&lt;th&gt;Code guarantees&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Which stops, in what order, and why each one&lt;/td&gt;
&lt;td&gt;Every stop is a real place from the map, and the walk fits your time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What's in the photo: material, size, mark visible, crushed or not&lt;/td&gt;
&lt;td&gt;What it pays, from the deposit table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What to look for, and one safety tip&lt;/td&gt;
&lt;td&gt;The place names in the spoken briefing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One opening line for your post&lt;/td&gt;
&lt;td&gt;The count, the amount and the cause in that post&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Gemma picks from a list of real places, and a stop it invents is dropped. A route that's too long is trimmed against the real walking path. Money never comes from the model: any sentence where Gemma mentions an amount is removed before it's shown or read aloud.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** Gemma's words are read aloud; they must not promise money the app did not compute. */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;stripMoney&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(?&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;=&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;.!?&lt;/span&gt;&lt;span class="se"&gt;])\s&lt;/span&gt;&lt;span class="sr"&gt;+/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;sentence&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;€£$&lt;/span&gt;&lt;span class="se"&gt;]\s?\d&lt;/span&gt;&lt;span class="sr"&gt;|&lt;/span&gt;&lt;span class="se"&gt;\d&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\s?(&lt;/span&gt;&lt;span class="sr"&gt;euro|eur|cent|kr|zł|ft&lt;/span&gt;&lt;span class="se"&gt;)\b&lt;/span&gt;&lt;span class="sr"&gt;/i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sentence&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/** Bins belong to the people who rely on them. Keep "leave bins alone", drop "look in the bins". */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;leaveBins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(?&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;=&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;.!?&lt;/span&gt;&lt;span class="se"&gt;])\s&lt;/span&gt;&lt;span class="sr"&gt;+/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;sentence&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;bins&lt;/span&gt;&lt;span class="se"&gt;?\b&lt;/span&gt;&lt;span class="sr"&gt;|pfandring/i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sentence&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b(&lt;/span&gt;&lt;span class="sr"&gt;leave|don'&lt;/span&gt;&lt;span class="se"&gt;?&lt;/span&gt;&lt;span class="sr"&gt;t|do not|never|avoid|not&lt;/span&gt;&lt;span class="se"&gt;)\b&lt;/span&gt;&lt;span class="sr"&gt;/i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sentence&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The walk showed why the split matters. Gemma couldn't see the deposit marks in my bag photo, so it didn't guess. It reported "mark not visible", and the code turned that into a range: €0.00 for sure, up to €0.30. The machine paid the top of it. When a model that handles money can't see, I want it to say so, and this one did.&lt;/p&gt;

&lt;p&gt;That split is also what should let a 2B model in a phone's browser do the same job as a 26B model in the cloud.&lt;/p&gt;
&lt;h3&gt;
  
  
  One model family, three places
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Where&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Where your haul photo goes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;In the cloud&lt;/td&gt;
&lt;td&gt;Gemma 4 26B-A4B through Google AI Studio&lt;/td&gt;
&lt;td&gt;To Google&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;On your laptop&lt;/td&gt;
&lt;td&gt;Gemma 4 E4B through Ollama&lt;/td&gt;
&lt;td&gt;Nowhere: it stays on your laptop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;In your phone's browser&lt;/td&gt;
&lt;td&gt;Gemma 4 E2B on WebGPU (&lt;a href="https://huggingface.co/onnx-community/gemma-4-E2B-it-ONNX" rel="noopener noreferrer"&gt;transformers.js&lt;/a&gt;), about 3.4 GB once&lt;/td&gt;
&lt;td&gt;Nowhere: it's read on the phone&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You pick in Settings. The prompts, the guard and the deposit table are the same for all three.&lt;/p&gt;

&lt;p&gt;The phone tier is &lt;strong&gt;untested&lt;/strong&gt;. The code is in the repo and the production build bundles the worker and the WebGPU runtime, but I haven't had an Android phone to run it on, so I can't tell you how long the download takes or how fast it plans. Treat it as the part I'd test first.&lt;/p&gt;

&lt;p&gt;Planning needs open map, weather and routing services (OpenFreeMap, Open-Meteo, Valhalla), so your start point goes to those whichever tier you pick. What changes between tiers is where your photo and the model's work go.&lt;/p&gt;
&lt;h3&gt;
  
  
  The planner: a Mastra workflow
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;place ──► map ║ weather ║ events ──► assemble ──► pick ──► route
 │          │      │         │          │          │         │
 deposit    OSM    Open-     SerpApi    score      Gemma     Valhalla walking
 scheme     POIs   Meteo     (optional) hotspots   picks &amp;amp;   route, trimmed
 for the                                           orders    until it fits
 country                                           2-3 stops
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The map, the weather and today's events are fetched in parallel. The score is a hotspot prior for each kind of place, times yesterday's weather (a warm evening leaves cans behind), the day of the week, any match or gig nearby, and your own past hauls. Nobody has a live litter feed, so the estimate starts as an honest guess and gets sharper with each walk you log. That history stays on your device. There are no accounts.&lt;/p&gt;

&lt;p&gt;If your country has no deposit scheme, the first step stops the workflow with a plain message instead of planning a walk that can't pay. On the phone tier, the server runs the first half of the same workflow, Gemma picks the stops in a Web Worker, and the server checks and routes the result.&lt;/p&gt;

&lt;p&gt;Here's one plan from the live site, as Sentry traced it. The Gemma call is 7.2 of the 8.7 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%2Fzzf7u9jndl0bf4dunf7c.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%2Fzzf7u9jndl0bf4dunf7c.png" alt="A Sentry trace waterfall of one plan: the plan-walk workflow with its place, map, weather, events, assemble, pick and route steps; inside pick, invoke_agent Return Route planner and chat gemma-4-26b-a4b-it take 7.2 seconds, and route calls Valhalla in 0.75 seconds" width="744" height="182"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Measuring it
&lt;/h3&gt;

&lt;p&gt;I wrote 8 Galway walks (different starts, lengths and notes like "finish at Lidl" or "stay off the main road") and ran them through both server tiers before and after tightening the planner:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Plans the guard didn't touch&lt;/th&gt;
&lt;th&gt;Too long&lt;/th&gt;
&lt;th&gt;Invented stop&lt;/th&gt;
&lt;th&gt;Finished where asked&lt;/th&gt;
&lt;th&gt;Time per plan&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cloud, 26B-A4B, before&lt;/td&gt;
&lt;td&gt;7/8&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;4/5&lt;/td&gt;
&lt;td&gt;5.2 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud, 26B-A4B, after&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;8/8&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5/5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5.3 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Laptop, E4B, before&lt;/td&gt;
&lt;td&gt;6/8&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;4/5&lt;/td&gt;
&lt;td&gt;5.7 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Laptop, E4B, after&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7/8&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5/5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5.4 s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The fix was mostly code, not prompting: for every return point on offer, the planner works out which stops still fit if the walk ends there, a shop you name becomes the finish, and two stops in the same field get distinct names. The one stop E4B invented was caught and dropped.&lt;/p&gt;

&lt;p&gt;To be clear about what this measures: it shows Gemma follows the rules. It doesn't show the stops have cans. Only walking tells you that, and on my one walk, the park was clean.&lt;/p&gt;

&lt;p&gt;The haul reader has an eval harness too (&lt;code&gt;pnpm eval&lt;/code&gt;), but only one real haul so far: the bag from this walk. Both server tiers read it as 0 eligible, because the marks were too small from above. The real answer was 2. That's why the camera screen says "labels up, nothing stacked", and it's the first thing I'll measure properly.&lt;/p&gt;
&lt;h3&gt;
  
  
  When the cloud gets turned away
&lt;/h3&gt;

&lt;p&gt;Locally, everything worked. On Render, planning failed. Sentry showed why: every Overpass mirror was answering the server with errors, and the place lookup and weather service were returning 429. Render's free tier sends traffic from IP addresses shared by many apps, and public map servers rate-limit them. A laptop never sees that.&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%2Fa82q4s2u7vivr7w62on6.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%2Fa82q4s2u7vivr7w62on6.png" alt="Sentry breadcrumbs for the failed plan: overpass.private.coffee and overpass.kumi.systems both answering 500, then the error Overpass unavailable" width="715" height="275"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So the map now has a chain of fallbacks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Render Key Value, which caches each neighbourhood for 12 hours.&lt;/li&gt;
&lt;li&gt;A bundled OpenStreetMap snapshot of Galway, so the demo never waits on a map server.&lt;/li&gt;
&lt;li&gt;OpenFreeMap vector tiles from a CDN. A 30-minute area took 1 to 2 seconds in Galway, Berlin, Copenhagen, Amsterdam and Vienna. Return machines come from Overpass alongside, with a 6-second budget.&lt;/li&gt;
&lt;li&gt;Full Overpass.&lt;/li&gt;
&lt;li&gt;The walker's own browser, which fetches the map from their connection and plans again.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The side effect is that plans now work anywhere in Europe, not just in Galway. The whole service is one &lt;code&gt;render.yaml&lt;/code&gt; Blueprint: the web service and the Key Value cache, deployed on every push to &lt;code&gt;main&lt;/code&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%2Fk38x6831mg9gdp3zyix7.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%2Fk38x6831mg9gdp3zyix7.png" alt="The ReturnRoute Blueprint in Render: return-route (Node, deployed) and return-route-cache (Valkey 8, available), synced from the GitHub repo's main branch" width="570" height="255"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  What Sentry sees, and what it shouldn't
&lt;/h3&gt;

&lt;p&gt;Every Gemma call is an agent span with the model, tokens and latency, so I can see the planner and the haul reader side by side. Prompts and replies are never sent: the Input tab is empty on purpose.&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%2Fh6wprgm0u4uo4ttjfbyg.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%2Fh6wprgm0u4uo4ttjfbyg.png" alt="Sentry's agent view: the Return Route planner and the Return Route haul checker, both on gemma-4-26b-a4b-it; the planner call took 7.20 s with 1.9K tokens in and 227 out, and its Input tab says no input for this span" width="744" height="252"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every time the guard overrules Gemma, that's an issue tagged with the tier and the model. The one at the top of the guard list is real: E4B planned a route too long for the time. The three below it I triggered on purpose, to check that the phone tier's picks are guarded and reported too.&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%2Fg0tdi6ekrosvr4oyegus.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%2Fg0tdi6ekrosvr4oyegus.png" alt="Sentry issues: two Overpass unavailable errors from the Render outage, and four guard issues: Gemma's route didn't fit the time, a return point that wasn't on the map, a stop that wasn't on the map, and none of Gemma's stops were real" width="744" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And then I found my own walk in it.&lt;/strong&gt; Taking screenshots for this post, I searched the traces and found 415 weather spans from the last two weeks with the walker's position in the URL: &lt;code&gt;latitude=53.2845&amp;amp;longitude=-9.0420&lt;/code&gt;, accurate to about 10 metres, from both the browser and the server. The cache spans were worse: the rate limiter's key held the walker's IP address, and the map cache's key held rounded coordinates. I had a privacy block in the Sentry config, and it didn't cover either.&lt;/p&gt;

&lt;p&gt;The fix is one small file shared by the browser, server and edge configs. URLs lose their query strings, and cache keys are cut down to their kind:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** "https://api.open-meteo.com/v1/forecast?latitude=53.28…" → "https://api.open-meteo.com/v1/forecast" */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;URL_QUERY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;https&lt;/span&gt;&lt;span class="se"&gt;?&lt;/span&gt;&lt;span class="sr"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\/\/[^\s&lt;/span&gt;&lt;span class="sr"&gt;?#"&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)\?[^\s&lt;/span&gt;&lt;span class="sr"&gt;#"&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*/g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cm"&gt;/** "incr rr:rl:plan:&amp;lt;ip&amp;gt;:29862636" → "incr rr:rl"; "get rr:area:v2:53.28,-9.04,2500" → "get rr:area" */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CACHE_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b(&lt;/span&gt;&lt;span class="sr"&gt;rr:&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-z&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)(?:&lt;/span&gt;&lt;span class="sr"&gt;:&lt;/span&gt;&lt;span class="se"&gt;[^\s&lt;/span&gt;&lt;span class="sr"&gt;"&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)?&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After it deployed, I planned a fresh walk on the live site and opened its trace. The weather span now reads &lt;code&gt;GET https://api.open-meteo.com/v1/forecast&lt;/code&gt;, the rate limiter's span reads &lt;code&gt;incr rr:rl&lt;/code&gt;, and there isn't a coordinate or an IP anywhere in it. The spans sent before the fix will age out with Sentry's retention.&lt;/p&gt;
&lt;h3&gt;
  
  
  Things that went wrong
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gemma sent people into bins.&lt;/strong&gt; It suggested checking bins for bottles. In Germany, people leave bottles on a &lt;em&gt;Pfandring&lt;/em&gt; for those who collect deposits for a living. &lt;code&gt;leaveBins&lt;/code&gt; drops any sentence about bins unless it says to leave them alone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Titles like "Park Waste Collection" and "Eyre Square Park Run".&lt;/strong&gt; A title now has to name a real place on the route, and "run" becomes "loop".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Based on the image, I have identified 7 containers."&lt;/strong&gt; The narration is stripped before the voucher shows Gemma's notes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cities that map every bin&lt;/strong&gt; ranked "Bins (4)" as their best stop. Street furniture is now capped, and bins only count inside a park.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two stops called "Pitch, Wildflower Meadow".&lt;/strong&gt; Look-alikes are now "east end" and "west end", and the briefing never says the same park twice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Map markers drifted 30, 60 and 90 pixels down the page.&lt;/strong&gt; Setting &lt;code&gt;position&lt;/code&gt; on a custom MapLibre marker overrides its own positioning. Don't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A school outline cut off at a tile edge&lt;/strong&gt; let pitches inside school grounds through (above).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;My privacy block had gaps&lt;/strong&gt; (above).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemma 4 E4B overcounts busy hauls by about one.&lt;/strong&gt; The voucher shows every item, so you can correct it before it counts.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;When the payout is 15 cents a can, the AI has to cost nothing.&lt;/strong&gt; A walk that earns €0.30 can't pay for API calls. On a laptop, Gemma costs nothing per plan and nothing per photo, so the maths of the whole idea only works with an open model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your photo doesn't have to leave your device.&lt;/strong&gt; On the laptop tier, the haul photo is read by Gemma on your own machine. The phone tier is built to do the same in the browser, though I haven't tested it on a phone yet. Your walk history stays in your browser too: there are no accounts. A walk history is a map of where you live and when you're out. It shouldn't sit on someone else's server, and after this week, it doesn't sit in my Sentry either.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I could build a box around the model.&lt;/strong&gt; Gemma runs inside my own pipeline, so every output passes through code I wrote and tested before anyone sees it. The same family runs at three sizes in three places, so I wrote the prompts and the guard once, and Sentry tells me which size breaks which rule.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's open all the way down.&lt;/strong&gt; Map data from OpenStreetMap, tiles from OpenFreeMap, walking routes from Valhalla, weather from Open-Meteo, the workflow on Mastra, the phone model on transformers.js. None of them needs a key. The only part that does is the optional cloud tier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where a closed model might do better:&lt;/strong&gt; reading small logos on crumpled cans in a bag. I haven't tested one, so I can't say it would. Both Gemma sizes I tried missed the marks on my real haul, and the honest fix so far is a better photo, not a bigger model.&lt;/p&gt;
&lt;h2&gt;
  
  
  What it can't do yet
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The hotspot scores are educated guesses.&lt;/strong&gt; They're based on what tends to attract drinkers (benches, pitches, off-licences), and my one real walk says roadsides beat parks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reading deposit marks from a bag photo is unreliable.&lt;/strong&gt; Close up, labels up, it works. From above, in a bag, it doesn't.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The phone tier is untested on a real phone.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Europe only:&lt;/strong&gt; 19 schemes. The UK's starts in October 2027. US states with bottle bills aren't in yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free hosting:&lt;/strong&gt; the first plan after a quiet spell waits about 50 seconds for Render to wake up.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;I built Return Route with Claude Code over three days, across five sessions: from reading this challenge, through the brain dump that became the PRD, the redesign, the Render outage, the videos, to the fixes in this post. This is a curated version: my prompts trimmed, Claude's turns summarised, and the tool calls real.&lt;/p&gt;


&lt;div class="ltag-agent-session"&gt;
  &lt;div class="agent-session-header"&gt;
    
    &lt;span class="agent-session-tool-icon-badge" title="Claude Code"&gt;
&lt;/span&gt;
    &lt;span class="agent-session-title"&gt;Building Return Route with Claude Code: from a brain dump to a €0.30 voucher&lt;/span&gt;
  &lt;/div&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Look into the Week 1 challenge, and get back to me when you have understood it. I am thinking of an idea meanwhile.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Read the Week 1 brief. Touch Grass: build something with open-source AI at its core that gets people off the screen and into the world, and make the screen the shortest part of it. Submissions close Sun 11 Oct, 23:59 PDT. Writing quality is weighted most, taking it outside earns bonus points, and you can win only one prize category.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-getchallenges"&gt;get_challenges&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;DEV challenges&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;DEV challenges&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Hacktoberfest Open-Source AI Challenge: Week 1, 5 to 11 Oct. Featured: Render, TabPFN, Tinker, Arduino, DigitalOcean, Gemma. Partner: Mastra, Sentry Agent Tracing and 8 more.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div&gt;
                  &lt;div class="agent-session-text agent-session-text-collapse"&gt;
                    &lt;p&gt;Here's my unedited brain dump. Categorize it into a PRD and tell me how the plan looks for the vision I have in mind. The persona is a student, an early-career person or just a young adult, who likes to walk around and explore the city but would also like a bit more change in their pocket. One easy way to get extra coins is collecting cans and bottles and sending them into the return machine. This is inspired by a story of a person in Germany who picked up about 2,000 bottles, turned them in for 500 euro and bought a PS5. Can my app give people a good, predictable path around parks and the usual hotspots where they can pick up cans and litter? Focus on Ireland, because that's where I know the return scheme works, and other European countries with a scheme, plus the UK.&lt;/p&gt;

                  &lt;/div&gt;
                  Show more
                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div&gt;
                  &lt;div class="agent-session-text agent-session-text-collapse"&gt;
                    &lt;p&gt;Wrote the PRD for "Return Route": say how long you've got, get a loop through likely hotspots that ends at a return machine, with an honest € range, then put the phone away. Checking the facts changed the plan: the UK scheme only starts in October 2027, so v1 is Ireland plus other live European schemes. The PS5 story is a viral 9GAG post with no outside confirmation, so the post should call it unverified. Re-turn pays 15c up to 500 ml and 25c above, only for cans and PET bottles with the logo, and the machines refuse crushed ones. Other Week 1 entries are already walk planners, so the edge is the money.&lt;/p&gt;

                  &lt;/div&gt;
                  Show more
                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-websearch"&gt;WebSearch&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Germany man collected 2000 bottles Pfand bought PS5&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Germany man collected 2000 bottles Pfand bought PS5&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Only the viral post itself; treat it as an unconfirmed viral story.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-websearch"&gt;WebSearch&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;UK deposit return scheme launch date England Scotland 2027&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;UK deposit return scheme launch date England Scotland 2027&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;October 2027, 20p per container.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-searchdevtosemantic"&gt;search_dev_to_semantic&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;walking route planner with OpenStreetMap and open source routing&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;walking route planner with OpenStreetMap and open source routing&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Paper Walk and other Week 1 walk planners.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;I like everything. Can we run a small-weight model locally, for an edge AI use case? If so, let's build that, as well as cloud Google AI Studio. Scope: Ireland and other European countries with a return scheme. Donate mode: keep it in v1. Solo. Keep this project polished and ambitious, we need to win.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Built the MVP with Gemma in three places: E2B in the browser on WebGPU through transformers.js, E4B through Ollama, and 26B-A4B through AI Studio, with a Mastra planner and a deposit table for 19 European schemes. The rule from day one: Gemma picks stops from a list of real places and explains them; code drops invented stops, trims long routes, composes the spoken place names and prices everything, and stripMoney removes any amount Gemma writes. Public Overpass servers kept failing, so Galway ships as a saved OpenStreetMap snapshot. The phone tier builds but hasn't run on a phone.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Fetch and save Galway OSM snapshot&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Fetch and save Galway OSM snapshot&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Overpass unavailable: overpass.private.coffee → 500 (4 attempts)&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Retry Galway snapshot with new mirrors&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Retry Galway snapshot with new mirrors&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;galway: 536 features, 210 sources, 25 parks, 19 return points (4 mapped machines)&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Test cloud Gemma tier from Terryland&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Test cloud Gemma tier from Terryland&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;→ Aldi return machine 4.06 km, €0.88 to €3.15&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Run unit tests&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Run unit tests&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Tests 25 passed (25)&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Pushed to GitHub, add the render.yaml file so I can deploy. Once that's done, we need to rework the UI/UX using the taste skill and other stuff, because this is currently very AI slop.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Added a render.yaml Blueprint and redesigned around two objects from the story: an Irish waymarked trail post and a return machine's voucher. The start screen is a fingerpost with three yellow signs (30 min, 1 hour, 90 min). The route is a yellow trail with diamond waymarks. The haul prints as an itemised thermal voucher with crushed or unmarked items struck through. Off-black, paper white, one waymark yellow, Archivo condensed for signs and IBM Plex Mono for the voucher, in light and dark.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Here's my feedback. The app is perfect for anyone that knows what the app is, however when sharing with an audience it doesn't say much to help a new user. I would like a first-time user pop-up referencing the 9GAG story and how the app works. The Gemma · Cloud button doesn't look like a button, so the local option is quite slept on. Donate the refund does nothing: what does it actually do? Maybe a toggle that changes the UI into something more motivating, like walking for a cause, and helps you write a quick tweet. And the note button doesn't say that's how you customise your walk.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Added a welcome pop-up (the 9GAG story, three steps, where Gemma runs), turned the Gemma switch into a real control with a border and caret, renamed the note to "Customise this walk: your own time or direction", and sketched a cause mode for Donate.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;I want you to open and audit, then tell me potential fixes and recommendations.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Ran the app at desktop and phone width, light and dark, and planned a real hour from Terryland on local Gemma. Worst bug: map markers for stops 2, 3 and € were drawn 30, 60 and 90 px below their real positions, because an inline position:relative on each marker overrode MapLibre's own positioning. Also found: Gemma suggesting people look in bins, generic titles like "Park Waste Collection", lowercased place names, a theme flash on reload and a sideways page jump.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Apply all, plus recommendations. Regarding Donate mode, I want the UI to have a different colour panel and an experience that makes people feel good about themselves. Also, since this app will be demoed for the competition, can we have the whole workflow demoed, from plotting to scanning and everything?&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Walk for a cause turns the whole app green, names the cause, counts what you've given, and ends on a thank-you screen with a post: Gemma writes only the opening line, and guardPostLine strips numbers, money and hashtags so the count and amount come from the voucher. The guided demo at /?demo runs the whole flow in 8 steps with live Gemma, never touches real totals, and falls back to a labelled recorded plan if Gemma can't be reached. leaveBins now drops any sentence about bins unless it says to leave them alone.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Typecheck, lint, tests, production build&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Typecheck, lint, tests, production build&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Tests 33 passed (33); build succeeded&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;What partner technologies are we using? I'm seeing how we can use niche technologies to increase our chances of winning a prize, as well as tune our model and look for room to improve. I just read the past weekend's overall winning write-up, and now I'm thinking how we can go an extra mile while keeping the app as simple as it is.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div&gt;
                  &lt;div class="agent-session-text agent-session-text-collapse"&gt;
                    &lt;p&gt;Made planning a Mastra workflow (place → map ‖ weather ‖ events → assemble → pick → route) that stops early with a plain message where no scheme exists. Added Sentry: a span per step, so the parallel fetches visibly overlap, gen_ai spans per Gemma call with model, tier and tokens, and one issue per guard rule tagged with tier and model, with no prompts, coordinates or photos sent. SerpApi was dropped because the free plan lacks the Google Events engine. Then moved planning problems into code: for every possible finish, code works out which stops fit, a named shop becomes the finish, and look-alike stops get distinct names.&lt;/p&gt;

                  &lt;/div&gt;
                  Show more
                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;pnpm eval:plan, 8 Galway walks per tier, before and after&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ pnpm eval:plan, 8 Galway walks per tier, before and after&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Cloud 26B: untouched by the guard 7/8 → 8/8, too long 1 → 0, finish honoured 4/5 → 5/5. Local E4B: 6/8 → 7/8, 2 → 0, 4/5 → 5/5&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;The app isn't working in the cloud, check what's wrong.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;The Sentry issue showed every Overpass mirror refusing the Render server, plus 429s from the place lookup and the weather service. Render's free tier sends traffic from IPs shared with thousands of apps, and public map servers rate-limit them; a laptop never sees it. Map data now comes from OpenFreeMap's vector tiles on a CDN, with Key Value cache, snapshots, full Overpass and the walker's own browser as fallbacks. Plans now work anywhere in Europe.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Time a 30-minute area from tiles in five cities&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Time a 30-minute area from tiles in five cities&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Galway, Berlin, Copenhagen, Amsterdam, Vienna: about 1 to 2 s each&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;I am back from the walk, I have added video from my walk and some photos. I want you to make 2 videos: one an interesting punchy reel with captions and motion graphics, and a full comprehensive video of the walk and the app. In the photos there is my haul; use that photo in the actual demo. The cans were recyclable, so I got the money back: make sure the demo returns €0.30.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Live reads of the real bag photo by both E4B and 26B came to €0.00: from above, the Re-turn logos are too small to confirm. So the demo shows the reading checked against the Lidl voucher (2 cans at 15c, €0.30) and says where it came from, while a photo taken in the demo still goes to Gemma live. Made both videos in Remotion: a 65-second reel and an 11:54 full walk with chapters. Captions come from a transcript of the audio, and where a figure was unclear the caption says "…" rather than putting words in your mouth.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Look at the winning write-ups from the past weekend challenge so we get an idea of good practice, then craft our write-up with all the good elements. Also give me honest feedback on the project. Don't worry about the deadline, worry about quality, polish and relevance.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Read the overall, Gemma, Render, Mastra and Sentry winners. What they share: a real opening scene, failures shown and kept in the numbers, code owning the risky parts, partner sections backed by screenshots, and a "where closed would do better" paragraph. Drafted the post around the irony of an hour's walk for €0.30. Honest feedback included: the phone tier is untested, the hotspot priors didn't hold up on the one real walk (the park was clean, the cans were in hedges), and one stop sat behind a college fence.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-getarticlecontent"&gt;get_article_content&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Congrats to the Hacktoberfest Weekend Challenge: Build for a Friend Winners&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Congrats to the Hacktoberfest Weekend Challenge: Build for a Friend Winners&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Overall: Before I Call. Gemma: Kitchen Table. Render: Tala. Mastra: Prep Buddy. Sentry: Actually.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;We can fix the private grounds one. The estimate was €1.05 to €3.85, but it's fine: a good indication that our neighbourhood is clean.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div&gt;
                  &lt;div class="agent-session-text agent-session-text-collapse"&gt;
                    &lt;p&gt;Stops inside school or childcare grounds, and anything tagged access=private, are no longer stops, unless the map marks that pitch as open. University campuses stay, since they're usually open. Overpass now returns school outlines; tiles use OpenMapTiles' landuse school polygons. The tile path still leaked 6 pitches: a place near a tile edge was read from the neighbour tile's margin, where that tile holds only a sliver of the school outline. Each place is now read from the tile it's in. Snapshots refreshed with only removals: east Galway lost 17 pitches and 6 picnic tables, the city 51 school pitches and a school playground. The area cache key was bumped so old areas aren't reused.&lt;/p&gt;

                  &lt;/div&gt;
                  Show more
                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Find snapshot stops inside school grounds (east Galway)&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Find snapshot stops inside school grounds (east Galway)&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;picnic ×6 and pitch ×4 → Merlin College Secondary School; pitches in 6 more schools&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Tiles around Merlin College: places inside school grounds&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Tiles around Merlin College: places inside school grounds&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;before the fix: 38 places, 6 inside school grounds; after: 32 places, 0 inside&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;pnpm test, tsc, lint, build&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ pnpm test, tsc, lint, build&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Tests 51 passed (51); build succeeded&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
  &lt;/div&gt;

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



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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma:&lt;/strong&gt; Gemma 4 is the only model, in three places (26B-A4B through AI Studio, E4B through Ollama, and E2B in the browser on WebGPU, which is built but untested on a phone), with one guard around all of them. Gemma plans the walk, reads the haul photo and drafts the post; code owns the stops and the money. Measured over 8 walks per server tier, before and after, and tested on a real walk that ended in a real voucher.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Render:&lt;/strong&gt; one &lt;code&gt;render.yaml&lt;/code&gt; Blueprint runs the app and a Render Key Value cache shared by the map, events and rate limits, deployed on every push. Render's shared outbound IPs taught me how public map servers treat cloud traffic, and the five-step fallback that came out of it makes plans work anywhere in Europe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Mastra:&lt;/strong&gt; planning is a Mastra workflow, &lt;code&gt;place → map ‖ weather ‖ events → assemble → pick → route&lt;/code&gt;, with the map, weather and events steps in parallel. It stops early with a plain message when a country has no scheme, and the phone tier runs its first half on the server and the Gemma step on the phone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Sentry Agent Tracing:&lt;/strong&gt; each plan is a trace with a span per workflow step and &lt;code&gt;gen_ai&lt;/code&gt; agent spans for the planner and the haul reader, with model, tokens and latency, and no prompts. Every guard override is an issue tagged with tier and model. Sentry found the Render outage that local runs never showed, and, while I was writing this post, a privacy hole in my own setup, which is now fixed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Built solo.&lt;/p&gt;

&lt;p&gt;If there's a deposit scheme where you live, take it out for half an hour and tell me in the comments what you found. And if you only find clean parks, that's useful too: it's what the planner needs to learn.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with AI assistance (Claude Code). I reviewed, tested and edited everything. The walk, the voucher and the evaluation numbers are real.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>gemma</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Pīzhù 批注: a writing tutor that never rewrites your essay, built for my friend Joy (Gemma 4)</title>
      <dc:creator>Muhammad Murtuza Hussain</dc:creator>
      <pubDate>Fri, 02 Oct 2026 17:11:44 +0000</pubDate>
      <link>https://dev.to/muhammadmurtuzahussain/pizhu-pi-zhu-a-writing-tutor-that-never-rewrites-your-essay-built-for-my-friend-joy-gemma-4-2n6e</link>
      <guid>https://dev.to/muhammadmurtuzahussain/pizhu-pi-zhu-a-writing-tutor-that-never-rewrites-your-essay-built-for-my-friend-joy-gemma-4-2n6e</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01"&gt;Hacktoberfest Weekend Challenge: Build for a Friend&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;My friend &lt;strong&gt;Joy&lt;/strong&gt; is doing an MA in Global Mass Communication in Ireland. Her first language is Mandarin. She reads media theory in two languages, argues well, and still gets essays back with comments like &lt;em&gt;"expression needs work"&lt;/em&gt; and &lt;em&gt;"be careful with academic tone"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Me and Joy met at the library of our university, both of us spend most of our day working in the reading room. This one particular afternoon, Joy invited me for a drink break at our student bar, where she also had her informal meeting with her EAP (english for academic purposes) faculty, where they discussed her dissertation, and I noticed how Joy received the feedback from faculty, but couldn't get the reasoning behind it, the faculty all could say was, &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's Just bad english&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;she said.&lt;/p&gt;

&lt;p&gt;This moment had me to tinkering, but also I recalled that, I have seen the same thing with a lot of friends from China and Taiwan. The marks they lose are rarely about ideas. They come from a handful of habits that make perfect sense in Chinese and read badly to a British marker:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No articles.&lt;/strong&gt; Mandarin has no &lt;em&gt;a&lt;/em&gt; or &lt;em&gt;the&lt;/em&gt;, so &lt;em&gt;"The society is changing"&lt;/em&gt; feels natural.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;一逗到底, "one comma all the way".&lt;/strong&gt; A Chinese sentence can run through commas until the thought is complete. In English that is a comma splice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exam-template English.&lt;/strong&gt; &lt;em&gt;"With the development of society…"&lt;/em&gt;, &lt;em&gt;"In a word…"&lt;/em&gt; were taught as good style for 高考 and IELTS. A UK marker reads them as filler.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confident claims.&lt;/strong&gt; &lt;em&gt;"This proves…"&lt;/em&gt; and &lt;em&gt;"Everyone knows…"&lt;/em&gt; (众所周知) persuade in Chinese argumentative writing. In a UK essay they are unsupported.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The usual tools make this worse. Grammar checkers and chatbots &lt;strong&gt;rewrite&lt;/strong&gt; the paragraph. It sounds fluent, it stops sounding like the student, she learns nothing, and in UK and Irish universities an AI-rewritten essay is an academic-integrity problem.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Pīzhù (批注)&lt;/strong&gt;. The word means &lt;em&gt;margin notes&lt;/em&gt;: the comments a good teacher writes beside your work. That is the whole product:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It underlines the &lt;strong&gt;exact words&lt;/strong&gt; a UK marker would pause on.&lt;/li&gt;
&lt;li&gt;It explains &lt;strong&gt;why&lt;/strong&gt;, in English and in Chinese (简体 or 繁體), including &lt;strong&gt;why a Mandarin speaker tends to write it that way&lt;/strong&gt;, framed as a habit, never a mistake in thinking.&lt;/li&gt;
&lt;li&gt;It gives a &lt;strong&gt;hint&lt;/strong&gt;, and at most a tiny &lt;strong&gt;nudge&lt;/strong&gt; of a few words.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It never rewrites.&lt;/strong&gt; Joy makes every change herself.&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/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7hm0qn4so6yfwvfiim4r.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%2F7hm0qn4so6yfwvfiim4r.gif" alt="Pīzhù's live demo: a Chinglish sentence gets marker-pen underlines and bilingual margin notes" width="599" height="231"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Try it:&lt;/strong&gt; &lt;a href="https://pizhu.onrender.com" rel="noopener noreferrer"&gt;pizhu.onrender.com&lt;/a&gt;. Press &lt;strong&gt;Try a sample&lt;/strong&gt;, then &lt;strong&gt;Check my writing&lt;/strong&gt;. The sample essay is one I wrote for testing; it is full of these habits and includes one reference I invented on purpose, so you can watch the reference checker catch it. (The demo runs on Render's free tier, so the very first load can take a few seconds to wake up.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The essay on grid paper, with notes in the margin.&lt;/strong&gt; Every note sits beside its own line, and the open one draws an ink line to its words.&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%2F1sn9eyb82knezbyz2h2s.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%2F1sn9eyb82knezbyz2h2s.png" alt="Margin notes beside the essay" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson mode.&lt;/strong&gt; One note at a time, with tapioca pearls as progress. Enter for "got it", the arrow keys to move.&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%2Fk1ngji5hvrwpxh33860i.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%2Fk1ngji5hvrwpxh33860i.png" alt="Lesson mode" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Back to Word.&lt;/strong&gt; Students write in Word, and Word comments are literally margin notes, so one click gives Joy her own document back, every word unchanged, with each note as a comment from Mòmo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reference check.&lt;/strong&gt; Google Scholar via SerpApi: three real books found, the invented one flagged.&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%2Fh3icgrn54lafzhulnnta.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%2Fh3icgrn54lafzhulnnta.png" alt="Reference check" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On a phone, in dark mode, in 简体中文.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzv1kiy8h3s5t13uy4jts.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%2Fzv1kiy8h3s5t13uy4jts.png" alt="Mobile, dark mode, Simplified Chinese" width="800" height="1731"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Everything is open source (MIT) at &lt;strong&gt;&lt;a href="https://github.com/MuhammadMurtuzaHussain/pizhu" rel="noopener noreferrer"&gt;github.com/MuhammadMurtuzaHussain/pizhu&lt;/a&gt;&lt;/strong&gt;. If you only read four files, read these:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/MuhammadMurtuzaHussain/pizhu/blob/main/src/lib/guard.ts" rel="noopener noreferrer"&gt;&lt;code&gt;src/lib/guard.ts&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The "never rewrite" rule: verbatim spans and a word-level edit budget for nudges&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/MuhammadMurtuzaHussain/pizhu/blob/main/src/mastra/agents/prompts.ts" rel="noopener noreferrer"&gt;&lt;code&gt;src/mastra/agents/prompts.ts&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The tutor brief: twelve Mandarin-to-English habits and the checklist Gemma follows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/MuhammadMurtuzaHussain/pizhu/blob/main/src/mastra/workflows/references.ts" rel="noopener noreferrer"&gt;&lt;code&gt;src/mastra/workflows/references.ts&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The reference check: Gemma extracts, code matches, SerpApi verifies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/MuhammadMurtuzaHussain/pizhu/blob/main/src/components/MarginPaper.tsx" rel="noopener noreferrer"&gt;&lt;code&gt;src/components/MarginPaper.tsx&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Margin notes positioned beside each line, with the ink connector&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Run it privately on your own laptop in three commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama pull gemma4:e4b
git clone https://github.com/MuhammadMurtuzaHussain/pizhu &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;pizhu &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pnpm &lt;span class="nb"&gt;install
&lt;/span&gt;pnpm dev   &lt;span class="c"&gt;# http://localhost:3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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/MuhammadMurtuzaHussain" rel="noopener noreferrer"&gt;
        MuhammadMurtuzaHussain
      &lt;/a&gt; / &lt;a href="https://github.com/MuhammadMurtuzaHussain/pizhu" rel="noopener noreferrer"&gt;
        pizhu
      &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;p&gt;
  &lt;a href="https://pizhu.onrender.com" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FMuhammadMurtuzaHussain%2Fpizhu%2Fmain%2Fsrc%2Fapp%2Fopengraph-image.png" alt="Pīzhù 批注: margin notes, not rewrites. Mòmo the ink panda holding a bubble tea." width="100%"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
  &lt;b&gt;Margin notes, not rewrites.&lt;/b&gt; An open-source writing tutor for Mandarin-speaking students at UK and Irish universities, powered by open-weight &lt;b&gt;Gemma 4&lt;/b&gt;
&lt;/p&gt;
&lt;p&gt;
  &lt;a href="https://pizhu.onrender.com" rel="nofollow noopener noreferrer"&gt;&lt;b&gt;Live demo&lt;/b&gt;&lt;/a&gt; ·
  &lt;a href="https://dev.to/muhammadmurtuzahussain" rel="nofollow"&gt;DEV post&lt;/a&gt; ·
  &lt;a href="https://github.com/MuhammadMurtuzaHussain/pizhu#run-it-locally-private-nothing-leaves-your-laptop" rel="noopener noreferrer"&gt;Run locally&lt;/a&gt; ·
  Built for the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01" rel="nofollow"&gt;DEV Hacktoberfest Weekend Challenge&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/MuhammadMurtuzaHussain/pizhu/main/docs/screenshots/demo.gif"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2FMuhammadMurtuzaHussain%2Fpizhu%2Fmain%2Fdocs%2Fscreenshots%2Fdemo.gif" alt="A Chinglish sentence gets marker-pen underlines and bilingual margin notes" width="760"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;My friend Joy is doing an MA in Global Mass Communication in an Irish University. Her ideas are sharp; her marks lose points to a small set of habits that make perfect sense in Chinese and read badly to a British marker: no articles (中文没有冠词), comma splices (一逗到底), exam-template phrases ("With the development of society…"), and confident claims (众所周知).&lt;/p&gt;

&lt;p&gt;Grammar tools and chatbots &lt;strong&gt;rewrite&lt;/strong&gt; the paragraph. It sounds fluent, it stops sounding like her, she learns nothing, and in an Irish university it is an academic-integrity risk.&lt;/p&gt;

&lt;p&gt;Pīzhù does what a good tutor does in the margin: it points at the exact words, explains &lt;em&gt;why&lt;/em&gt; in English and Chinese (简体 or…&lt;/p&gt;&lt;/div&gt;


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


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

&lt;p&gt;&lt;strong&gt;Gemma 4 is the only model in Pīzhù.&lt;/strong&gt; It is open weights under Apache 2.0, and the same family runs in two places:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Where&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Joy's laptop (the default)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;gemma4:e4b&lt;/code&gt; or &lt;code&gt;gemma4:12b&lt;/code&gt; via &lt;strong&gt;Ollama&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Her coursework never leaves her machine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hosted demo&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt; via &lt;strong&gt;Google AI Studio&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;So anyone can try it without installing anything&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One environment variable switches between them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Next.js UI ──► /api/analyze  (streams one paragraph at a time)
                 │
                 ▼
          Mastra tutorAgent ──► Gemma 4  (structured output, Zod schema)
                 │
                 ▼
          guard.ts  ← the "never rewrite" rule, enforced in code
                 │
                 ▼
          + rule-based British spelling  →  margin notes

Reference tab ──► Mastra workflow:
          extract (Gemma) → match citations (code) → verify (SerpApi Google Scholar)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  1. Teaching Gemma to annotate instead of rewrite
&lt;/h3&gt;

&lt;p&gt;The tutor is a &lt;a href="https://mastra.ai" rel="noopener noreferrer"&gt;Mastra&lt;/a&gt; agent with a system prompt written like a brief for a university writing-centre tutor. It describes twelve habits, each pairing a UK convention with the Mandarin pattern behind it, and gives Gemma a checklist: check every comma, every &lt;em&gt;"As for…"&lt;/em&gt;, every bare countable noun.&lt;/p&gt;

&lt;p&gt;Gemma returns structured JSON validated with Zod. The schema has &lt;strong&gt;no field for a rewritten paragraph&lt;/strong&gt;. The only text Gemma may propose is an optional &lt;code&gt;nudge&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Not trusting the prompt
&lt;/h3&gt;

&lt;p&gt;Prompts are requests, not guarantees. &lt;code&gt;guard.ts&lt;/code&gt; checks every note before Joy sees it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The highlighted span must exist in her text&lt;/strong&gt; (tolerating curly quotes and spacing). If Gemma "quotes" something she never wrote, the note is dropped.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A nudge may change at most &lt;code&gt;max(4, 30%)&lt;/code&gt; of the span's words&lt;/strong&gt;, measured by word-level edit distance. Anything bigger is stripped back to a hint, and the card says &lt;em&gt;"Try this one yourself."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spans that cross a sentence boundary never get a nudge.&lt;/strong&gt; Restructuring is the student's job.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;nudgeAllowed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nudge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;nudge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;nudge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;words&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;crossesSentence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;wordEditDistance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nudge&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;words&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Across my evaluation runs, Gemma proposed 89 nudges and the guard turned 8 of them back into hints. Most came from the smallest model, which is exactly where you want the safety net.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Rules for what rules do best
&lt;/h3&gt;

&lt;p&gt;The small model was unreliable at spotting American spellings, so I stopped asking it. A word list catches &lt;em&gt;analyze → analyse&lt;/em&gt; and &lt;em&gt;behavior → behaviour&lt;/em&gt; every time, and those notes merge with Gemma's. Gemma handles the judgement; the rules handle the lookups.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Checking references with SerpApi
&lt;/h3&gt;

&lt;p&gt;Fabricated or garbled references are a growing problem, so the reference tab runs a three-step Mastra workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Gemma extracts&lt;/strong&gt; each entry (authors, year, title) and offers Harvard formatting &lt;em&gt;hints&lt;/em&gt;, never a corrected entry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plain code matches&lt;/strong&gt; in-text citations like &lt;code&gt;(Hall, 1980)&lt;/code&gt; against the list: cited but missing, or listed but never cited.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SerpApi's Google Scholar engine&lt;/strong&gt; looks up every title: ✅ found, ≈ details differ, or ❓ couldn't find it, so check it exists.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Two real-world snags made it better. Scholar often drops subtitles (&lt;em&gt;"Understanding media"&lt;/em&gt; for &lt;em&gt;Understanding Media: The Extensions of Man&lt;/em&gt;), and its top hit is sometimes a &lt;strong&gt;book review&lt;/strong&gt; rather than the book. Pīzhù compares main titles, searches with Scholar's &lt;code&gt;author:&lt;/code&gt; operator first, and accepts a one-year drift for reprints. Only titles and first authors are sent, never essay text.&lt;/p&gt;
&lt;h3&gt;
  
  
  5. Designed for Joy, not for a generic user
&lt;/h3&gt;

&lt;p&gt;This is where I spent the second half of the weekend, because a tool you feel judged by is a tool you stop opening.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mòmo 墨墨, the ink panda.&lt;/strong&gt; Black and white is literally 墨 ink on paper. Pandas are loved in both mainland China and Taiwan, and a gentle mascot takes the sting out of being corrected. Mòmo reads with you, sips bubble tea, cheers when you fix things, and presses a 好 seal when you finish. A reduplicated name like 墨墨 feels affectionate, the way 团团圆圆 does.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A bubble-tea palette.&lt;/strong&gt; Taro purple, milk white, strawberry for must-fix, mango for worth-fixing, matcha for all good. Red is the colour of luck and celebration in Chinese culture, so errors are a soft strawberry, never alarm red.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feedback that protects 面子 (face).&lt;/strong&gt; Notes are private, never graded, and called &lt;em&gt;habits&lt;/em&gt;. The "Marker's eye" summary under each paragraph uses UK marking dimensions (argument, structure, language, referencing) and never gives a mark.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;集章, collecting stamps.&lt;/strong&gt; Anyone who grew up with 7-Eleven point cards or station stamp books knows the pull. Work through three notes of a habit and you earn its stamp.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handwriting-style Chinese.&lt;/strong&gt; Explanations are set in 霞鹜文楷 (LXGW WenKai), an open-source kai typeface many Chinese and Taiwanese students already love, so they read like a teacher's note.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The interface in 简体 and 繁體&lt;/strong&gt;, with explanations in English, Chinese or both.&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%2Fk0bkhnrijzpof51dqx6u.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%2Fk0bkhnrijzpof51dqx6u.png" alt="The stamp book" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;This project only makes sense with open models.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Privacy and academic integrity.&lt;/strong&gt; Pasting unsubmitted coursework into a third-party chatbot means handing it to a server you do not control, and universities increasingly tell students to be careful with exactly that. With Gemma in Ollama, Joy's drafts stay on her laptop, and the app says so in plain words: &lt;em&gt;🔒 Local. Your essay stays on this laptop.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Control over behaviour.&lt;/strong&gt; Closed chat products are built to produce the answer. I needed the opposite: a model that points and explains but does not fix. With open weights inside my own pipeline, I could enforce that rule in code instead of hoping a prompt holds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Being able to swap models, and measure it.&lt;/strong&gt; I wrote fifteen test paragraphs seeded with known habits, plus two clean ones to catch over-flagging, and ran the same pipeline on three sizes of Gemma:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model (where it runs)&lt;/th&gt;
&lt;th&gt;Recall on seeded habits&lt;/th&gt;
&lt;th&gt;Must-fix notes on clean paragraphs&lt;/th&gt;
&lt;th&gt;Seconds per paragraph&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 E4B (laptop, 16 GB)&lt;/td&gt;
&lt;td&gt;84.2%&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;12.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 12B (laptop, 16 GB)&lt;/td&gt;
&lt;td&gt;94.7%&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;34.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma 4 26B-A4B (AI Studio)&lt;/td&gt;
&lt;td&gt;89.5%&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;25.4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Joy can choose her trade-off: E4B for quick checks while drafting, 12B before she submits. Tuning the hosted model taught me something too: Gemma 4 "thinks" at length by default, and one paragraph took &lt;strong&gt;335 seconds&lt;/strong&gt;. Setting the thinking level to &lt;code&gt;minimal&lt;/code&gt; brought it to about &lt;strong&gt;30 seconds&lt;/strong&gt; with no visible loss in quality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Cost.&lt;/strong&gt; Running locally costs nothing. International students already pay some of the highest fees in UK higher education; a tool behind a subscription is a tool many of them will not use.&lt;/p&gt;
&lt;h2&gt;
  
  
  Handing it to Joy
&lt;/h2&gt;

&lt;p&gt;I sent Joy the link on WeChat with a slightly nervous &lt;em&gt;"i made this app for u"&lt;/em&gt;. She didn't test it on my sample essay. She tested it on what she is actually writing right now, her dissertation, and later sent back a review I could not have scripted.&lt;/p&gt;

&lt;p&gt;What worked for her:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The general feeling of this app: it's very useful, especially for our module assignments. The Chinese explanation is easier to understand than the criteria written in our module 😂&lt;/p&gt;

&lt;p&gt;Another advantage of it is that it explains why I should correct my sentence. As grammarly could only give me a red label but sometimes I don't know that's the problem and how to fix it. The explanation really helps me to understand how to write properly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That second message is the reason Pīzhù exists, put better than I managed: a red underline tells you &lt;em&gt;that&lt;/em&gt; something is wrong, and Joy needed to know &lt;em&gt;why&lt;/em&gt;. It is the same gap as "It's just bad English".&lt;/p&gt;

&lt;p&gt;She was just as honest about what didn't work:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As my dissertation is a long paper, when I tried to ask advice from momo, I have to send my paper separately, even need to split each chapter to 2-3 parts. Thus, momo cannot get the full understanding of my argument. If the app could do longer articles, it would be great!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(She calls it "momo". That made my day.)&lt;/p&gt;

&lt;p&gt;And she had two requests:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Another advice I would like to share it that, if it could help you analyse the assignment requirements or criteria, and have similarity detection like turntin, it will help students understand how to do their assignments and worry less before submitting.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  What I shipped the same evening
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Longer papers.&lt;/strong&gt; The hosted demo now accepts 6,000 words instead of 1,500. The cap only exists because the demo runs on free tiers; running Pīzhù locally has no limit at all.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A whole-paper overview.&lt;/strong&gt; Mòmo now reads the entire paper in one pass, alongside the line-by-line notes, and tells you what it thinks your argument is, what works, and the three most important whole-paper fixes. If Mòmo's summary of your argument isn't what you meant, that is the most useful feedback of all.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your assignment brief, explained.&lt;/strong&gt; Paste the task and the marking criteria, and Mòmo restates each criterion in plain English and Chinese, then marks it met, partly or missing against your paper. Joy's line about the Chinese being easier than her module criteria was the whole spec.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It travels.&lt;/strong&gt; The overview sits at the top of the Word export, above her own unchanged text.&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%2F882zunbd0e96zkwba039.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%2F882zunbd0e96zkwba039.png" alt="Whole-paper overview checked against an assignment brief" width="800" height="670"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Turnitin-style similarity checking is the one request I'm deliberately not building.&lt;/strong&gt; It only works by comparing your essay against a database of other people's papers, which means uploading and keeping your writing: exactly what Pīzhù is designed never to do. It does the honest half of that job instead: it flags claims that need a citation and checks that every reference actually exists.&lt;/p&gt;

&lt;p&gt;Her last message: &lt;em&gt;"No problem, it's already a brilliant app!"&lt;/em&gt; I've promised her half the prize if it wins.&lt;/p&gt;
&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;I built Pīzhù with Claude Code over the weekend, from reading the challenge rules, to the PRD, to debugging the reference matcher and the margin-note layout:&lt;/p&gt;


&lt;div class="ltag-agent-session"&gt;
  &lt;div class="agent-session-header"&gt;
    
    &lt;span class="agent-session-tool-icon-badge" title="Claude Code"&gt;
&lt;/span&gt;
    &lt;span class="agent-session-title"&gt;Building Pīzhù 批注 with Claude Code: a margin-note writing tutor on Gemma 4&lt;/span&gt;
  &lt;/div&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Today's Hacktoberfest challenge is Build for a Friend. My idea: a tool that helps Mandarin-native students write better academic English (EAP). Lots of my friends from China and Taiwan lose marks and confidence when they're so smart. I do NOT want the model to rewrite their work, just tell them where the English is off and why. Focus on UK and Irish academic writing, UI relevant to Mandarin speakers, with a Chinese UI option. Plan it against the submission template and partners, build a PRD, and ask me questions.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Read the challenge rules (deadline 5 Oct 06:59 UTC; writing quality weighted most) and checked partner tech. Gemma 4 is open-weight under Apache 2.0, multilingual and runs locally, so it is the core model; Tinker can't fine-tune Gemma, so I left it out. Asked four questions: the friend, where Gemma runs, partner categories, and stack.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-getchallenges"&gt;get_challenges&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;DEV challenges&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;DEV challenges&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Hacktoberfest Weekend Challenge: Build for a Friend, 2-5 Oct&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-websearch"&gt;WebSearch&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;latest Gemma open model release 2026 Ollama sizes&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;latest Gemma open model release 2026 Ollama sizes&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Gemma 4: E2B, E4B, 12B, 26B A4B, 31B&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Named friend who will test (Joy, Global Mass Communication, Simplified Chinese). Hybrid inference. Gemma with SerpApi. TypeScript: Next.js + Mastra. 16 GB RAM.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Wrote the PRD: 'annotate, don't rewrite'. Built a Mastra tutor agent with a Zod schema that has no field for a rewritten paragraph, plus guard.ts: every span must exist verbatim in the student's text, and any nudge changing more than max(4, 30%) of the words is stripped back to a hint. First local run on gemma4:e4b: six notes on paragraph 1 with natural Chinese explanations, one oversized fix stripped by the guard.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Smoke-test paragraph analysis with local Gemma&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Smoke-test paragraph analysis with local Gemma&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;6 annotations, nudgesStripped: 1&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Write and run unit tests for guard and citations&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Write and run unit tests for guard and citations&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;14 passed&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Wrote 15 hand-made test paragraphs seeded with Mandarin-L1 habits plus 2 clean ones. E4B recall 73.7%, weakest on American spellings and missing citations. Added a deterministic US→UK spelling list (rules for lookups, Gemma for judgement) and a sharper checklist: recall rose to 84.2%. 12B: 94.7% with zero false must-fix notes.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Run eval fixtures on Gemma 4 E4B&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Run eval fixtures on Gemma 4 E4B&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;recall 0.737&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Eval Gemma 12B then re-eval E4B&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Eval Gemma 12B then re-eval E4B&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;12B 0.947, E4B 0.842&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Hosted path: one paragraph took 335 s on Gemma 4 31B because it thinks at length. Probed the API: 31B was returning 500s, and 26B-A4B with thinkingLevel 'minimal' answered in ~7 s. Switched the hosted demo to 26B-A4B; paragraphs now take ~30 s with no visible quality loss (89.5% recall).&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Compare latency of Gemma 26B MoE vs 31B&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Compare latency of Gemma 26B MoE vs 31B&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;26b-a4b minimal: 6.7s; default: 28.4s&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Reference checker as a Mastra workflow: Gemma extracts entries, plain code matches in-text citations, SerpApi Google Scholar verifies. Two real snags fixed: Scholar drops subtitles ('Understanding media'), and its top hit is sometimes a book review. Compare main titles, search with author: first, allow ±1 year for reprints. Result: three real books found, the invented one flagged.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Run reference check twice for stability&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Run reference check twice for stability&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;found, found, found, not_found&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Deploy failed (Render: EROFS read-only file system, unlink /usr/bin/pnpm).&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;&lt;code&gt;corepack enable&lt;/code&gt; tries to write a pnpm link into Render's read-only /usr/bin. Switched render.yaml to &lt;code&gt;corepack pnpm install/build/start&lt;/code&gt;, verified a local production build, pushed. It went live at pizhu.onrender.com.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Load the design skills we used for my website and enhance the UI/UX and colours. It's for a Chinese audience, so maybe a dragon or panda avatar, chosen by the consumer psychology of Chinese and Taiwanese students.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Recommended 墨墨 Mòmo, an ink panda: black and white is literally ink on paper, pandas are loved in both the PRC and Taiwan, and a dragon reads as authority, intimidating for something that corrects you. Design principles: protect 面子 (private, never graded, 'habits' not errors), 萌 mascot culture, 集章 stamp collecting, and 霞鹜文楷 for Chinese so notes read like a teacher's handwriting.&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;It's still lackluster, and the palette looks like the Claude colour scheme. Can we think of something much more?&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Offered four palette worlds; you chose 珍奶 taro &amp;amp; boba, plus all four signature features. Built: a live demo hero (sentence types in, underlines draw, notes pop in); true margin notes positioned beside each line with an ink connector; lesson mode with tapioca-pearl progress and a share card; and a Mòmo companion dock that narrates, cheers and stamps 好.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-write"&gt;Write&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;src/components/MarginPaper.tsx&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;MarginPaper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tsx&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-write"&gt;Write&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;src/components/LessonMode.tsx&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;LessonMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tsx&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Add a light/dark toggle. Bug: the line from words to note stays while I edit a paragraph. The hero demo grows and shrinks so the page jumps. Export my habits gives JSON, improve it. Credit the challenge and me in the footer. Make this a great finished product that would make us win!&lt;/p&gt;

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

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Fixed all five, each verified in the browser: the toggle applies before first paint; editing hides that paragraph's notes and connector; the demo card reserves its final size (height constant across a full loop); a habit-report image and 集章 stamp book replace raw JSON; and the footer has credits. Extras: Word export with notes as real Word comments, friendly errors with retry, draft autosave, WCAG contrast fixes, OG card. A headless-Chrome script ran the whole flow on the live site and captured the README screenshots.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Capture production screenshots and demo GIF&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Capture production screenshots and demo GIF&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;analysis done in 84.7s; all scenes captured&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-bash"&gt;Bash&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;Final checks&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ Final checks&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;lint clean, 19 tests passed&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class="agent-session-footer"&gt;
    &lt;span class="agent-session-meta"&gt;
        15 of 16 messages
          · some content was hidden by the author
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma:&lt;/strong&gt; Gemma 4 is the only model, running locally (E4B and 12B via Ollama) and hosted (26B-A4B via AI Studio), with a measured size comparison and a guardrail built around its structured output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of SerpApi:&lt;/strong&gt; the Google Scholar engine powers the reference checker that catches sources which may not exist, using the &lt;code&gt;author:&lt;/code&gt; operator to find the work itself rather than reviews of it.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Built with AI assistance (Claude Code). I reviewed, tested and edited everything, and the evaluation numbers come from real runs of the code in the repo.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>hf26challenge</category>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>Any Feedbacks on this?</title>
      <dc:creator>Muhammad Murtuza Hussain</dc:creator>
      <pubDate>Fri, 02 Oct 2026 12:38:52 +0000</pubDate>
      <link>https://dev.to/muhammadmurtuzahussain/any-feedbacks-on-this-523c</link>
      <guid>https://dev.to/muhammadmurtuzahussain/any-feedbacks-on-this-523c</guid>
      <description>&lt;p&gt;&lt;a href="https://pizhu.onrender.com/" rel="noopener noreferrer"&gt;https://pizhu.onrender.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have made this for the weekend 1 challenge, looking for UI/UX improvement. &lt;/p&gt;

&lt;h2&gt;
  
  
  &amp;gt; Recommend me skills below!
&lt;/h2&gt;

</description>
      <category>sideprojects</category>
      <category>hacktoberfest</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Cool social media</title>
      <dc:creator>Muhammad Murtuza Hussain</dc:creator>
      <pubDate>Thu, 01 Oct 2026 12:53:27 +0000</pubDate>
      <link>https://dev.to/muhammadmurtuzahussain/cool-social-media-2og2</link>
      <guid>https://dev.to/muhammadmurtuzahussain/cool-social-media-2og2</guid>
      <description>&lt;p&gt;How do you make friends here?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
