<?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: Dosunmu Hassan</title>
    <description>The latest articles on DEV Community by Dosunmu Hassan (@dosunmu_hassan_46f2ac141d).</description>
    <link>https://dev.to/dosunmu_hassan_46f2ac141d</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%2F4158637%2F1eaaaae3-c430-4bf7-a780-18423e903b03.png</url>
      <title>DEV Community: Dosunmu Hassan</title>
      <link>https://dev.to/dosunmu_hassan_46f2ac141d</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dosunmu_hassan_46f2ac141d"/>
    <language>en</language>
    <item>
      <title>I built a panic button that doesn't tell me anything</title>
      <dc:creator>Dosunmu Hassan</dc:creator>
      <pubDate>Sun, 04 Oct 2026 09:10:49 +0000</pubDate>
      <link>https://dev.to/dosunmu_hassan_46f2ac141d/i-built-a-panic-button-that-doesnt-tell-me-anything-published-4glf</link>
      <guid>https://dev.to/dosunmu_hassan_46f2ac141d/i-built-a-panic-button-that-doesnt-tell-me-anything-published-4glf</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;p&gt;When someone close to you is getting through an addiction, you become the monitor. You ask how it&lt;br&gt;
went. You check in. You want the number. It feels like support for about a week — and then it is&lt;br&gt;
surveillance, and the moment honesty costs something, honesty stops. Which leaves you worse off&lt;br&gt;
than when you started, because now the person you were trying to help has to manage your feelings&lt;br&gt;
on top of their own.&lt;/p&gt;

&lt;p&gt;I built this for one real person: someone close to me who is getting through this, and I'm the&lt;br&gt;
person closest to it. I'm deliberately not describing her, and not describing the specifics.&lt;br&gt;
That's her information, and a repo is permanent.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Steady&lt;/strong&gt; — one screen, three buttons, sized for a phone at 3am.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"I'm having a craving right now"&lt;/strong&gt; — an open-weight model replies with one grounding line and
one concrete thing to do in the next two minutes. No typing, no explaining, no waking anyone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"The craving has passed"&lt;/strong&gt; — it marks the moment, so surviving becomes something you remember
doing instead of something that only ever felt unsurvivable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"I slipped"&lt;/strong&gt; — private. It does not report. It helps you work out what you want to say, to
whom, and when.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the thing I actually built is an absence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The person supporting you gets a signal, never a transcript — and that part is built, not&lt;br&gt;
described.&lt;/strong&gt; She taps &lt;em&gt;"make a link for one person"&lt;/em&gt; and hands it to whoever she chooses. On his&lt;br&gt;
phone it is a different page: a state line — &lt;em&gt;"she has gone quiet for a bit"&lt;/em&gt; — and nothing else.&lt;br&gt;
No buttons, no notes, no history, no transcript to scroll.&lt;/p&gt;

&lt;p&gt;The only thing the server ever holds per link is &lt;strong&gt;the time of her last check-in.&lt;/strong&gt; Not her words,&lt;br&gt;
not which button she pressed, not a count of anything. I checked what a supporter's phone actually&lt;br&gt;
receives: two fields, &lt;code&gt;signal&lt;/code&gt; and &lt;code&gt;minutes&lt;/code&gt;. There is no third field, and there is nowhere to put&lt;br&gt;
one without deleting this paragraph.&lt;/p&gt;

&lt;p&gt;And &lt;strong&gt;the slip button deliberately never reports at all&lt;/strong&gt; — not even a timestamp. If it did, then&lt;br&gt;
"checked in" and "gone quiet" would start to &lt;em&gt;mean&lt;/em&gt; something, and the moment a supporter can infer&lt;br&gt;
a slip from timing, the honest button is dead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Steady keeps no session log.&lt;/strong&gt; Not "we don't look at it" — there is nothing to look at. No&lt;br&gt;
history, no streaks, no record of a slip, and no copy of anything she typed. The single thing&lt;br&gt;
stored anywhere is the time of her last check-in, and it exists only so that someone who loves her&lt;br&gt;
can tell she came back. A tool that recorded more would be used dishonestly within a week, because&lt;br&gt;
that is what people do when the record is a threat.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And the uncomfortable part, plainly:&lt;/strong&gt; on the hosted demo, what she writes &lt;em&gt;is&lt;/em&gt; sent to Google's&lt;br&gt;
endpoint to be answered — it has to be, that is where the model runs. What Steady itself keeps is&lt;br&gt;
nothing. The offline path is the one where the words never leave the device at all: a GGUF through&lt;br&gt;
&lt;code&gt;llama.cpp&lt;/code&gt;, on her own hardware, with no network involved.&lt;/p&gt;

&lt;p&gt;I want to be precise about why this isn't a compromise I'm grudgingly making. The whole value of&lt;br&gt;
the tool &lt;em&gt;to me&lt;/em&gt; is the refusal. If she doesn't trust the button, she won't press it, and the&lt;br&gt;
button is worth nothing. &lt;strong&gt;Privacy wasn't the ethical tax on this project. It's the mechanism.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Live at &lt;strong&gt;&lt;a href="https://steady-21e1.onrender.com" rel="noopener noreferrer"&gt;https://steady-21e1.onrender.com&lt;/a&gt;&lt;/strong&gt; — open it on a phone. Type something, or nothing, and&lt;br&gt;
tap a button.&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%2Fk9kzttbwadmrm5khi9v7.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%2Fk9kzttbwadmrm5khi9v7.png" alt="Steady answering with her own words" width="800" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That screenshot is a real reply, word for word:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"That shop brought on a powerful wave. Try focusing on your feet on the ground for a moment.&lt;br&gt;
Can you name three things you see around you right now?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;— what he sees right now: &lt;em&gt;"she checked in recently."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That second line is the entire design on one screen. She gets the help. He gets a signal with no&lt;br&gt;
content in it. Nobody had to decide whether to be honest.&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%2Fxystj3k4nrt9dt3kykkr.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%2Fxystj3k4nrt9dt3kykkr.png" alt="The supporter's own page: a state line, a time, and no buttons" width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is the whole of what he ever sees. Open the link on a second phone and you can watch it&lt;br&gt;
change when she taps a button — it is a different page, for a different person, serving a&lt;br&gt;
different payload. Nothing about that screen is a mockup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Honest performance note:&lt;/strong&gt; a reply typically takes &lt;strong&gt;30–60 seconds&lt;/strong&gt;, because Gemma 4 reasons before it&lt;br&gt;
answers. The service is always-on, so there is no cold start, and the model is warmed at boot —&lt;br&gt;
but that latency is still the model's, not the box's, and it is too slow to be a real 3am button. Which is exactly why the path&lt;br&gt;
below runs on your own device instead.&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/Zaygal" rel="noopener noreferrer"&gt;
        Zaygal
      &lt;/a&gt; / &lt;a href="https://github.com/Zaygal/steady" rel="noopener noreferrer"&gt;
        steady
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Private one-tap support companion for two people in recovery. Build for a Friend - Hacktoberfest Weekend Challenge.
    &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;Steady&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A private, one-tap support companion for two people who are getting through something together.&lt;/p&gt;
&lt;p&gt;Built for &lt;strong&gt;one real person&lt;/strong&gt; — someone close to me — as an entry in the
&lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01" rel="nofollow"&gt;Hacktoberfest Weekend Challenge&lt;/a&gt;
theme &lt;em&gt;"Build for a Friend."&lt;/em&gt; Her name and anything identifying her are deliberately not in
this repository. That is her information to publish, not mine.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;The problem this actually solves&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;When two people are getting through the same thing, the partner becomes the monitor. That
feels like help for about a week. After that it is surveillance, and once honesty is punished
the person stops reporting the truth — which is the one thing the partner needed.&lt;/p&gt;
&lt;p&gt;So Steady inverts it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In the craving moment&lt;/strong&gt;, the person taps one button and gets immediate, private help
No typing, no explaining, no waking anyone at 3am.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The partner gets a signal, never a transcript.&lt;/strong&gt; "She's gone…&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/Zaygal/steady" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/Zaygal/steady" rel="noopener noreferrer"&gt;https://github.com/Zaygal/steady&lt;/a&gt;&lt;/strong&gt; — MIT, and deliberately small. &lt;code&gt;agent/steady.py&lt;/code&gt; is the whole&lt;br&gt;
policy and the model calls. &lt;code&gt;app/server.py&lt;/code&gt; is a stdlib HTTP server with &lt;strong&gt;no third-party&lt;br&gt;
dependencies at all&lt;/strong&gt; — a support tool for someone in crisis should have the smallest possible&lt;br&gt;
attack surface. &lt;code&gt;app/index.html&lt;/code&gt; is the entire front end. &lt;code&gt;NOT-A-TREATMENT.md&lt;/code&gt; is a thing I&lt;br&gt;
shouldn't have to write, and did.&lt;/p&gt;

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

&lt;p&gt;Both model paths are open-weight, and &lt;strong&gt;there is no proprietary-model path in the code&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gemma&lt;/strong&gt;, served through Google AI Studio — &lt;code&gt;gemma-4-31b-it&lt;/code&gt; answering on the live site.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A GGUF served locally by &lt;code&gt;llama.cpp&lt;/code&gt;&lt;/strong&gt; — fully offline, no network at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the model does not run on anyone's laptop. It runs in &lt;strong&gt;GitHub Actions&lt;/strong&gt;, on a clean public&lt;br&gt;
runner, from a workflow in the repo. The runner downloads the official GGUF, checksums it, runs the&lt;br&gt;
support policy and uploads the reply as an artifact. &lt;strong&gt;No API key, nothing installed on the phone,&lt;br&gt;
and anyone can click the workflow and reproduce it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The policy lives in plain sight in &lt;code&gt;agent/steady.py&lt;/code&gt;: no diagnosis, no dosages, no clinical claims,&lt;br&gt;
replies under 60 words, at most one question, and an explicit rule never to moralise about a slip.&lt;br&gt;
Ask it for help with no model reachable and it does not improvise — it says so and hands over a&lt;br&gt;
crisis pointer. I'd rather it be visibly broken than confidently wrong to someone mid-craving.&lt;/p&gt;

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

&lt;p&gt;I could have built this on a proprietary model behind an API key. I didn't, and the reasons are&lt;br&gt;
specific to this problem rather than general praise for open source.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A tool about addiction has to be inspectable.&lt;/strong&gt; Someone is being asked to trust it in the worst&lt;br&gt;
hour of their week, so "nothing is kept" cannot be a marketing line — it has to be checkable. The&lt;br&gt;
entire policy is thirty lines in &lt;code&gt;agent/steady.py&lt;/code&gt;. The model is a public GGUF. The runtime is&lt;br&gt;
&lt;code&gt;llama.cpp&lt;/code&gt;. The workflow that runs it is in the repo. You can read all of it, and none of it&lt;br&gt;
required my permission.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Free matters more here than anywhere.&lt;/strong&gt; A person in a bad week is not going to add a subscription&lt;br&gt;
to get help at 3am. Open weights mean they can run this on hardware they already own, indefinitely,&lt;br&gt;
without a billing relationship deciding whether they deserve an answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Swappable means it outlives me.&lt;/strong&gt; The model is one environment variable. When a better small model&lt;br&gt;
lands — and it will — nobody needs my release cycle, or my continued existence, to put it in. That's&lt;br&gt;
the difference between an open project and a product I own.&lt;/p&gt;

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

&lt;p&gt;DevRelay sessions are optional, so here's the equivalent: &lt;strong&gt;every run of the agent is public in the&lt;br&gt;
&lt;a href="https://github.com/Zaygal/steady/actions" rel="noopener noreferrer"&gt;Actions tab&lt;/a&gt;&lt;/strong&gt;, including the four that went wrong. That&lt;br&gt;
tab is the actual build log, and it's more candid than a summary would be.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Best Use of Render — featured.&lt;/strong&gt; The front end is live on Render at&lt;br&gt;
&lt;strong&gt;&lt;a href="https://steady-21e1.onrender.com" rel="noopener noreferrer"&gt;https://steady-21e1.onrender.com&lt;/a&gt;&lt;/strong&gt;. The criterion is &lt;em&gt;"host an agent's front end,"&lt;/em&gt; and you can&lt;br&gt;
open it on a phone right now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best Use of Gemma — featured.&lt;/strong&gt; Gemma is the model, open-weight, with no proprietary path&lt;br&gt;
anywhere. The app asks the API which open-weight Gemma ids the key can actually reach instead of&lt;br&gt;
trusting a hardcoded id — which is how I found that this key serves &lt;strong&gt;Gemma 4&lt;/strong&gt;, not the Gemma 3&lt;br&gt;
ids I had assumed, all of which returned 404.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best Use of GitHub Copilot — partner.&lt;/strong&gt; The qualifying path is &lt;em&gt;"automate your project with&lt;br&gt;
GitHub Actions,"&lt;/em&gt; and for Steady that isn't a garnish: the entire model runtime &lt;strong&gt;is&lt;/strong&gt; a GitHub&lt;br&gt;
Actions workflow. Nothing runs on anyone's machine, and every run is public.&lt;/p&gt;

&lt;p&gt;There's one family of categories Steady is built to lose — the data-layer ones (MongoDB Atlas,&lt;br&gt;
Tiger Data). &lt;strong&gt;Not keeping the data is the product.&lt;/strong&gt; A version that stored every craving and every&lt;br&gt;
slip so it could win a storage prize would be the exact thing it exists to avoid.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Got Wrong, in Public
&lt;/h2&gt;

&lt;p&gt;I built the model path four times, and the last failure was the most useful one.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gemma-3-270m-it&lt;/code&gt; — the smallest Gemma — &lt;strong&gt;restated my instructions back at me&lt;/strong&gt; instead of&lt;br&gt;
answering: &lt;em&gt;"Okay, I understand. I will adhere to the rules and provide a concise, helpful&lt;br&gt;
response."&lt;/em&gt; Useless to someone mid-craving. I moved to 1B, then 4B.&lt;/p&gt;

&lt;p&gt;The 4B was warm and stayed inside the policy, &lt;strong&gt;and it ignored her completely.&lt;/strong&gt; I passed it&lt;br&gt;
&lt;em&gt;"walked past the shop and it hit hard"&lt;/em&gt; and it never once mentioned the shop — every run it offered&lt;br&gt;
breathing. I added a rule that ignoring what she said counts as a failure, and found a real&lt;br&gt;
interface bug behind it: &lt;strong&gt;I had been burying her words inside a paragraph of instructions addressed&lt;br&gt;
to the agent.&lt;/strong&gt; Her sentence was a footnote in my message. I fixed that — her words are now the&lt;br&gt;
user turn and nothing else — and &lt;strong&gt;the behaviour still didn't change.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's when I stopped blaming the prompt and admitted it was capacity. A 4B model doesn't have the&lt;br&gt;
room to hold the policy, her sentence, and a reply that uses both. So I moved to 12B:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"That walk brought it on strong. Feel your feet on the ground. Can you take three slow, deep&lt;br&gt;
breaths now?"&lt;/em&gt; — using &lt;strong&gt;her&lt;/strong&gt; word, from &lt;strong&gt;her&lt;/strong&gt; sentence.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And then the bigger model did something worse. On its first run, given the same note, it said&lt;br&gt;
&lt;em&gt;"That smell is strong right now."&lt;/em&gt; &lt;strong&gt;There was no smell.&lt;/strong&gt; It invented a sensory detail she never&lt;br&gt;
gave and handed it to someone in distress as fact. So I added a rule that it may use only what she&lt;br&gt;
actually said, and it stopped.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then I tried to fix it with a fine-tune, and that failed too.&lt;/strong&gt; I trained a LoRA adapter on&lt;br&gt;
1,800 synthetic examples and compared it against the same model untuned, on a held-out set, against&lt;br&gt;
one metric I fixed &lt;em&gt;before&lt;/em&gt; running it: does the reply reuse a content word from the person's note?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;baseline &lt;strong&gt;68.3%&lt;/strong&gt; → fine-tuned &lt;strong&gt;60.0%&lt;/strong&gt;, for $1.11&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It made it worse. So there is no "Best Use of Tinker" claim anywhere in this post — I'm not going to&lt;br&gt;
go shopping for a metric that flatters my own adapter. What the samples actually show is that my&lt;br&gt;
&lt;em&gt;metric&lt;/em&gt; was the weak part: the baseline learned to parrot her sentence straight back, which&lt;br&gt;
guarantees word overlap and reads like a machine, while the fine-tuned model used the exact noun the&lt;br&gt;
baseline had paraphrased away. Two real lessons: the defect I'd documented was the &lt;strong&gt;4B's capacity&lt;br&gt;
limit, not a universal problem&lt;/strong&gt; — a 30B model already used the detail 68% of the time — and my&lt;br&gt;
synthetic data was too mechanical to beat that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every step up the ladder bought capability and sold a little accuracy — and accuracy is the only&lt;br&gt;
thing that matters here.&lt;/strong&gt; All four runs are public. You can watch me get it wrong, watch the model&lt;br&gt;
invent something, and watch me take it back out.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Steady is not treatment.&lt;/strong&gt; Not therapy, not medical advice, not a crisis service. It cannot detect&lt;br&gt;
anything or measure anything, and it doesn't replace a professional. If someone is in immediate&lt;br&gt;
danger they should contact local emergency services, or find a verified crisis line for their&lt;br&gt;
country at findahelpline.com.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The supporter's view is pull, not push&lt;/strong&gt; — he opens the link to see it. Nothing is texted or&lt;br&gt;
emailed to him, and no notification fires. That is the honest edge of what I built: the signal&lt;br&gt;
is real and delivered, but he has to look.&lt;/p&gt;

&lt;p&gt;The instance is always-on, so there is no cold start. The workflow is the reproducible proof that&lt;br&gt;
the open-weight path works; the phone UI is what someone would actually press, pointed at a model&lt;br&gt;
they host themselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd Say to Anyone Building for Someone Real
&lt;/h2&gt;

&lt;p&gt;The constraint they give you &lt;em&gt;is&lt;/em&gt; the product. Mine was one sentence — &lt;em&gt;"don't make me report to&lt;br&gt;
you"&lt;/em&gt; — and the whole design fell out of it. Everything I was tempted to add (history, streaks, a&lt;br&gt;
dashboard for the supporter) would have quietly turned it back into the thing it exists to avoid.&lt;/p&gt;

&lt;p&gt;Not every feature you can build is a feature you should ship to someone you love.&lt;/p&gt;

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