<?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: Ry</title>
    <description>The latest articles on DEV Community by Ry (@maryamrahat).</description>
    <link>https://dev.to/maryamrahat</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%2F4155351%2F0508e3d7-2e49-4169-811b-930fb1b91e0f.jpg</url>
      <title>DEV Community: Ry</title>
      <link>https://dev.to/maryamrahat</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/maryamrahat"/>
    <language>en</language>
    <item>
      <title>Bringing in the OutsideQuest</title>
      <dc:creator>Ry</dc:creator>
      <pubDate>Sat, 10 Oct 2026 18:33:00 +0000</pubDate>
      <link>https://dev.to/maryamrahat/bringing-in-the-outsidequest-1jag</link>
      <guid>https://dev.to/maryamrahat/bringing-in-the-outsidequest-1jag</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05"&gt;Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;OutsideQuest&lt;/strong&gt; is a one-button, 70s-arcade-style desktop game that pushes you away from the screen and into the real world.&lt;/p&gt;

&lt;p&gt;Press NEW MISSION, and it checks the live weather outside; then a local LLM writes a short, safe photo mission to suit the conditions, like "Find three different shades of green" on a clear day or "Capture a puddle reflection" when it's raining. You go outside, complete it, and press SNAP PHOTO. A local vision model looks at your webcam shot and replies with PASS or FAIL plus a witty reaction to what it actually sees and the weather around you.&lt;/p&gt;

&lt;p&gt;Win, and your daily streak climbs. Miss a day, and it resets, which turns "I should go for a walk" into "I can't break the streak."&lt;/p&gt;

&lt;p&gt;It's for anyone who spends too much time at a desk: students, developers, remote workers, or anyone who needs a small, playful reason to step outside.&lt;/p&gt;

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

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/ZkbWXhY-MS0" width="710" height="399"&gt;
  &lt;/iframe&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%2Fwd8ouh08c53l1c36prep.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%2Fwd8ouh08c53l1c36prep.png" alt=" " width="800" height="450"&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%2F8j1v78hzkzg3xujzukqf.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%2F8j1v78hzkzg3xujzukqf.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

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


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/maryam-rahat" rel="noopener noreferrer"&gt;
        maryam-rahat
      &lt;/a&gt; / &lt;a href="https://github.com/maryam-rahat/OutsideQuest" rel="noopener noreferrer"&gt;
        OutsideQuest
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      a one-button outdoor game built with Python, tkinter and Ollama. checks your live local weather, has a local LLM generate a safe photo mission that suits the conditions, then uses a vision model to judge the photo from your webcam. PASS or FAIL with a witty reaction to what it sees, and a daily streak counter tracks your consecutive-day wins.
    &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;OutsideQuest&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A 70s-arcade-style desktop game that sends you outside on photo missions and has a local AI judge your snap.&lt;/p&gt;
&lt;p&gt;Press one button, get a weather-aware mission, go complete it, snap a photo, and watch a vision model react to the real world. Build a daily streak.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Missions generated by a local LLM, tuned to your live weather&lt;/li&gt;
&lt;li&gt;Webcam photo judged by a local vision model with a PASS or FAIL and a witty reaction&lt;/li&gt;
&lt;li&gt;Persistent daily streak and best score&lt;/li&gt;
&lt;li&gt;Retro CRT UI: amber and phosphor-green text, Atari-style stripes, typewriter output, blinking &lt;code&gt;INSERT COIN&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Resizable window with scaling fonts, fullscreen on &lt;code&gt;F11&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Stack&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Python, tkinter, OpenCV, Ollama, Open-Meteo&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Requirements&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Python 3.9+&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ollama.com" rel="nofollow noopener noreferrer"&gt;Ollama&lt;/a&gt; running locally&lt;/li&gt;
&lt;li&gt;A webcam&lt;/li&gt;
&lt;li&gt;Internet access for the weather lookup only&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Setup&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;pip install ollama opencv-python
ollama pull llama3.2
ollama pull llava
python mission.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Controls&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;NEW MISSION&lt;/td&gt;
&lt;td&gt;Fetch weather, generate an objective&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SNAP PHOTO&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/maryam-rahat/OutsideQuest" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Run it yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;ollama opencv-python
ollama pull llama3.2
ollama pull llava
python mission.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The whole game runs on open-weight models through local inference with Ollama, so there are no API keys and no cloud calls for the AI.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mission generation:&lt;/strong&gt; &lt;code&gt;llama3.2&lt;/code&gt; gets a random theme (colors, shapes, textures, sky, tiny details) plus the current weather and returns a one-sentence mission.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Photo judging:&lt;/strong&gt; &lt;code&gt;llava&lt;/code&gt;, an open multimodal model, receives the webcam frame, the mission and the weather, and answers with PASS or FAIL and a one-line reaction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live weather:&lt;/strong&gt; approximate location from the IP, then current conditions from Open-Meteo, which needs no key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streak:&lt;/strong&gt; a small JSON file tracks consecutive-day wins and a best score.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interface:&lt;/strong&gt; tkinter with a 70s CRT look: amber and phosphor-green text, Atari-style stripes, typewriter output, and a blinking INSERT COIN. It's resizable, fonts scale with the window, and F11 goes fullscreen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsiveness:&lt;/strong&gt; model calls run in worker threads so the UI never freezes while the models think.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The core of the judging step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;judge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mission&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;capture&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Weather right now: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;weather_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ollama&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;VISION_MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mission: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;mission&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Does this photo complete the mission? Start with PASS or FAIL, then one witty sentence reacting to what you see and the weather.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;images&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;path&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;This project sends a camera frame of your surroundings to an AI every time you play. With a closed API, that photo would go to someone else's servers on every mission. With open-weight models running locally, the photo never leaves your machine. The only network calls are the weather lookup.&lt;/p&gt;

&lt;p&gt;Open models also made it practical to build:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No keys, no bills, no rate limits.&lt;/strong&gt; Anyone can clone the repo, pull two models, and play, with no signup and no per-call cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swappable parts.&lt;/strong&gt; Changing the mission writer or the judge is a one-line edit to &lt;code&gt;TEXT_MODEL&lt;/code&gt; or &lt;code&gt;VISION_MODEL&lt;/code&gt;, so users can pick a smaller model for a laptop or a stronger one for a GPU.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Works as a daily habit.&lt;/strong&gt; A streak game has to be free and always available, and local inference means it doesn't depend on a provider's pricing or uptime.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open innovation made it possible to build something that looks at your real world without handing your world to anyone.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>Hydra: Drink up, Sam!</title>
      <dc:creator>Ry</dc:creator>
      <pubDate>Sat, 03 Oct 2026 17:35:49 +0000</pubDate>
      <link>https://dev.to/maryamrahat/hydra-drink-up-sam-39bk</link>
      <guid>https://dev.to/maryamrahat/hydra-drink-up-sam-39bk</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;I built this for my friend Sam, who studies until 2 am and realises at midnight that the only thing they drank all day was a soda. Every reminder app they tried said the same thing, "Time to drink water!", and they just ignored it (like everything else).&lt;/p&gt;

&lt;p&gt;The obvious fix is another app with an account, cloud sync and a notification schedule. But a water log is a diary of someone's habits: when they wake up, when they study, when they forget to look after themselves. That is personal and doesn't need to be on a server.&lt;/p&gt;

&lt;p&gt;Hydra is a small desktop app that runs entirely on Sam's laptop. Sam sets a daily goal, logs water with &lt;strong&gt;+250 / -250&lt;/strong&gt;, and ten small hearts fill up through the day. Every hour, Sam chooses; a local open-weight model writes a reminder that sounds like a friend wrote it. It uses a tone I set, a short description of Sam, the time, and how much is left. It arrives as a Windows notification decorated with ❁✿❀ instead of emoji. The next morning it starts again from zero.&lt;/p&gt;

&lt;p&gt;The look is inspired by Olivia Rodrigo's "the cure": a pastel blue polka-dot background, a pink lace heart, nurse hair clips, a bandage, and coral script lettering. The progress bar is ten small hearts that fill with red as the day goes on. Sam likes that song, so I built the whole window around it.&lt;/p&gt;

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

&lt;p&gt;Hydra runs locally, so there is no hosted link.&lt;br&gt;
  &lt;/p&gt;
&lt;div&gt;
    &lt;iframe src="https://www.youtube.com/embed/YrDMQjO9iRU" width="315" height="560"&gt;
    &lt;/iframe&gt;
  &lt;/div&gt;


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

&lt;p&gt;&lt;em&gt;UI inspired by Olivia Rodrigo's "the cure". Not affiliated with or endorsed by her or her label.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/maryam-rahat" rel="noopener noreferrer"&gt;
        maryam-rahat
      &lt;/a&gt; / &lt;a href="https://github.com/maryam-rahat/hydra" rel="noopener noreferrer"&gt;
        hydra
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Hydra&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A local hydration buddy built for a friend. An open-weight model running on Ollama writes each reminder in her voice, based on her habits and how much she has had today. No API key, no cloud, no cost per message, and her data stays on her laptop.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Setup (Windows)&lt;/h2&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Install Ollama from ollama.com, then:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;   ollama pull llama3.2:3b
   pip install requests
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Run:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;   python hydra.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Use &lt;code&gt;pythonw hydra.py&lt;/code&gt; for no console window. Errors go to &lt;code&gt;hydra.log&lt;/code&gt;
3. On first run, &lt;code&gt;config.json&lt;/code&gt; is created. Edit &lt;code&gt;friend_name&lt;/code&gt;, &lt;code&gt;tone&lt;/code&gt; and &lt;code&gt;about_friend&lt;/code&gt; to personalize it. See &lt;code&gt;config.example.json&lt;/code&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How it works&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;A startup window asks for today's goal and how much you've had.&lt;/li&gt;
&lt;li&gt;A window with +250 / -250 buttons logs water.&lt;/li&gt;
&lt;li&gt;A background thread checks every 30 seconds and sends a Windows toast every &lt;code&gt;interval_min&lt;/code&gt; minutes, during &lt;code&gt;active_hours&lt;/code&gt;, until the goal is reached.&lt;/li&gt;
&lt;li&gt;If Ollama is down, it falls back to…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/maryam-rahat/hydra" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


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

&lt;p&gt;The core is a small open-weight model (&lt;code&gt;gemma3:4b&lt;/code&gt;) served locally by Ollama. Around it: a Python loop, a Tkinter canvas for the UI, and native Windows toasts. No API keys and nothing to sign up for.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. It started as a Chrome extension, and the reminders kept failing
&lt;/h3&gt;

&lt;p&gt;My first version was a Manifest V3 extension using &lt;code&gt;chrome.alarms&lt;/code&gt;. The alarms depended on a service worker that Chrome can stop and restart, and the reminders were unreliable. I rewrote it as a plain Python app with its own loop. That fixed the trigger problem and gave me a place to put a local model.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. A local model writes the reminder
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You write one hydration reminder for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;friend_name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;About them: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;about_friend&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tone: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tone&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Time now: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. They have had &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;consumed&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; ml of &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;goal_ml&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; ml today, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;remaining&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; ml left.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Rules: max 20 words, no emoji, no symbols, no quotes, no hashtags. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Output only the message.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ollama_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;friend_name&lt;/code&gt;, &lt;code&gt;tone&lt;/code&gt;, &lt;code&gt;about_friend&lt;/code&gt;, &lt;code&gt;model&lt;/code&gt; and &lt;code&gt;flourishes&lt;/code&gt; all live in &lt;code&gt;config.json&lt;/code&gt;. Changing what the reminders sound like is a text edit, not a code change.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The loop
&lt;/h3&gt;

&lt;p&gt;A background thread wakes every 30 seconds and sends a reminder only if all three are true:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;lo&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;hour&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;consumed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;goal_ml&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;next_due&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It must be inside &lt;code&gt;active_hours&lt;/code&gt;, under the goal, and past the interval. Water totals are saved with a date, so a new date counts as a fresh day, and nothing needs a reset button. If Ollama isn't running, a plain "X ml to go" message goes out instead, so a reminder is never lost.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Taming a small model
&lt;/h3&gt;

&lt;p&gt;I told the model "no emoji". It sometimes added them anyway. So I strip emoji and symbols from its output with a regex, then append a random flourish from my own list (&lt;code&gt;❁✿❀❁✿❀&lt;/code&gt;, &lt;code&gt;✿ ❀ ✿&lt;/code&gt;, ...). The decoration now comes from me, not from the model's mood.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. What broke along the way
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reminders unreliable:&lt;/strong&gt; &lt;code&gt;chrome.alarms&lt;/code&gt; ran inside an MV3 service worker that Chrome can stop. Fixed by moving to a Python loop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No popups on Windows 11:&lt;/strong&gt; &lt;code&gt;plyer&lt;/code&gt; notifications failed silently. Fixed with a native PowerShell toast, no extra package.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;malformed bucket chain in Tcl_DeleteHashEntry&lt;/code&gt;:&lt;/strong&gt; I was deleting canvas items inside their own click handler. Fixed by running every action through &lt;code&gt;root.after(20, ...)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model kept adding emoji:&lt;/strong&gt; small models sometimes ignore "no emoji". Fixed by stripping them with a regex and appending my own flourishes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Greeting showed the old name:&lt;/strong&gt; &lt;code&gt;config.json&lt;/code&gt; overrides the new defaults. Fixed by editing the file, since defaults only apply when it's missing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. The UI
&lt;/h3&gt;

&lt;p&gt;The theme comes from Olivia Rodrigo's "the cure" artwork. There are no UI libraries and no image files. Everything is drawn on one Tkinter canvas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The lace heart is a parametric heart curve with scalloped circles along its outline.&lt;/li&gt;
&lt;li&gt;The nurse clips, bandage and progress hearts are polygons.&lt;/li&gt;
&lt;li&gt;The polka dots are a grid of offset ovals.&lt;/li&gt;
&lt;li&gt;Text uses Segoe Script, which ships with Windows.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;The data never has to leave.&lt;/strong&gt; A water log shows when someone wakes, studies and forgets to eat or drink. With a closed API, every reminder is a request to someone else's server carrying that. With a local model, Hydra works with the Wi-Fi off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Free to run, with no secrets to leak.&lt;/strong&gt; A reminder every hour would otherwise mean a paid API and a key to protect. Here, there is no per-message cost, and I could publish the repo as it is, because there is nothing to hide in it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The personality is a text file.&lt;/strong&gt; Swapping the model is one line in &lt;code&gt;config.json&lt;/code&gt;. Making the reminders gentler, funnier or more specific to Sam means editing two sentences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where a closed model would have been better:&lt;/strong&gt; the writing. A frontier model would write funnier, more varied reminders than a 4B one, and it wouldn't need an emoji filter. I accepted clumsier messages in exchange for nothing leaving the machine.&lt;/p&gt;

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

&lt;p&gt;Built over one weekend, a chat session with Claude helped with the debugging of the Windows notification code.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Best Use of Gemma:&lt;/strong&gt; Hydra runs &lt;code&gt;gemma3:4b&lt;/code&gt; locally through Ollama. Gemma writes every reminder Sam receives, using a tone, a short description of Sam, the time, and how much water is left. It runs on Sam's laptop, so no API key is needed, and nothing leaves the machine. &lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>This is my first post</title>
      <dc:creator>Ry</dc:creator>
      <pubDate>Thu, 01 Oct 2026 17:26:34 +0000</pubDate>
      <link>https://dev.to/maryamrahat/this-is-my-first-post-2215</link>
      <guid>https://dev.to/maryamrahat/this-is-my-first-post-2215</guid>
      <description>&lt;p&gt;kinda daunting to be writing over here, but very very excited to continue my journey!! hope to meet some great peers along the way!!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>community</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
