<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Self-Hosting on Linux Colorado</title><link>https://www.linuxcolorado.com/categories/self-hosting/</link><description>Recent content in Self-Hosting on Linux Colorado</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Tue, 18 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://www.linuxcolorado.com/categories/self-hosting/index.xml" rel="self" type="application/rss+xml"/><item><title>Speaker-Diarized Call Transcription on a CPU — No Cloud, No GPU, No Hugging Face Token</title><link>https://www.linuxcolorado.com/post/2026-08-18-speaker-diarized-call-transcription/</link><pubDate>Tue, 18 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.linuxcolorado.com/post/2026-08-18-speaker-diarized-call-transcription/</guid><description>&lt;p&gt;I wanted a speaker-labeled, timestamped transcript of a two-person phone call — the kind an LLM can actually reason about (&amp;ldquo;what did the customer commit to?&amp;rdquo;, &amp;ldquo;when did the price come up?&amp;rdquo;) — without shipping the audio to a cloud speech-to-text service.&lt;/p&gt;
&lt;p&gt;One hard constraint shaped every decision: &lt;strong&gt;it all had to run on hardware already in the rack.&lt;/strong&gt; No new GPU, no API keys, no &amp;ldquo;just use the cloud for the hard part.&amp;rdquo; A 35-watt desktop chip that already earns its keep running other things.&lt;/p&gt;
&lt;p&gt;It worked. And, as usual, the interesting parts weren&amp;rsquo;t in the happy path — they were in &lt;em&gt;why the whisper I already had running couldn&amp;rsquo;t do the job&lt;/em&gt;, how to diarize speakers on a CPU with no Hugging Face token, and a genuinely great debugging story that ends with a &lt;strong&gt;114-byte file&lt;/strong&gt; quietly corrupting every timestamp in the system.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A note on the transcript examples below:&lt;/strong&gt; the real test call involved an actual third-party business and named individuals who never agreed to be quoted. Every name, company, and phone number in the excerpts here is &lt;strong&gt;synthetic&lt;/strong&gt; — invented for illustration. In many US states, Colorado included, recording calls and reusing what was said carries real legal weight. If you build one of these, redact before you publish. I&amp;rsquo;m practicing what I preach.&lt;/p&gt;
&lt;/blockquote&gt;</description></item><item><title>Cheap Phone Service and Whole-House Intercom with FreePBX + SignalWire</title><link>https://www.linuxcolorado.com/post/2026-08-18-freepbx-signalwire-home-phone/</link><pubDate>Sun, 16 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.linuxcolorado.com/post/2026-08-18-freepbx-signalwire-home-phone/</guid><description>&lt;p&gt;Business phone service — RingCentral and the like — runs $20–35 per seat per month, locks your desk phones to their firmware, and puts your dial tone at the mercy of someone else&amp;rsquo;s cloud. I replaced all of it with a self-hosted PBX that costs a few dollars a month in actual usage, keeps every phone on hardware I own, and adds something the commercial offerings either charge extra for or simply don&amp;rsquo;t do: &lt;strong&gt;push-to-talk intercom between rooms.&lt;/strong&gt; Dial the kitchen, it answers itself on speaker, you talk.&lt;/p&gt;
&lt;p&gt;The whole thing is four Docker containers on one host, one DNS record on another, and a single SIP trunk in the cloud. Everything else is a text file.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A note on the examples:&lt;/strong&gt; this runs on my real network with real family phone numbers on it. Every phone number, personal name, and account identifier below is &lt;strong&gt;synthetic&lt;/strong&gt; — invented for illustration and drawn from the &lt;code&gt;555-01xx&lt;/code&gt; range reserved for fiction. The &lt;em&gt;configuration&lt;/em&gt; is real and copied verbatim from the running system; only the personal data is swapped. If you build one of these, keep your own credentials and family numbers out of your blog. I&amp;rsquo;m practicing what I preach.&lt;/p&gt;
&lt;/blockquote&gt;</description></item><item><title>A Valid TLS Cert for a LAN-Only Home Assistant: Traefik, DNS-01, and Split-Horizon DNS</title><link>https://www.linuxcolorado.com/post/2026-08-18-home-assistant-traefik-tls/</link><pubDate>Sat, 15 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.linuxcolorado.com/post/2026-08-18-home-assistant-traefik-tls/</guid><description>&lt;p&gt;Here&amp;rsquo;s a puzzle that trips up a lot of homelabbers: you want a &lt;strong&gt;publicly-trusted&lt;/strong&gt; TLS certificate for a service that is &lt;strong&gt;only ever reachable on your LAN.&lt;/strong&gt; No port forwarding, no exposing the box to the internet — but also no browser warnings, no self-signed-cert clicking-through, and no private CA to install on every device.&lt;/p&gt;
&lt;p&gt;The specific thing that forced my hand: I wanted to connect Claude.ai&amp;rsquo;s remote MCP connector to my &lt;strong&gt;Home Assistant&lt;/strong&gt; instance, and that connector flatly &lt;strong&gt;refuses plain HTTP.&lt;/strong&gt; It demands a valid &lt;code&gt;https://&lt;/code&gt; endpoint. My HA is a sealed Green appliance at &lt;code&gt;192.168.1.18:8123&lt;/code&gt;, LAN-only, and I had no intention of exposing it to the world.&lt;/p&gt;
&lt;p&gt;The answer is a nice combination of three ideas — a &lt;strong&gt;Let&amp;rsquo;s Encrypt DNS-01 challenge&lt;/strong&gt;, a &lt;strong&gt;wildcard certificate&lt;/strong&gt;, and &lt;strong&gt;split-horizon DNS&lt;/strong&gt; — wired together with Traefik. This post is the worked example.&lt;/p&gt;</description></item><item><title>Letting Claude Read My Firewall: an OPNsense MCP Server, and What It Found on My Network</title><link>https://www.linuxcolorado.com/post/2026-08-18-opnsense-mcp-network-forensics/</link><pubDate>Fri, 14 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.linuxcolorado.com/post/2026-08-18-opnsense-mcp-network-forensics/</guid><description>&lt;p&gt;I gave Claude a read-only window into my firewall. Not &amp;ldquo;pasted some logs into a chat&amp;rdquo; — an actual &lt;a href="https://modelcontextprotocol.io"&gt;Model Context Protocol&lt;/a&gt; server wrapping the &lt;strong&gt;OPNsense&lt;/strong&gt; API, so Claude Code could call &lt;code&gt;leasesSearchLease&lt;/code&gt;, &lt;code&gt;dnsReverseLookup&lt;/code&gt;, and dozens of other firewall functions on demand. Then I pointed it at a simple question — &lt;em&gt;what is actually on my network, and where does it all phone home?&lt;/em&gt; — and got a genuinely uncomfortable answer.&lt;/p&gt;
&lt;p&gt;This post is two things: how to stand up an OPNsense MCP server in Docker &lt;strong&gt;safely&lt;/strong&gt;, and the little network-forensics session it enabled, which is the real reason to build one.&lt;/p&gt;</description></item><item><title>Two Ways My Self-Hosted Immich Broke — and Neither Was Corrupt Data</title><link>https://www.linuxcolorado.com/post/2026-08-18-immich-flaky-mount-and-boot-loop/</link><pubDate>Thu, 13 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.linuxcolorado.com/post/2026-08-18-immich-flaky-mount-and-boot-loop/</guid><description>&lt;p&gt;I self-host &lt;a href="https://immich.app"&gt;Immich&lt;/a&gt; for my photo library, and it has broken on me in two completely different ways — both instructive, and both sharing a reassuring punchline: &lt;strong&gt;the photos were always fine.&lt;/strong&gt; The failures were in the plumbing around them, not the data.&lt;/p&gt;
&lt;p&gt;The first was a storage problem wearing a data-corruption costume: thousands of &amp;ldquo;unsupported image format&amp;rdquo; and &amp;ldquo;input file is missing&amp;rdquo; errors for files that were perfectly healthy. The second was a self-inflicted supply-chain problem: an overnight auto-update yanked the database extension out from under the server and put it in a boot loop. This post is both stories, because together they&amp;rsquo;re a decent field guide to operating Immich in a homelab.&lt;/p&gt;</description></item><item><title>After the Rip: Auto-Naming a Home Media Library for Jellyfin with Python, TMDB, and ffprobe</title><link>https://www.linuxcolorado.com/post/2026-08-18-jellyfin-media-automation-arm/</link><pubDate>Wed, 12 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.linuxcolorado.com/post/2026-08-18-jellyfin-media-automation-arm/</guid><description>&lt;p&gt;Getting video &lt;em&gt;off&lt;/em&gt; a disc is the part everyone talks about. The part that actually eats your evenings is everything &lt;em&gt;after&lt;/em&gt;: a folder full of &lt;code&gt;title_t00.mkv&lt;/code&gt;, &lt;code&gt;disc1/&lt;/code&gt;, &lt;code&gt;C3_t01.mkv&lt;/code&gt; files that mean nothing to a media server. &lt;a href="https://jellyfin.org"&gt;Jellyfin&lt;/a&gt; wants very specific names and folder layouts, and if you don&amp;rsquo;t give them to it, you get &amp;ldquo;Unknown Movie,&amp;rdquo; mismatched episodes, and bonus features scattered as phantom entries.&lt;/p&gt;
&lt;p&gt;So I extended a post-processing step into a proper Python pipeline that takes whatever came out of my ripping setup and turns it into a Jellyfin-perfect library: correct movie names with IMDb IDs, TV episodes matched to the right &lt;code&gt;SxxExx&lt;/code&gt;, extras bucketed into the folders Jellyfin recognizes, then rsynced to the NAS and scanned in — with an ntfy ping at the end. This post is about that pipeline. &lt;strong&gt;It is deliberately not about disc decryption&lt;/strong&gt; — it starts the moment you have plain &lt;code&gt;.mkv&lt;/code&gt; files.&lt;/p&gt;</description></item><item><title>jf-barcode-search: Scanning Barcodes to Query Jellyfin — and a Checklist for Open-Sourcing a Homelab Repo</title><link>https://www.linuxcolorado.com/post/2026-08-18-jf-barcode-search-open-source/</link><pubDate>Tue, 11 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.linuxcolorado.com/post/2026-08-18-jf-barcode-search-open-source/</guid><description>&lt;p&gt;Here&amp;rsquo;s a problem specific to people who rip their own discs: you&amp;rsquo;re standing in a thrift store holding a $3 Blu-ray, and you genuinely cannot remember whether it&amp;rsquo;s already in your library. Pull out your phone, squint at a media app, type the title, hope you spelled it like the metadata does… by which point you&amp;rsquo;ve put it back.&lt;/p&gt;
&lt;p&gt;So I built &lt;strong&gt;jf-barcode-search&lt;/strong&gt;: point your phone camera at the barcode on the case, and it tells you instantly whether that title is already in your &lt;a href="https://jellyfin.org"&gt;Jellyfin&lt;/a&gt; library. It&amp;rsquo;s a small Flask app, and this post covers both what it does and — because I decided to open-source it — the &lt;strong&gt;pre-flight review that makes a homelab repo safe to publish&lt;/strong&gt;, which is a checklist worth having regardless of what you&amp;rsquo;re releasing.&lt;/p&gt;</description></item><item><title>/ipad-internet off: A Claude Code Skill That Cuts One Device's Internet at the Firewall</title><link>https://www.linuxcolorado.com/post/2026-08-18-ipad-internet-firewall-skill/</link><pubDate>Mon, 10 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.linuxcolorado.com/post/2026-08-18-ipad-internet-firewall-skill/</guid><description>&lt;p&gt;I wanted one command — &lt;code&gt;/ipad-internet off&lt;/code&gt; — that instantly cuts the household iPad&amp;rsquo;s internet, and &lt;code&gt;/ipad-internet on&lt;/code&gt; to give it back. Simple ask. The interesting part is doing it &lt;em&gt;correctly&lt;/em&gt;: instantly (no waiting on a config save), reversibly, without disturbing the LAN (AirPlay, printers, local media should all keep working), and — most importantly — in a way that &lt;strong&gt;can never accidentally knock a different device offline.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It ended up as a &lt;a href="https://docs.claude.com/en/docs/claude-code"&gt;Claude Code&lt;/a&gt; skill backed by a careful bit of &lt;strong&gt;OPNsense&lt;/strong&gt; / &lt;code&gt;pf&lt;/code&gt; design. This post is about that design: why it uses a pf table instead of editing the config, how it survives the iPad&amp;rsquo;s shifting IP and Apple&amp;rsquo;s private Wi-Fi MAC, and the ownership guard that makes the &amp;ldquo;wrong device&amp;rdquo; failure mode structurally impossible.&lt;/p&gt;</description></item><item><title>Teaching the House to Announce the Mail Truck: A Zero-Shot CLIP Classifier on the Homelab</title><link>https://www.linuxcolorado.com/post/2026-08-17-mail-truck-clip-classifier/</link><pubDate>Sun, 09 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.linuxcolorado.com/post/2026-08-17-mail-truck-clip-classifier/</guid><description>&lt;p&gt;I wanted my house to say, out loud, &amp;ldquo;the mail truck is out front&amp;rdquo; — the moment the USPS truck pulls up, spoken through the same Home Assistant TTS pipeline that runs the rest of the place. Not &amp;ldquo;a vehicle was detected.&amp;rdquo; Specifically the mail truck.&lt;/p&gt;
&lt;p&gt;The gap between those two sentences is the whole project. My NVR (&lt;a href="https://frigate.video"&gt;Frigate&lt;/a&gt;) is very good at &amp;ldquo;there&amp;rsquo;s a truck in the driveway zone&amp;rdquo; and completely incapable of &amp;ldquo;that&amp;rsquo;s a USPS LLV.&amp;rdquo; Closing that gap meant adding a small &lt;strong&gt;second-stage classifier&lt;/strong&gt; that looks at the snapshot Frigate already captured and decides &lt;em&gt;what kind&lt;/em&gt; of truck it is — running on hardware I already own, with no cloud vision API. It ended up as a &lt;strong&gt;zero-shot CLIP&lt;/strong&gt; classifier, and along the way it picked up a second job I never planned: catching the garbage truck too.&lt;/p&gt;</description></item><item><title>Moving My ADS-B Receiver Outdoors: Ultrafeeder on a Raspberry Pi, Done Right</title><link>https://www.linuxcolorado.com/post/2026-08-16-adsb-outdoor-raspberry-pi/</link><pubDate>Sat, 08 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.linuxcolorado.com/post/2026-08-16-adsb-outdoor-raspberry-pi/</guid><description>&lt;p&gt;I run an ADS-B receiver at home — it decodes the transponder broadcasts from aircraft overhead, plots them on a live map, and feeds the data to FlightAware. It started life the lazy way: an RTL-SDR dongle plugged into a server indoors, with a run of coax to an antenna. That works, but it&amp;rsquo;s the &lt;em&gt;wrong&lt;/em&gt; topology if you want range, and I wanted to move the whole thing up high and outdoors.&lt;/p&gt;
&lt;p&gt;Two things came out of that project worth writing down. First, a diagnostic detour that taught me the map wasn&amp;rsquo;t lying to me even though it looked like it was. Second — the real content — how to relocate an SDR receiver to the top of a mast &lt;strong&gt;without breaking MLAT&lt;/strong&gt;, which is the part most &amp;ldquo;just put a Pi outside&amp;rdquo; guides skip.&lt;/p&gt;</description></item><item><title>Aiming an OTA Antenna With Data: Prometheus + Grafana on an HDHomeRun FLEX 4K</title><link>https://www.linuxcolorado.com/post/2026-08-15-hdhomerun-antenna-aiming-grafana/</link><pubDate>Fri, 07 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.linuxcolorado.com/post/2026-08-15-hdhomerun-antenna-aiming-grafana/</guid><description>&lt;p&gt;Aiming an over-the-air TV antenna is traditionally a two-person job with a lot of yelling: one person on the roof rotating the mast, one inside shouting &amp;ldquo;better… worse… BETTER… no, worse again.&amp;rdquo; The feedback loop is slow, the signal bar in the tuner&amp;rsquo;s web UI updates lazily, and you can never quite tell whether that last nudge helped.&lt;/p&gt;
&lt;p&gt;I wanted a &lt;em&gt;tight&lt;/em&gt; feedback loop: a live graph, updating every few seconds, of the exact signal metrics that matter — so I could rotate the antenna and watch a line move in real time. My tuner is an &lt;strong&gt;HDHomeRun FLEX 4K&lt;/strong&gt;, and it turns out you can scrape per-tuner signal quality straight into &lt;strong&gt;Prometheus&lt;/strong&gt; and chart it in &lt;strong&gt;Grafana&lt;/strong&gt;. This post is how I built that, the one exporter that actually does the job, and the surprise ending where the data explained a &amp;ldquo;broken&amp;rdquo; channel that wasn&amp;rsquo;t broken at all.&lt;/p&gt;</description></item><item><title>"0 Detections, Hundreds of Alerts": The Frigate Terminology Trap That Isn't a Bug</title><link>https://www.linuxcolorado.com/post/2026-08-14-frigate-alerts-vs-detections/</link><pubDate>Thu, 06 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.linuxcolorado.com/post/2026-08-14-frigate-alerts-vs-detections/</guid><description>&lt;p&gt;I opened my &lt;a href="https://frigate.video"&gt;Frigate&lt;/a&gt; dashboard one morning and my stomach dropped: &lt;strong&gt;0 detections, hundreds of alerts.&lt;/strong&gt; My first read was the obvious one — the object detector had fallen over, and Frigate was now firing blind, alerting on raw motion instead of actual objects.&lt;/p&gt;
&lt;p&gt;That read was completely wrong. Nothing had broken. The detector was healthy, running OpenVINO inference at ~10 ms per frame the entire time. What had actually happened is that I didn&amp;rsquo;t understand what the words &lt;em&gt;&amp;ldquo;Alert&amp;rdquo;&lt;/em&gt; and &lt;em&gt;&amp;ldquo;Detection&amp;rdquo;&lt;/em&gt; mean in modern Frigate — and once I did, the &amp;ldquo;outage&amp;rdquo; evaporated and turned into a five-minute config change.&lt;/p&gt;
&lt;p&gt;This is a post about a debugging story with a satisfying anticlimax, and about a genuinely confusing bit of Frigate&amp;rsquo;s UI vocabulary that trips up a lot of people running 0.14 and later.&lt;/p&gt;</description></item><item><title>Building a Headless AI Workstation: Ubuntu Server + RTX 3060 + Ollama, Zero-Touch from a USB Stick</title><link>https://www.linuxcolorado.com/post/2026-08-05-ai-workstation-rtx3060-ollama/</link><pubDate>Wed, 05 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.linuxcolorado.com/post/2026-08-05-ai-workstation-rtx3060-ollama/</guid><description>&lt;p&gt;Several of my homelab projects want a local GPU for inference — running a vision LLM for OCR, offloading work that would otherwise hit a cloud API, keeping a small model resident and fast. So I built a dedicated box for it: a &lt;strong&gt;Dell Precision 3640&lt;/strong&gt; (i3-10105F, 16 GB) with a &lt;strong&gt;Gigabyte RTX 3060 12 GB&lt;/strong&gt;, running &lt;strong&gt;Ubuntu Server&lt;/strong&gt; and serving a vision model through &lt;strong&gt;Ollama&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Two things made this worth writing up. First, the actual GPU-serving setup has a few non-obvious choices (which driver, no CUDA Toolkit, exposing the port safely). Second — the fun part — I made the whole install &lt;strong&gt;zero-touch&lt;/strong&gt;: plug in a USB stick, walk away, and the box comes up on a &lt;strong&gt;static IP with SSH pubkey auth ready&lt;/strong&gt;, no monitor or keyboard ever attached. This post covers both, and both live as reusable docs/scripts in my &lt;a href="https://github.com/vlouvet/infra-config"&gt;&lt;code&gt;infra-config&lt;/code&gt;&lt;/a&gt; repo.&lt;/p&gt;</description></item><item><title>Backing Up a Homelab as Code: Docker Configs to a Private Git Repo, Without Leaking Secrets</title><link>https://www.linuxcolorado.com/post/2026-08-04-infra-config-backup-as-code/</link><pubDate>Tue, 04 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.linuxcolorado.com/post/2026-08-04-infra-config-backup-as-code/</guid><description>&lt;p&gt;If my main Docker host died tomorrow, how fast could I rebuild it? For a long time the honest answer was &amp;ldquo;slowly, and from memory.&amp;rdquo; The fix is to treat the box&amp;rsquo;s configuration as &lt;strong&gt;code&lt;/strong&gt;: every &lt;code&gt;docker-compose.yml&lt;/code&gt;, Dockerfile, and config file committed to a private git repo, so reimaging is a &lt;code&gt;git clone&lt;/code&gt; and a handful of &lt;code&gt;docker compose up&lt;/code&gt; commands.&lt;/p&gt;
&lt;p&gt;The trap is that a live Docker tree is a minefield of secrets — &lt;code&gt;.env&lt;/code&gt; files, TLS private keys, API tokens hardcoded into compose files — and pushing any of them to GitHub, even a private repo, is a bell you can&amp;rsquo;t fully un-ring. This post is the repeatable procedure I landed on: what to commit, what to never commit, and the automated checks that keep the second category out.&lt;/p&gt;</description></item><item><title>"My NAS Is Out of RAM and My Download Is Stuck" — Two Homelab Myths, Debunked</title><link>https://www.linuxcolorado.com/post/2026-08-03-nas-ram-and-stuck-arr-imports/</link><pubDate>Mon, 03 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.linuxcolorado.com/post/2026-08-03-nas-ram-and-stuck-arr-imports/</guid><description>&lt;p&gt;Two things happened on the same day that &lt;em&gt;looked&lt;/em&gt; like problems and weren&amp;rsquo;t — at least not the problems they appeared to be. My NAS was reporting almost all its RAM in use, which sounds like a leak or an imminent crash. And a TV show I&amp;rsquo;d grabbed through &lt;a href="https://www.lunasea.app/"&gt;LunaSea&lt;/a&gt; on my phone had downloaded fine but then &amp;ldquo;wouldn&amp;rsquo;t import&amp;rdquo; into the library, which sounds like a broken automation pipeline.&lt;/p&gt;
&lt;p&gt;Both are among the most common false alarms in a self-hosted media stack. Neither was what it looked like. Here&amp;rsquo;s what was actually going on, and the real fixes.&lt;/p&gt;</description></item><item><title>The Mail Truck Classifier Cried Wolf: Tuning Zero-Shot CLIP With Real Data</title><link>https://www.linuxcolorado.com/post/2026-08-02-mail-truck-classifier-tuning/</link><pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.linuxcolorado.com/post/2026-08-02-mail-truck-classifier-tuning/</guid><description>&lt;p&gt;A while back I &lt;a href="https://www.linuxcolorado.com/post/2026-08-17-mail-truck-clip-classifier/"&gt;taught my house to announce the mail truck&lt;/a&gt;: Frigate spots a vehicle out front, a small service crops the snapshot and runs zero-shot &lt;strong&gt;CLIP&lt;/strong&gt; against a list of text prompts, and if it decides &amp;ldquo;USPS truck&amp;rdquo; or &amp;ldquo;garbage truck,&amp;rdquo; Home Assistant says so out loud through Piper. That post ended on an optimistic note — a garbage truck scoring &lt;code&gt;p_trash 0.995&lt;/code&gt;, and a line about how a labeled dataset for future tuning would &amp;ldquo;build itself from real events.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;This is the reckoning with that optimism.&lt;/p&gt;
&lt;p&gt;Because the classifier worked, and then it would not shut up. &lt;strong&gt;143 garbage-truck announcements in seven weeks&lt;/strong&gt;, on a street where the garbage truck comes exactly &lt;em&gt;once a week&lt;/em&gt;. The house had become the boy who cried wolf, and my family had — correctly — started ignoring it. This post is about actually fixing that: what 200 real detections showed, why the obvious fix is a trap, and the one idea worth stealing even if you never touch CLIP.&lt;/p&gt;</description></item></channel></rss>