<?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: James D. Bartlett III</title>
    <description>The latest articles on DEV Community by James D. Bartlett III (@jamesdbartlett3).</description>
    <link>https://dev.to/jamesdbartlett3</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%2F120436%2Fe3fd3177-3f6b-4fbf-90ed-54576d7c4a9d.jpeg</url>
      <title>DEV Community: James D. Bartlett III</title>
      <link>https://dev.to/jamesdbartlett3</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jamesdbartlett3"/>
    <language>en</language>
    <item>
      <title>I gave my messy photo archive a spirit guide — an offline, open-weight AI that learns your family, names your places, and finds any memory</title>
      <dc:creator>James D. Bartlett III</dc:creator>
      <pubDate>Sat, 31 Oct 2026 17:13:01 +0000</pubDate>
      <link>https://dev.to/jamesdbartlett3/i-gave-my-messy-photo-archive-a-spirit-guide-an-offline-open-weight-ai-that-learns-your-family-4ffb</link>
      <guid>https://dev.to/jamesdbartlett3/i-gave-my-messy-photo-archive-a-spirit-guide-an-offline-open-weight-ai-that-learns-your-family-4ffb</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;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Alebrije&lt;/strong&gt; (&lt;a href="https://github.com/JamesDBartlett3/Alebrije" rel="noopener noreferrer"&gt;github.com/JamesDBartlett3/Alebrije&lt;/a&gt;) is a local-first archive spirit-guide for your photos, videos, and audio clips. Alebrijes are the brightly colored creatures of Mexican folk art that guide souls where they need to go — this one guides &lt;em&gt;you&lt;/em&gt; through thousands of memories that would otherwise sit in folders with names like &lt;code&gt;DCIM_0947&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You point it at a messy directory. It then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Meets your people.&lt;/strong&gt; You introduce a friend or family member from a sample photo (&lt;code&gt;alebrije person add Abuela --photo abuela.jpg&lt;/code&gt;), and Alebrije builds a private &lt;em&gt;people book&lt;/em&gt;: the face is embedded locally by open face models (SCRFD detection + AdaFace recognition via onnxruntime) and described in words by the vision model — no cloud, no face database handed to a third party.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recognizes them everywhere, and names every place.&lt;/strong&gt; Every photo is scanned for faces; each becomes a 512-d vector stored locally. Faces close to someone in your people book are matched automatically, borderline ones are double-checked by Gemma, and recurring strangers cluster into "Unnamed" people you name with one rename. It also tags every photo and video with objects, clothing, animals, food, and the &lt;em&gt;mood&lt;/em&gt; of the moment. If a photo carries GPS coordinates, it finds the &lt;strong&gt;closest point of interest&lt;/strong&gt; (a park, museum, landmark — nearest by real haversine distance, via the OpenStreetMap Overpass API) and &lt;strong&gt;always appends the municipality chain&lt;/strong&gt;: &lt;code&gt;Civic Center Park — Denver, Colorado, USA&lt;/code&gt;, or with no landmark in range simply &lt;code&gt;City of Golden, Jefferson County, Colorado, USA&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remembers by feeling, not filename.&lt;/strong&gt; Everything is embedded with an open model into a local SQLite index, so you can search in plain language — &lt;em&gt;"dog on the beach at sunset"&lt;/em&gt; — sorted by relevance, newest, media type, or name.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Everything runs on your machine: an open-weight multimodal model (Gemma 3 4B via llama.cpp) looks at your media, open face models (SCRFD + AdaFace via onnxruntime) recognize your people, an open embedding model (nomic-embed-text) indexes it, and a Día de los Muertos–themed local web app — papel picado banner, marigold glow — serves the whole collection to any phone or laptop on your network. Nothing about your family ever leaves your hardware (the only outbound calls, and only for GPS-tagged files, are the two open-data OpenStreetMap geocoders, which receive coordinates, never images).&lt;/p&gt;

&lt;p&gt;I built this for the #GhostInTheMachine theme the way Día de los Muertos itself treats it: the dead stay alive as long as their stories are told. A hard drive full of untagged photos is a room full of ancestors waiting to be introduced. Alebrije is the marigold path through it.&lt;/p&gt;

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

&lt;p&gt;Everything below is from a live run on an ordinary 4-core desktop, CPU only:&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%2F7y774z2sqdr4px9pq4hp.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%2F7y774z2sqdr4px9pq4hp.png" alt="Alebrije web gallery" width="799" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Six files went in named &lt;code&gt;IMG_4031.png&lt;/code&gt; … &lt;code&gt;IMG_4043.jpg&lt;/code&gt;. Alebrije tagged all six (captions, objects, clothing, mood), recognized and named a person across four of them from a single sample photo, and reverse-geocoded the two that carried GPS. Then, in plain language:&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%2Fg2kt21b8on69m1y6h3fc.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%2Fg2kt21b8on69m1y6h3fc.png" alt="Natural-language search" width="799" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;"dog on the beach at sunset"&lt;/code&gt; puts the three beach-dog photos on top — including one taken before the archive's newest party photos — because ranking is by meaning, not date.&lt;/p&gt;

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

&lt;p&gt;The CLI speaks the same language:&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%2Fzoht0bgf5hw76jflca5m.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%2Fzoht0bgf5hw76jflca5m.png" alt="CLI search" width="799" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And it's the same app on a phone, served from your own desk over the LAN:&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%2Fc7oktk9phfw2hw9eucyy.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%2Fc7oktk9phfw2hw9eucyy.png" alt="Phone view" width="405" height="811"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://github.com/JamesDBartlett3/Alebrije" rel="noopener noreferrer"&gt;https://github.com/JamesDBartlett3/Alebrije&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Install and run (Python 3.10+ and &lt;a href="https://pipx.pypa.io/" rel="noopener noreferrer"&gt;pipx&lt;/a&gt; are the only prerequisites — Alebrije installs everything else):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pipx &lt;span class="nb"&gt;install &lt;/span&gt;git+https://github.com/JamesDBartlett3/Alebrije.git@v0.2.0
alebrije setup        &lt;span class="c"&gt;# downloads llama.cpp + the open-weight models, auto-detects your GPU&lt;/span&gt;
alebrije init ~/Pictures/family
alebrije up           &lt;span class="c"&gt;# starts the two local model servers&lt;/span&gt;
alebrije scan         &lt;span class="c"&gt;# index files, read EXIF dates + GPS&lt;/span&gt;
alebrije tag          &lt;span class="c"&gt;# vision-tag everything (CPU: ~1 min/photo, GPU: seconds)&lt;/span&gt;
alebrije serve        &lt;span class="c"&gt;# http://localhost:8799 — also on your LAN&lt;/span&gt;
alebrije update       &lt;span class="c"&gt;# later: checks GitHub releases, upgrades in place&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No pipx? &lt;code&gt;git clone&lt;/code&gt; + &lt;code&gt;python alebrije.py &amp;lt;command&amp;gt;&lt;/code&gt; works straight from the repo — friendliest option on Windows.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vision + language:&lt;/strong&gt; &lt;a href="https://huggingface.co/ggml-org/gemma-3-4b-it-GGUF" rel="noopener noreferrer"&gt;Gemma 3 4B IT&lt;/a&gt; (open weights, Gemma license) served by &lt;strong&gt;llama.cpp's&lt;/strong&gt; &lt;code&gt;llama-server&lt;/code&gt; with its multimodal projector. Every caption, object list, clothing item, animal, mood, person description, and gray-band identity double-check comes from this one local model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embeddings &amp;amp; search:&lt;/strong&gt; &lt;a href="https://huggingface.co/nomic-ai/nomic-embed-text-v1.5-GGUF" rel="noopener noreferrer"&gt;nomic-embed-text v1.5&lt;/a&gt; (Apache-2.0), via llama.cpp's OpenAI-compatible embeddings endpoint. Vectors live as float32 blobs in SQLite; cosine ranking is a few lines of Python.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faces, without the cloud:&lt;/strong&gt; v0.1 matched people by Gemma descriptions alone — we shipped it, watched it conflate lookalike relatives and miss people across decades, measured the failure, and rebuilt identity on real face embeddings. &lt;a href="https://github.com/deepinsight/insightface" rel="noopener noreferrer"&gt;SCRFD-10GF&lt;/a&gt; detects every face (five landmarks each) and &lt;a href="https://github.com/yakhyo/adaface-onnx" rel="noopener noreferrer"&gt;AdaFace ir101&lt;/a&gt; — trained specifically to handle &lt;em&gt;low-quality&lt;/em&gt; faces, i.e. old family photos — turns each aligned crop into a 512-d identity vector, both on onnxruntime (MIT) on CPU. Detection runs a letterboxed whole-image pass &lt;em&gt;plus&lt;/em&gt; overlapping native-resolution tiles on large photos, so faces never get lost to downsampling; alignment crops are always warped from the full-resolution original. Matching uses measured thresholds (same person ≈ 0.56–0.95, different people ≈ 0.0), with Gemma confirming borderline cases and strangers auto-clustering into nameable "Unnamed" people.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The app itself is nearly all Python standard library&lt;/strong&gt; — a scanner (with a hand-rolled EXIF parser that pulls capture dates &lt;em&gt;and&lt;/em&gt; GPS coordinates out of JPEG APP1 segments), a tagging pipeline, a people book, a vector index, a CLI, and a threaded web server with an embedded single-page UI. The only pip dependencies are &lt;code&gt;onnxruntime&lt;/code&gt; and &lt;code&gt;Pillow&lt;/code&gt;. No framework, no account.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fully self-installing, fully cross-platform.&lt;/strong&gt; &lt;code&gt;alebrije setup&lt;/code&gt; works on Linux, macOS, and Windows: it queries the llama.cpp GitHub releases API and downloads the prebuilt build matching your OS, CPU architecture, and &lt;strong&gt;accelerator&lt;/strong&gt; — NVIDIA (&lt;code&gt;nvidia-smi&lt;/code&gt;), AMD ROCm (&lt;code&gt;rocm-smi&lt;/code&gt;), Vulkan (&lt;code&gt;vulkaninfo&lt;/code&gt;), Apple Metal on any Mac, or plain CPU — then fetches the five open models (three GGUFs from Hugging Face, two face ONNXs from GitHub releases) with resume support. When a GPU is present, &lt;code&gt;alebrije up&lt;/code&gt; launches the models with full layer offload (&lt;code&gt;-ngl 999&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests:&lt;/strong&gt; 182 offline tests (&lt;code&gt;alebrije selftest&lt;/code&gt;) cover the scanner (including a synthetic JPEG with hand-built EXIF + GPS binary), the face pipeline (letterbox/tiling math, SCRFD decoding, similarity alignment, threshold bands, clustering, v0.1-database migration), tag coercion, people matching, vector math, search sorting, the bootstrap asset picker for every OS/GPU combo, server lifecycle, the web API (real HTTP on an ephemeral port), and the CLI — all against fake model servers, no network or GPU required.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Your family photos are the last data you'd ever hand to a stranger, and the first data that gets uploaded without thinking the moment you use a cloud "AI photo assistant." Open weights flip that: the same Gemma model a giant cloud product would run is running &lt;em&gt;on your desk&lt;/em&gt;, inspectable, with your files never leaving the room.&lt;/p&gt;

&lt;p&gt;Openness also made this project possible at all. llama.cpp's OpenAI-compatible server meant the whole app is one &lt;code&gt;urllib&lt;/code&gt; call away from vision and embeddings; the GGUF ecosystem meant a 4B model runs on an ordinary 4-core CPU; permissive licenses meant everything here ships without negotiation; and OpenStreetMap's open geodata meant place names without a paid maps API. If the models were closed, an offline family-archive assistant simply couldn't exist — and if they were free-but-closed, it couldn't be audited, fine-tuned, or trusted with something as personal as a memorial archive.&lt;/p&gt;

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

&lt;p&gt;The moment it landed: I fed it six files named &lt;code&gt;IMG_40xx&lt;/code&gt; and asked, out loud, &lt;em&gt;"dog on the beach at sunset"&lt;/em&gt; — and the first three results were exactly the three photos I'd have picked, one of them taken years before the others. A folder became a memory. That's the whole ofrenda: the tech is just the marigold petals; what they guide home is your own past.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gemma&lt;/strong&gt; (Featured) — Alebrije is built around Gemma 3 4B: every caption, tag, person description, and borderline identity double-check comes from the open-weight Gemma model running locally through llama.cpp.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>python</category>
      <category>ai</category>
    </item>
    <item>
      <title>I rode out two hurricanes with a Discord bot. Here's the open-source, offline-first version anyone can run.</title>
      <dc:creator>James D. Bartlett III</dc:creator>
      <pubDate>Mon, 26 Oct 2026 05:43:08 +0000</pubDate>
      <link>https://dev.to/jamesdbartlett3/i-rode-out-two-hurricanes-with-a-discord-bot-heres-the-open-source-offline-first-version-anyone-52m8</link>
      <guid>https://dev.to/jamesdbartlett3/i-rode-out-two-hurricanes-with-a-discord-bot-heres-the-open-source-offline-first-version-anyone-52m8</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19"&gt;Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Earlier this month I closed on a house in coastal Mexico, got hit by Hurricane Simon before I'd even unpacked, and rode out Hurricane Trudy the following weekend. Between board-up runs I ran a little Discord bot that watched the National Hurricane Center for me every two hours, logged every advisory, and screamed only when something actually mattered. It worked. The house is fine, and I never opened a cone map once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Batten&lt;/strong&gt; (&lt;em&gt;verb&lt;/em&gt;: to batten down the hatches) is that bot rebuilt for everyone else — generalized, hardened, and with an open-weight model at its core:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Watches NOAA for you.&lt;/strong&gt; NHC storm trackers for your part of the world, NWS alerts for your exact coordinates (US), configurable alert feeds for anywhere else. It fires on the things that matter — new storms, category changes, rapid intensification, landfall statements, proximity crossings at 300/150 nm — and stays quiet otherwise. Routine updates respect quiet hours; real triggers break through.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keeps working when the internet dies.&lt;/strong&gt; This is the whole point. The first failed check tells you &lt;em&gt;what broke&lt;/em&gt; ("DNS failing — internet down or captive portal" vs "connections timing out — weak signal"). It keeps retrying in the background, and if NOAA stays unreachable for 6 hours it builds a &lt;strong&gt;worst-case 48-hour outlook&lt;/strong&gt; from the last good advisory — persistence track extrapolation, one category of assumed intensification, wind-field arrival times, rainfall bands — every line labeled ESTIMATE, timestamped to the last good data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Talks to you through a local model.&lt;/strong&gt; Chat, briefings, and the worst-case action plan run on an open-weight model via &lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt; on your own machine. When a storm takes your internet down — the exact moment you want a weather assistant — the AI is the part that still works.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Three ways to see it:&lt;/strong&gt; a plain CLI, a cross-platform &lt;strong&gt;TUI&lt;/strong&gt; (PC/Mac/Linux), and a &lt;strong&gt;local web dashboard&lt;/strong&gt; served on your LAN — open it on your phone while you're boarding up the windows, no cloud involved.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tracks your supplies&lt;/strong&gt; against a ready.gov-derived checklist that scales to your household, so "are we ready?" is one command, not a 2 a.m. inventory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speaks metric and imperial&lt;/strong&gt;, takes your location as GPS coordinates or ZIP code, and frames everything relative to &lt;em&gt;your&lt;/em&gt; position: how far, which direction, and whether the storm is headed toward you or moving away.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Who gets to be lazier: anyone in a storm's path who currently has twelve browser tabs of cone maps open and a not-app storm checklist in their head. You set Batten up once; it does the watching, the remembering, and the "what does this advisory actually mean for my address" translation.&lt;/p&gt;

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

&lt;p&gt;Batten is deliberately local (that's the thesis — it has to work when the internet doesn't), so instead of a hosted demo the repo ships a &lt;strong&gt;fully offline storm replay&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/JamesDBartlett3/Batten &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;Batten
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; batten demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This replays a real hurricane's full lifecycle — advisories transcribed from an actual storm watcher's log — including a simulated internet outage. You'll watch it detect the storm, fire category-change and rapid-intensification triggers, warn "cannot reach NOAA" when the outage hits, and at the six-hour mark produce the worst-case 48-hour outlook from stale data. No network needed, runs in about fifteen seconds.&lt;/p&gt;

&lt;p&gt;Screenshots (from the repo's &lt;code&gt;screenshots/&lt;/code&gt; folder):&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%2Fcizaywho7p8050nnprhd.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%2Fcizaywho7p8050nnprhd.png" alt="TUI dashboard" width="799" height="373"&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%2F0a0yx7k742ecc06rmaj4.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%2F0a0yx7k742ecc06rmaj4.png" alt="TUI dashboard, 6 hours into a simulated outage" width="799" height="373"&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%2Fhfi6j1z338bwrkb7viyr.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%2Fhfi6j1z338bwrkb7viyr.png" alt="Worst-case outlook from stale data" width="800" height="441"&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%2Fhvuewm6nqxab0k61tl3k.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%2Fhvuewm6nqxab0k61tl3k.png" alt="Chat on the local model" width="800" height="735"&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%2F2jl37ip62vmolwrqznr8.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%2F2jl37ip62vmolwrqznr8.png" alt="LAN dashboard on a phone" width="390" height="844"&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%2Fh0okobeymn12cqe9fe1r.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%2Fh0okobeymn12cqe9fe1r.png" alt="Supply readiness" width="800" height="933"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Repo: &lt;strong&gt;&lt;a href="https://github.com/JamesDBartlett3/Batten" rel="noopener noreferrer"&gt;https://github.com/JamesDBartlett3/Batten&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The entire thing is &lt;strong&gt;Python stdlib — zero pip dependencies&lt;/strong&gt; (~4k lines, 155 offline tests):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;noaa.py&lt;/code&gt; + &lt;code&gt;providers/&lt;/code&gt; — NHC trackers, and a pluggable alert-provider layer: built-ins for NWS, CAP 1.2 feeds (the format most national weather services publish), and a generic JSON endpoint with field mapping, so you can point it at any alert service with a connection string&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;worstcase.py&lt;/code&gt; — the offline 48-hour extrapolation engine with documented, deliberately pessimistic assumptions&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;brain.py&lt;/code&gt; — the Ollama client (plain &lt;code&gt;urllib&lt;/code&gt;, ~40 lines) and the prompts&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;watcher.py&lt;/code&gt; — the trigger state machine, adaptive cadence, quiet hours, outage fires&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tui.py&lt;/code&gt; — ANSI terminal dashboard; &lt;code&gt;web.py&lt;/code&gt; — stdlib HTTP server + mobile-first single-page dashboard for the LAN&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tests/&lt;/code&gt; — a full offline suite; nothing in CI touches the network&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;The open-source AI core:&lt;/strong&gt; an open-weight model (default &lt;code&gt;llama3.2:3b&lt;/code&gt;, any Ollama-pulled model works) doing local inference for everything conversational — chat, briefings, and narrating the worst-case plan. It talks to Ollama over plain HTTP; no SDKs, no accounts, no API keys.&lt;/p&gt;

&lt;p&gt;The design rule that shaped everything else: &lt;strong&gt;the model is never a single point of failure.&lt;/strong&gt; The safety loop — trigger detection, connectivity monitoring, worst-case math — is deterministic Python. The model turns numbers into judgment; if the model is cold or the laptop is struggling, the numbers still get delivered. The model gets &lt;em&gt;only&lt;/em&gt; data Batten fetched or computed, with source timestamps, so it can't hallucinate an advisory that doesn't exist. Data in, judgment out, all on one machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The data half is open too:&lt;/strong&gt; NOAA/NHC/NWS are public-domain open data. The alert-provider layer means the same binary works in Mexico on a CAP feed or against your municipality's JSON endpoint, not just US NWS.&lt;/p&gt;

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

&lt;p&gt;Because the failure mode this tool exists for is &lt;em&gt;the internet being gone&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A closed API assistant goes dark exactly when you need it most.&lt;/strong&gt; Storm knocks out connectivity — a cloud-model chat is unreachable, and your conversation history is on someone else's server. Batten's model runs on the laptop next to the flashlights. The chat that answered "should I cover the windows now?" at noon answers it at hour six of the outage, working from the last good advisory and its own log.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your data stays yours.&lt;/strong&gt; Coordinates, household size, supply list, and every anxious 3 a.m. question live in &lt;code&gt;~/.batten/&lt;/code&gt;. There is no telemetry, because there's nowhere to send it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost nothing, forever.&lt;/strong&gt; No subscription, no per-query meter, no tier where alerts become a paid feature. Set it up once; it runs on a decade-old laptop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inspectable and swappable.&lt;/strong&gt; Worst-case doctrine too conservative for your coast? It's a documented module with the assumptions written at the top. Prefer Qwen to Llama? One flag. Try asking a closed weather assistant to change its forecasting philosophy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open compounds.&lt;/strong&gt; The cone-image download workaround, the trigger thresholds, the quiet-hours rules — all of that came from an open-source storm bot's fix history, and now it's in a generalized tool anyone can fork for their own coast.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;During the real week this tool is based on, the storm it watched meandered offshore for &lt;strong&gt;five days&lt;/strong&gt;. Manually checking the NHC that responsibly means roughly 60+ cone-map refreshes across a work week while also doing actual storm prep — and the checks you skip at 4 a.m. are exactly the ones where rapid intensification happens.&lt;/p&gt;

&lt;p&gt;Batten's deal: it checks on cadence (tightening to 30 minutes when things get close), pages you only on triggers that matter, and &lt;em&gt;stops nagging&lt;/em&gt; during quiet hours. You get pinged four or five times across a five-day event — new storm, category change, "it's within 300 nm, finish outdoor prep," "it's within 150 nm, go inside" — instead of refreshing a map sixty times. The supply list is built once and re-scores itself every season. And the worst-case outlook means an internet outage during the storm stops being "am I blind now?" and becomes "here's the plausible worst case, here's what to finish first."&lt;/p&gt;

&lt;p&gt;The original bot ran through the real Trudy week; zero house damage, and its human spent the whole storm swinging a hammer instead of watching maps. That's the lazy payoff: the bot does the watching so you can do the boarding.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>python</category>
      <category>ai</category>
    </item>
    <item>
      <title>My Coworkers Pay Monthly to Stream Their Voice to a Datacenter. So I Built Them Loquacio: a Free Dictation App That Never Phones Home</title>
      <dc:creator>James D. Bartlett III</dc:creator>
      <pubDate>Mon, 05 Oct 2026 04:46:58 +0000</pubDate>
      <link>https://dev.to/jamesdbartlett3/my-coworkers-pay-monthly-to-stream-their-voice-to-a-datacenter-so-i-built-them-loquacio-a-free-4kmd</link>
      <guid>https://dev.to/jamesdbartlett3/my-coworkers-pay-monthly-to-stream-their-voice-to-a-datacenter-so-i-built-them-loquacio-a-free-4kmd</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;&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%2Fbfrdzhnemoyzi8oejsss.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%2Fbfrdzhnemoyzi8oejsss.png" alt=" " width="799" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;This one's for my coworkers at P3 Adaptive. Many of them dictate every day, and many of them pay a monthly subscription for commercial apps that don't even process the audio locally — so there's always a "who's potentially reading this?" question looming over everything. Their voice, recorded at their own desk, streamed to somebody else's datacenter. Some of them live with it; the rest just kept typing.&lt;/p&gt;

&lt;p&gt;So I built them &lt;strong&gt;Loquacio&lt;/strong&gt;: a desktop dictation app where every millisecond of audio stays on the machine it was spoken into, and which costs exactly nothing. That last part matters: since it's built entirely from open-source components — Whisper, local LLM servers, .NET itself — the subscription apps they've been paying for really ought to be free. Loquacio is me making that true. Speech recognition runs on a local Whisper model through &lt;a href="https://github.com/sandrohanea/whisper.net" rel="noopener noreferrer"&gt;Whisper.net&lt;/a&gt;. If they want punctuation and filler-word cleanup, that goes through their &lt;em&gt;own&lt;/em&gt; local LLM — LM Studio or Ollama on localhost. The only network connection the app ever needs is to download the Whisper model files the first time. After that, it works just as well on a desert island with no Wi-Fi as it does at the office.&lt;/p&gt;

&lt;p&gt;It's not a toy voice-note recorder — it's a real dictation workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Continuous mode&lt;/strong&gt; listens and transcribes as you speak, chunking on silence&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Push-to-talk&lt;/strong&gt; holds a hotkey for precise, on-demand capture&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keyword activation&lt;/strong&gt; toggles listening with a spoken wake word&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom vocabulary&lt;/strong&gt; teaches it the names and jargon Whisper would otherwise mangle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local LLM post-processing&lt;/strong&gt; fixes capitalization, punctuation, "um"s, and misheard words — offline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architecture is what makes it pleasant to live with: a small headless &lt;strong&gt;daemon&lt;/strong&gt; owns the microphone and the model, and any controller — a full Avalonia GUI, a keyboard-only TUI, or the Windows WPF app — attaches to it over a private socket. Start the daemon once; dictate from whichever surface you're in.&lt;/p&gt;

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

&lt;p&gt;The app itself ships as self-contained desktop builds (no runtime installation needed):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Build&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Linux&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.AppImage&lt;/code&gt;, &lt;code&gt;.deb&lt;/code&gt; (with a systemd user service), portable &lt;code&gt;.tar.gz&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows 10/11&lt;/td&gt;
&lt;td&gt;portable &lt;code&gt;.zip&lt;/code&gt; with daemon auto-start script; MSIX buildable on a Windows host&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;The full source is on GitHub: &lt;a href="https://github.com/JamesDBartlett3/Loquacio" rel="noopener noreferrer"&gt;JamesDBartlett3/Loquacio&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/JamesDBartlett3/Loquacio.git
dotnet build &lt;span class="nt"&gt;-c&lt;/span&gt; Release
dotnet &lt;span class="nb"&gt;test &lt;/span&gt;Loquacio.Tests &lt;span class="nt"&gt;-c&lt;/span&gt; Release   &lt;span class="c"&gt;# 373 tests, all platforms&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;.NET 10, C#, MIT licensed. The test suite runs on Linux and Windows alike — including the daemon, IPC, and transcription pipeline.&lt;/p&gt;

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

&lt;p&gt;The core AI is &lt;strong&gt;Whisper&lt;/strong&gt;, OpenAI's open-source speech recognition model, running &lt;em&gt;inference locally&lt;/em&gt; via Whisper.net — no API, no account, no per-minute billing. The app downloads whichever open-weight model size fits the user's hardware (tiny through large-v3) and validates checksums, so a corrupted model can't silently produce garbage.&lt;/p&gt;

&lt;p&gt;The post-processing layer leans on the open &lt;strong&gt;OpenAI-compatible API shape&lt;/strong&gt; that LM Studio and Ollama expose locally: the same protocol the cloud services use, pointed at &lt;code&gt;localhost&lt;/code&gt;. That means the "smart cleanup" pass is swappable — any model they run locally works, and nothing is locked to one vendor.&lt;/p&gt;

&lt;p&gt;On the engineering side, the interesting decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Daemon-first architecture.&lt;/strong&gt; Audio capture and inference live in one long-running process; GUIs are thin clients. The dictation state machine (sessions, stage timeouts) means a controller crash never interrupts a transcription.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-platform by construction.&lt;/strong&gt; The core library is plain .NET; platform code (WASAPI on Windows, D-Bus desktop integration on Linux) is isolated at the edges. The whole test suite runs on Linux even though one controller is WPF.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Honest packaging.&lt;/strong&gt; Linux builds are cross-published on Linux (AppImage validated without FUSE, deb, tarball); the Windows zip is cross-built with &lt;code&gt;EnableWindowsTargeting&lt;/code&gt; and every &lt;code&gt;.exe&lt;/code&gt; verified as a real PE32+ binary before shipping.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Because voice is the most sensitive data type most people ever produce, and the default options all route it through someone's cloud. Open-source AI at the core changes that equation completely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy isn't a policy, it's a property.&lt;/strong&gt; There is no server to trust, no retention policy to read, no training opt-out to hunt for. The audio physically cannot leave the machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It works offline, forever.&lt;/strong&gt; No subscription, no rate limit, no deprecation. The app my coworkers run today will work identically in ten years.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The model is a setting, not a lock-in.&lt;/strong&gt; Whisper model sizes are a dropdown. The LLM cleanup layer speaks a standard local API. When a better open model ships next year, it's a swap, not a migration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero marginal cost.&lt;/strong&gt; My coworkers can dictate all day without anyone's meter running.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This project was built pair-programming style with local AI agents. The agents planned phases, wrote and reviewed code through a real PR process (every change merged via review, including a dependency CVE adjudication), ran the 373-test suite, and built the release artifacts — while the human steered. Fitting, for an app about talking to your computer instead of typing at it.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Overall&lt;/li&gt;
&lt;li&gt;Featured: Best use of open-source AI / local inference&lt;/li&gt;
&lt;/ul&gt;

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