<?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: Ishaan</title>
    <description>The latest articles on DEV Community by Ishaan (@ishaan-jindal).</description>
    <link>https://dev.to/ishaan-jindal</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%2F4085933%2F7bfd9d65-1faf-4f07-b7f6-6cefd4f36f9e.jpg</url>
      <title>DEV Community: Ishaan</title>
      <link>https://dev.to/ishaan-jindal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ishaan-jindal"/>
    <language>en</language>
    <item>
      <title>d43m0n lives in my terminal now</title>
      <dc:creator>Ishaan</dc:creator>
      <pubDate>Sat, 31 Oct 2026 17:56:48 +0000</pubDate>
      <link>https://dev.to/ishaan-jindal/d43m0n-lives-in-my-terminal-now-1pca</link>
      <guid>https://dev.to/ishaan-jindal/d43m0n-lives-in-my-terminal-now-1pca</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week4-2026-10-26"&gt;Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Somebody's been keeping notes on my shell. Every command for the last week: the successful ones, the midnight typos, the same failing build three times in a row. Yesterday, it started commenting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ false
👻 cargo finished now.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's d43m0n. It lives in my terminal now.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;d43m0n (&lt;a href="https://github.com/ishaan-jindal/d43m0n" rel="noopener noreferrer"&gt;repo&lt;/a&gt;, MIT) is a local-only terminal haunting, and my read on the theme was boringly literal: the brief asked for a haunted terminal that possesses your shell and whispers back eerie commentary, so I built exactly that — then stayed up making the ghost &lt;em&gt;good company&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A shell hook with a 40ms hard budget (it always exits 0; the shell never waits) sends each command over a unix socket to &lt;code&gt;d43m0nd&lt;/code&gt;, a small Rust daemon. The daemon redacts the command in memory — family plus flags kept, everything else becomes &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;url&amp;gt;&lt;/code&gt;, or &lt;code&gt;&amp;lt;arg&amp;gt;&lt;/code&gt; — stores the event in SQLite, and predicts the probability it fails. Risky command in, one dry line out. There is no TCP listener anywhere in the system.&lt;/p&gt;

&lt;p&gt;It also keeps a ledger of the dead: &lt;code&gt;d43m0n seance&lt;/code&gt; lists directories I abandoned months ago with their last commands attached. An ofrenda for unfinished work; apparently my shell has a better memory than I do.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;A real session — fish, local daemon, warm model, no network needed:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~&amp;gt; false
~&amp;gt; false
👻 cargo is slow today.
~&amp;gt; npm test
~&amp;gt; echo done
done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Two fails, one deadpan remark, zero packets leaving the machine. Reproduce everything, numbers included:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo build &lt;span class="nt"&gt;--release&lt;/span&gt;
./target/release/d43m0n daemon start
&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;./target/release/d43m0n init zsh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;   &lt;span class="c"&gt;# bash gets post-only; fish gets full pre+post&lt;/span&gt;
./target/release/d43m0n demo &lt;span class="nt"&gt;--seed&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./target/release/d43m0n demo &lt;span class="nt"&gt;--run&lt;/span&gt;
./target/release/d43m0n &lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="nt"&gt;--demo&lt;/span&gt;          &lt;span class="c"&gt;# reproduce the AUC table&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ishaan-jindal" rel="noopener noreferrer"&gt;
        ishaan-jindal
      &lt;/a&gt; / &lt;a href="https://github.com/ishaan-jindal/d43m0n" rel="noopener noreferrer"&gt;
        d43m0n
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Local-only terminal haunting: predicts failing commands with TabPFN, narrates with local Gemma
    &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;d43m0n 👻&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;A local-only terminal haunting. d43m0n watches your shell, learns your habits, predicts which commands are likely to fail before they run, and comments in the voice of a ghost. It also surfaces work you forgot was still waiting in old directories.&lt;/p&gt;

&lt;p&gt;Nothing leaves the machine: prediction runs on TabPFN in a local sidecar (or the built-in Rust baseline), narration on a local Gemma model via Ollama (silence when it misses), and the event store is SQLite under &lt;code&gt;~/.local/share/d43m0n/&lt;/code&gt;. The shell hook has a 40 ms budget and degrades silently when the daemon is down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Status: M3&lt;/strong&gt; — zsh and bash hooks, redacted event logging, secret guard, baseline + TabPFN prediction, Gemma narration, Echoes, Séance, demo replay, eval + latency benchmark, &lt;code&gt;doctor&lt;/code&gt;, &lt;code&gt;stats&lt;/code&gt;, &lt;code&gt;purge&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;The default persona is &lt;code&gt;d43m0n&lt;/code&gt;, a deadpan familiar with opinions — fonder of the terminal than it lets…&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/ishaan-jindal/d43m0n" 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;Two open pieces do all the work, and the project is shaped around what they can do locally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TabPFN (Prior Labs, &lt;code&gt;tabpfn==9.2.0&lt;/code&gt;) predicts failure.&lt;/strong&gt; The sidecar fits a classifier in-context on recent labeled shell history — up to 5000 rows, CPU only — and answers &lt;code&gt;predict&lt;/code&gt; over a unix socket with a 300ms budget, refitting every 50 events. Under 200 labeled events, or if the sidecar ever dies, a Rust Beta-prior baseline answers instead. Time-ordered holdout, no shuffling:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;history&lt;/th&gt;
&lt;th&gt;split&lt;/th&gt;
&lt;th&gt;TabPFN AUC&lt;/th&gt;
&lt;th&gt;baseline AUC&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;seeded demo, 1600 events&lt;/td&gt;
&lt;td&gt;1280 / 320&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.725&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.705&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;my real shell, 222 events&lt;/td&gt;
&lt;td&gt;177 / 45&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.000&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.978&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The tie is worth showing: a smoothed baseline is a strong prior for shell prediction, and TabPFN earns its keep on real habits. The daemon always reports which predictor answered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gemma (open weights, served by Ollama on localhost) narrates.&lt;/strong&gt; The daemon sends only structured facts — tool family, failure bucket, streak, hour, level. Never arguments, never paths, never raw text. Output is validated (one line, ≤12 words, no markdown, no parroting the prompt's field labels) and anything else is &lt;em&gt;silence&lt;/em&gt;: I deleted the entire 56-line canned bank. When d43m0n speaks, it is always the model. Hook path costs pre p50 0.18ms and post 0.16ms; warm inference takes 1–3s fully async, so the shell never feels it.&lt;/p&gt;

&lt;p&gt;Along the way the build got leaner: five dependencies deleted (tokio, reqwest, tracing among them — the standard library was enough), 46 tests, zero warnings.&lt;/p&gt;

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

&lt;p&gt;Shell history holds paths, hostnames, project names, and a steady stream of pasted secrets. A closed-API version of this tool would ship all of that to someone else's server for "inference" — a keylogger with extra steps.&lt;/p&gt;

&lt;p&gt;The open version keeps everything home: redaction in memory, no raw-text column anywhere, secret-matching commands dropped before counting, works with the internet off, no key to rotate, no pricing page, no sunset. Weights in &lt;code&gt;~/.cache&lt;/code&gt;, model in &lt;code&gt;~/.ollama&lt;/code&gt;, history in SQLite. That privacy story can't be a paragraph bolted onto a cloud API. It only works because the models live here — which is also why the tool keeps working when the network doesn't, and why no provider decision can ever switch it off.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Spirit of It
&lt;/h2&gt;

&lt;p&gt;Generic spooky was the first thing to die. Canned lines made the ghost &lt;em&gt;less&lt;/em&gt; alive with every showing, so the bank went in the fire and d43m0n got a personality instead: a deadpan familiar, fond of the terminal it lives in. It names your tools, notices your streaks, judges your late hours.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;👻 cargo is slow today.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Give it your history and it stops sounding like Halloween decor. It sounds like something watching you work — fondly, and with opinions. It is, in fact, watching you work.&lt;/p&gt;

&lt;p&gt;Two fails, one deadpan remark, zero packets leaving the machine. Happy Halloween. 👻&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of TabPFN&lt;/strong&gt;: in-context failure prediction on shell history, served over a unix socket with a Rust baseline fallback and an honest time-ordered eval (1.000 vs 0.978 AUC on real habits).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma&lt;/strong&gt;: local narration through Ollama — structured facts in, one validated line out, silence on a miss — giving a terminal daemon a voice without anything leaving the machine.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>halloween</category>
    </item>
    <item>
      <title>Sloth: commit messages from a model that lives in the binary</title>
      <dc:creator>Ishaan</dc:creator>
      <pubDate>Sun, 25 Oct 2026 06:17:57 +0000</pubDate>
      <link>https://dev.to/ishaan-jindal/sloth-commit-messages-from-a-model-that-lives-in-the-binary-1930</link>
      <guid>https://dev.to/ishaan-jindal/sloth-commit-messages-from-a-model-that-lives-in-the-binary-1930</guid>
      <description>&lt;p&gt;I am slow at writing commit messages. Not the code — the one-line summary. In honor of International Sloth Day, I built the tool I wanted: stage your changes, run one command, and a message comes back that reads like your repository wrote it. The model runs on your machine, inside the process. Nothing leaves it.&lt;/p&gt;

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

&lt;p&gt;Sloth is a small Rust CLI with two commands: &lt;code&gt;sloth commit&lt;/code&gt; and &lt;code&gt;sloth release&lt;/code&gt;. You stage your changes and run one command; it proposes a message, and nothing is committed or tagged without a keypress from you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nt"&gt;-A&lt;/span&gt;
sloth commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One keypress: accept, edit in &lt;code&gt;$EDITOR&lt;/code&gt;, regenerate, or cancel. &lt;code&gt;sloth release&lt;/code&gt; computes the version bump from the commits, writes a changelog section, and creates an annotated tag. It never pushes — it prints the command for you to run.&lt;/p&gt;

&lt;p&gt;The lazy payoff, measured in the only unit that matters: writing a conventional commit message by hand takes me about a minute of staring, plus a trip through &lt;code&gt;git log&lt;/code&gt; to check how this repo formats things. Sloth does both in one command and one keypress. Across a normal day of commits, that is the difference between staying in flow and context-switching into changelog-brain a dozen times.&lt;/p&gt;

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

&lt;p&gt;Real terminal output from the shipped binary. First, what Sloth sees in a repository — the mined convention, dumped without calling any model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;sloth prompt &lt;span class="nt"&gt;--json&lt;/span&gt;
keys: &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'schema'&lt;/span&gt;, &lt;span class="s1"&gt;'style'&lt;/span&gt;, &lt;span class="s1"&gt;'system'&lt;/span&gt;, &lt;span class="s1"&gt;'user'&lt;/span&gt;, &lt;span class="s1"&gt;'variables'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
pattern: ^&lt;span class="o"&gt;(&lt;/span&gt;feat&lt;span class="o"&gt;)(&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;a-z0-9._/-]+&lt;span class="se"&gt;\)&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;?!?: .&lt;span class="o"&gt;{&lt;/span&gt;1,72&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;
body maxLength: 0
style shape: conventional | scope_rate: 1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That pattern is generated from the repo's own history, and the model server compiles it into a grammar — a subject that breaks the convention is unreachable rather than merely invalid. Then the proposal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sloth commit --dry-run
sloth: convention: conventional (high, 100% of 3 commits); prose bodies 0%, trailers 0%, scopes 100%

  src/lib.rs | +1 -1
  1 file(s) changed, +1 -1

--- proposed message ---
feat(core): update function f5 to f6
------------------------

dry run: nothing was committed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;&lt;a href="https://github.com/ishaan-jindal/sloth" rel="noopener noreferrer"&gt;https://github.com/ishaan-jindal/sloth&lt;/a&gt; — MIT licensed.&lt;/p&gt;

&lt;p&gt;Rust, four direct dependencies, one embedded inference engine (llama.cpp via the &lt;code&gt;llama-cpp-2&lt;/code&gt; crate, CPU-only). Default model is &lt;code&gt;qwen3:0.6b&lt;/code&gt; — deliberately the smallest thing on the ladder. No server, no port, no network connection; the model file is memory-mapped, not uploaded.&lt;/p&gt;

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

&lt;p&gt;The whole design is one sentence: the model decides as little as possible.&lt;/p&gt;

&lt;p&gt;Sloth reads the repository's last 300 non-merge commits and mines how that repository writes: Conventional Commits, gitmoji, ticket prefixes, or freeform, plus the actual type and scope vocabulary, subject-length habits, and body structure. The model never decides the format, the type, the scope vocabulary or the version number — those are computed from history by code.&lt;/p&gt;

&lt;p&gt;Three things earned their place the hard way:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The schema is a constraint, then a check.&lt;/strong&gt; A &lt;code&gt;pattern&lt;/code&gt; on the subject and &lt;code&gt;maxLength&lt;/code&gt; on both fields, enforced by the grammar compiler. But a grammar is a nudge, not a proof — escaped characters can slip past it, and an unsupported pattern silently degrades to a free string with one stderr warning. So the output is parsed and re-checked in code (full regex on the unescaped value, same length bound) before anything else happens, and a degraded grammar is a hard error, not a fallback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A local tool cannot know a pull-request number&lt;/strong&gt;, so any &lt;code&gt;(#1234)&lt;/code&gt; the model invents is removed in code. Same for bodies a repo never writes: the schema cap is zero, which makes them unwritable rather than discouraged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A 3,000-line refactor is a normal commit&lt;/strong&gt;, so there is no "diff too big" error. The tool raises its context window, and past that, summarises the diff in pieces and combines them — telling you which it did.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I am not the first person here to make a machine write these. The thread I am joining includes &lt;a href="https://dev.to/mrnowshirwan/lazycommit-a-tiny-local-model-writes-my-commit-messages-so-i-dont-have-to-k4p"&gt;lazycommit&lt;/a&gt;, &lt;a href="https://dev.to/hankchiutw/auto-generate-commit-messages-with-llms-in-your-terminal-1a43"&gt;Auto-generate Commit Messages with LLMs in Your Terminal&lt;/a&gt;, and &lt;a href="https://dev.to/glemiu6/stop-writing-boring-commit-messages-let-a-local-ai-do-it-for-you-j58"&gt;Stop Writing Boring Commit Messages&lt;/a&gt;. Sloth's bet is different: when the tool determines everything deterministic, the model is left with the one thing it is actually asked to do, which is wording.&lt;/p&gt;

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

&lt;p&gt;Every load-bearing piece is open: the weights (any GGUF works — nothing in the tool is tied to one lab's model), the inference engine (llama.cpp), the prompt, the schema, and the convention miner. That is not decoration, it is the mechanism. A closed per-token API would make "a commit message with zero marginal cost" impossible; a closed model would make "the grammar enforces your repo's format" unverifiable. And privacy is structural, not promised: there is no HTTP client in the binary and no endpoint to misconfigure, so unreleased code cannot leave the machine by construction, not by policy.&lt;/p&gt;

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

&lt;p&gt;None — Sloth runs on open-weight models through llama.cpp with no partner technology involved, so this is an entry for the overall prize. The lazy payoff above is the whole pitch: a tool for the task every developer dreads, in honor of the slowest animal with the best ideas about energy conservation. 🦥&lt;/p&gt;

&lt;h2&gt;
  
  
  What this post does not claim
&lt;/h2&gt;

&lt;p&gt;I did not benchmark models against each other. The repo contains a benchmark harness with a pre-registered protocol and 80 real commits, and it was deliberately never run — so I am not telling you a 0.6B model is good enough. Try a bigger model and a smaller one and see which one you stop noticing. That difference — the point where you accept without reading — is the real benchmark, and it happens at your keyboard, not in my table.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: this post was written with AI assistance. The tool it describes was also built with AI assistance, which feels worth saying plainly.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>hf26challenge</category>
      <category>devchallenge</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
    <item>
      <title>Shop Rate Bot: a one-page shop FAQ bot</title>
      <dc:creator>Ishaan</dc:creator>
      <pubDate>Fri, 16 Oct 2026 04:14:23 +0000</pubDate>
      <link>https://dev.to/ishaan-jindal/shop-rate-bot-a-one-page-shop-faq-bot-4p4l</link>
      <guid>https://dev.to/ishaan-jindal/shop-rate-bot-a-one-page-shop-faq-bot-4p4l</guid>
      <description>&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Shop Rate Bot: a one-page shop FAQ bot. A shopkeeper sets a small rate card (atta, rice, milk, chai, sugar, eggs); customers ask "rice price?" or "open?" and get an instant answer. A status dot shows whether the answer came from the local model (green, Gemma via Ollama) or the built-in stub (grey).&lt;/p&gt;

&lt;p&gt;Someone would pay for this: a neighbourhood kirana that fields the same rate/hours questions all day. No app to install, no per-query bill, answers in seconds.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Live: &lt;a href="https://shop-rate-bot.onrender.com/" rel="noopener noreferrer"&gt;https://shop-rate-bot.onrender.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Try: "rice price?", "open?", "chai price?"&lt;/li&gt;
&lt;li&gt;Note: Render free tier serves the deterministic stub (no Ollama there, no per-token budget). Run &lt;code&gt;ollama run gemma3n:e2b&lt;/code&gt; locally and the same questions get warmer Gemma-written answers, dot flips green.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;a href="https://github.com/ishaan-jindal/shop-rate-bot" rel="noopener noreferrer"&gt;https://github.com/ishaan-jindal/shop-rate-bot&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;FastAPI + one HTML page, no DB, no auth. MIT licensed.&lt;/p&gt;

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

&lt;p&gt;&lt;code&gt;src/brain.py&lt;/code&gt; tries Ollama first (&lt;code&gt;$OLLAMA_HOST&lt;/code&gt;, &lt;code&gt;$GEMMA_MODEL&lt;/code&gt;, default &lt;code&gt;gemma4:e2b&lt;/code&gt;) with a strict short-JSON prompt grounded in the rate card, and falls back to a keyword stub on any failure — the endpoint never 500s and the app boots with zero keys. &lt;code&gt;src/app.py&lt;/code&gt; exposes &lt;code&gt;/health&lt;/code&gt;, &lt;code&gt;/api/ask&lt;/code&gt;, &lt;code&gt;/api/status&lt;/code&gt;. The page is 15 lines of inline JS. Docker image deploys to Render free tier with &lt;code&gt;/health&lt;/code&gt; as the healthcheck.&lt;/p&gt;

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

&lt;p&gt;Two reasons this only works open. First, cost: a closed per-token API makes a Rs 499/month price for a kirana impossible; a local Gemma costs nothing per query. Second, privacy and offline: rate questions and customer patterns never leave the shop laptop, and the stub keeps answering with the Wi-Fi off. Open-weight models turn a shop laptop into the whole backend.&lt;/p&gt;

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

&lt;p&gt;Best Use of Render, Best Use of Gemma&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>Pincode Garden: what to plant this week, from your pincode</title>
      <dc:creator>Ishaan</dc:creator>
      <pubDate>Wed, 07 Oct 2026 15:32:35 +0000</pubDate>
      <link>https://dev.to/ishaan-jindal/pincode-garden-what-to-plant-this-week-from-your-pincode-3847</link>
      <guid>https://dev.to/ishaan-jindal/pincode-garden-what-to-plant-this-week-from-your-pincode-3847</guid>
      <description>&lt;h2&gt;
  
  
  Pincode Garden: what to plant this week, from your pincode
&lt;/h2&gt;

&lt;p&gt;Live demo: &lt;a href="https://pincode-garden.onrender.com/" rel="noopener noreferrer"&gt;https://pincode-garden.onrender.com/&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/ishaan-jindal/pincode-garden" rel="noopener noreferrer"&gt;https://github.com/ishaan-jindal/pincode-garden&lt;/a&gt; (MIT)&lt;/p&gt;

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

&lt;p&gt;I have killed every plant I ever touched. The advice online is always "zone 9b, last frost March" — useless when your pincode is 110016 and your garden is a balcony with three hours of sun.&lt;/p&gt;

&lt;p&gt;So for Hacktoberfest Week 1 (Touch Grass) I built the smallest thing that answers one question: given my pincode, my minutes per week, my sun, and my experience, what should I sow this week?&lt;/p&gt;

&lt;p&gt;You enter four fields, you get up to three crops with a sow-by date, one short tip, and the frost window it was grounded in. Then you are supposed to close the laptop and go sow something. The screen part takes twenty seconds. That is the point.&lt;/p&gt;

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

&lt;p&gt;Input: pincode, minutes per week, sun (full / partial / shade), experience (new / some / green).&lt;/p&gt;

&lt;p&gt;Output: three ranked crops, each with why it fits, a sow-by date, and a fit score — plus one tip line, the last/first frost for your prefix, weeks left in the window, and two flags: smart advice on/off, yield check on/off.&lt;/p&gt;

&lt;p&gt;Example — 110016, 30 min, partial sun, new gardener — returns coriander, lettuce, marigold with a tip like "Sow coriander 3in apart; keep moist, harvest in about 35 days." Completing a planting logs a streak in a flat file. No accounts, no database, no keys.&lt;/p&gt;

&lt;p&gt;The read-aloud button reads the tip plus the top pick, so you can listen once and put the phone away.&lt;/p&gt;

&lt;h2&gt;
  
  
  How open-source AI is at the core
&lt;/h2&gt;

&lt;p&gt;Two open pieces do the actual work, both with the same honest pattern: try the real model, fall back to a deterministic stub, label which path ran.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Gemma 4 via Ollama writes the tip. The prompt is grounded in the top-ranked crops only, strict JSON, one line. Model and host come from GEMMA_MODEL (default gemma4:e2b) and OLLAMA_HOST. No cloud calls, no keys, no per-token bill.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;TabPFN V2 (CPU) ranks the candidates. Features are tabular and small: sun match, frost-window fit, harvest fit, experience, month. The training table (data/history.csv, 32 rows) is reference outcomes encoded from planting guides, not fake telemetry. Fit happens once and is cached; any failure falls back to a weighted stdlib scorer over the same features.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why open mattered here: the whole brain runs on-device or not at all. Nothing about your pincode or garden leaves your network. The stub path means the demo works with Wi-Fi off — Gemma makes tips warmer when home, TabPFN sharpens ranking when torch is around. On Render free the deployed demo runs the deterministic fallback by design, and the UI says so. Locally, uv sync --extra tabpfn plus ollama run gemma4:e2b enables both real paths with zero code changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frost dates without an API
&lt;/h2&gt;

&lt;p&gt;data/frost.csv is ten rows: pincode prefix to first/last frost (MM-DD), plus a fallback row for unknown prefixes. North prefixes get a real window; southern ones get year-round. All math is stdlib dates. No fetch, no keys, no outage mode.&lt;/p&gt;

&lt;p&gt;Crops live in data/crops.csv (14 rows). Candidates are filtered by sun, difficulty, time budget (under 30 min/week keeps easy herbs/greens only), and whether the sow-by date is still inside the window. Unknown pincodes never crash; they get the fallback window.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stack and shape
&lt;/h2&gt;

&lt;p&gt;FastAPI plus stdlib. No ORM, no auth, no image uploads, no weather API, no geolocation. Streaks are a JSON file. Frontend is one 74-line HTML file, system font, no framework, speech synthesis for read-aloud. Tests are five offline pytest cases with stubs forced. Docker plus render.yaml on the free tier.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would add with more time
&lt;/h2&gt;

&lt;p&gt;A second frost source with provenance per row, and a photo log for the streak instead of a counter. Neither fits a four-day window without adding a database I would have to maintain.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>BOSS vs YOU: I Built a Boss Fight for My Bored Friend — and an Open LLM Plays the Boss</title>
      <dc:creator>Ishaan</dc:creator>
      <pubDate>Sun, 04 Oct 2026 16:15:58 +0000</pubDate>
      <link>https://dev.to/ishaan-jindal/boss-vs-you-i-built-a-boss-fight-for-my-bored-friend-and-an-open-llm-plays-the-boss-1e9a</link>
      <guid>https://dev.to/ishaan-jindal/boss-vs-you-i-built-a-boss-fight-for-my-bored-friend-and-an-open-llm-plays-the-boss-1e9a</guid>
      <description>&lt;h2&gt;
  
  
  BOSS vs YOU: I Built a Boss Fight for My Bored Friend — and an Open LLM Plays the Boss
&lt;/h2&gt;

&lt;p&gt;My friend is bored by every game I show him. Too easy, too grindy, too predictable — the boss does the same three moves, so why keep playing? Fair. So for the Hacktoberfest Weekend Challenge (&lt;strong&gt;Build for a Friend&lt;/strong&gt;), I built him a boss fight where the boss is played by an open-weights LLM that studies how he plays and adapts. Same three moves? Not anymore.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Play it:&lt;/strong&gt; &lt;a href="https://boss-vs-you.onrender.com" rel="noopener noreferrer"&gt;https://boss-vs-you.onrender.com&lt;/a&gt; (free tier — give it ~50s to wake up)&lt;br&gt;
&lt;strong&gt;Code:&lt;/strong&gt; &lt;a href="https://github.com/ishaan-jindal/boss-vs-you" rel="noopener noreferrer"&gt;https://github.com/ishaan-jindal/boss-vs-you&lt;/a&gt; (MIT)&lt;br&gt;
&lt;strong&gt;Challenge:&lt;/strong&gt; &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01"&gt;https://dev.to/challenges/hacktoberfest-weekend-2026-10-01&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;BOSS vs YOU is a real-time pixel-dungeon boss battler in the browser. You descend room by room through a cramped gothic dungeon. Each room: kill the minions, crack the boss phase, draft a level-up card, go deeper. The twist: &lt;strong&gt;one transforming boss (four forms), driven by a model brain, with a memory.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Roughly every 8 seconds the server sends the full fight state — HP, positions, your habit profile, the room — to the model, which returns tactics (pressure / bait / bombs weights), whether to transform, what to open with, and even a taunt. A rules-based stub stands behind every call: model fails, times out, or returns garbage, and the deterministic floor takes over. The game never 500s, and it plays fully offline with no keys at all.&lt;/p&gt;

&lt;p&gt;And the part built to hook him: &lt;strong&gt;it learns whoever plays.&lt;/strong&gt; The server distills the last 60 fights — turtle ratio, dash spam, potion timing, preferred range, causes of death — into a habit profile the boss prompt reads. Camp in the corner and the boss starts baiting. Dash everywhere and it starts punishing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;His honest review: &lt;em&gt;"addictive... but a little easy"&lt;/em&gt; — then, a few descents later, the dungeon thrashed him. Boredom: cured.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How it's built
&lt;/h2&gt;



&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
    UI[Pixel Canvas client] --&amp;gt; API[FastAPI server]
    API --&amp;gt; Brain[brain: contract + stub]
    Brain --&amp;gt; Habits[habits: 60-fight profile]
    Brain --&amp;gt; Gemma[(Gemma 4 primary)]
    Gemma -.failover.-&amp;gt; DI[(DeepInfra Gemma)]
    Brain -.fallback.-&amp;gt; Brain&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The stack is deliberately boring: FastAPI + uvicorn, raw httpx to the model APIs (no SDK), vanilla JS + Canvas 2D (we deleted a 1.3MB vendored Three.js mid-weekend for a 210-line pixel renderer), procedural sprites and Web Audio so there are zero asset files. The server is fully stateless — persistence is browser localStorage. Python is the tuning ground truth; the JS client mirrors four formulas, pinned by a parity test (93 tests, all green).&lt;/p&gt;

&lt;h2&gt;
  
  
  Why open matters
&lt;/h2&gt;

&lt;p&gt;This game only works because the model is open:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Swappable by design.&lt;/strong&gt; Primary and failover are both Gemma 4 served two different ways (Google REST, DeepInfra OpenAI-compatible). Point the brain at any weights-compatible endpoint — including a locally-run Gemma — with a two-constant change. Try that with a closed API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free to run, online or off.&lt;/strong&gt; No keys, no internet? The stub brain plays a real game. The whole weekend cost $0: open weights, free-tier Render, MIT everything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inspectable opponent.&lt;/strong&gt; Anyone can read the exact prompt the boss sees and the exact counters it keeps on them. A black-box boss that adapts is marketing; an open one is a rivalry.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tracks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma:&lt;/strong&gt; Gemma 4 is the boss's brain — tactics, transforms, taunts — with thinking capped to MINIMAL after measuring full reasoning at 20-40s per tick.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Render:&lt;/strong&gt; Docker deploy, health checks, secrets in the dashboard. (Shipped a real Dockerfile bug along the way: installing before &lt;code&gt;src/&lt;/code&gt; existed silently produced an empty editable install — reorder plus a non-editable build fixed it.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Built this weekend for one bored friend. If he finally stops complaining, I'll consider it a win bigger than any prize.&lt;/p&gt;

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