I was fed up with spending 45 mins reading multiple newsletters every morning. A developer built Slothreader, an offline-first newsletter compiler that ingests .eml/.html files and IMAP inboxes, strips tracking pixels and sponsor banners with BeautifulSoup, then uses a locally running Gemma 2 model to cluster topics, deduplicate stories and extract signal into a Markdown morning briefing. The pipeline is instrumented with Sentry Agent Tracing (send_default_pii=False) to monitor time-to-first-token and local model latency, and computes a "Sloth Badge" estimating minutes saved from raw word counts. This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady https://dev.to/challenges/hacktoberfest-week3-2026-10-19 Each time I come across a compelling article, I end up subscribing to the author's newsletter. I am already subscribed to Aeon, Ali Abdaal's newsletter, ByteByteGo, The Pragmatic Engineer and I am sure this list is going to get longer. But more often than not, these newsletters end up collecting dust in my inbox, but I can't seem to bring myself to unsubscribe because I end up thinking, "What if some important news comes up and I end up falling behind?" But that important news seems to come up few and far in between. I have finally built the solution to this problem- Slothreader, an offline-first newsletter compiler and multi-source deduplicator . It channels your inner sloth by handling the mental heavy lifting while you sleep: .eml/.html files. Newsletters folder. send default pii=False . The demo video is as follows: The codebase for Slothreader is given below: "Sloths conserve energy because the world moves too fast. Slothreader lets your computer do the reading so you can do the living." Modern developers and knowledge workers suffer from chronic newsletter debt : 1,842 unread , producing background anxiety. Slothreader was designed around a strict guiding principle: energy conservation for the user, zero cloud data leakage, and zero recurring token costs. Instead of building another cloud API wrapper, the entire intelligence pipeline runs locally on-device. 1. The Open-Source AI Stack 2. Code vs. Model Division of Labor Deterministic Python: Uses imaplib with TLS read-only BODY.PEEK and BeautifulSoup to strip DOM junk, tracking pixels, and regex-matched sponsor banners Sponsor , Presented by... . We never waste model compute on tasks standard code can solve in milliseconds. Gemma 2 Engine: Ingests only clean technical text to perform topic clustering, deduplication, and signal extraction. 3. Observability with Sentry Agent Tracing I instrumented the agent pipeline with Sentry Agent Tracing sentry-sdk to track performance across custom spans email.clean , gemma.deduplicate , gazette.render . This lets me monitor Time-To-First-Token TTFT , token volume, and local model latency—with send default pii=False ensuring private email content never touches Sentry servers. 4. The Sloth Gazette & Badge The engine renders a morning briefing to the terminal with rich and exports an offline Markdown gazette. It automatically computes a Sloth Badge e.g., 18,000 raw words → 450 summary words = ~88 minutes saved , rewarding you for letting the machine do the reading. Building Slothreader with open-weight AI wasn't just a design choice— it was the only way this project could ethically and practically exist. The reasons why open innovation matters are as follows: Your email inbox holds the keys to your digital identity—password resets, financial receipts, and private correspondence. Handing raw email streams to commercial cloud APIs is an unacceptable privacy gamble. With Google Gemma 2 running locally on-device, inference happens entirely in RAM. Not a single byte of email data ever leaves your machine. Ingesting 15 bloated newsletters daily burns hundreds raw tokens every morning. On closed cloud APIs, that makes reading quiet costly. Open weights keeps it free forever. Closed APIs fail the moment your Wi-Fi drops. Slothreader works in full airplane mode— on a train, off-grid, or during an outage—with zero rate limits, latency spikes, or corporate vendor lock-in. My agent session with Antigravity and Gemini CLI is as follows: { "DirectoryPath": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\"", "toolAction": "\"Listing project directory\"", "toolSummary": "\"List directory contents\"" } Executed successfully $ {"CommandLine": "\"git status; git log -n 5\"", "Cwd": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\"", "WaitMsBeforeAsync": "5000", "toolAction": "\"Checking git status\"", "toolSummary": "\"Git status and log\""} Executed successfully $ {"CommandLine": "\"git ls-remote origin\"", "Cwd": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\"", "WaitMsBeforeAsync": "5000", "toolAction": "\"Checking remote branches\"", "toolSummary": "\"Git remote check\""} Executed successfully { "DirectoryPath": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\"", "toolAction": "\"Listing parent projects directory\"", "toolSummary": "\"List projects directory\"" } Executed successfully $ {"CommandLine": "\"Get-ChildItem -Force\"", "Cwd": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\"", "WaitMsBeforeAsync": "3000", "toolAction": "\"Listing all files in workspace\"", "toolSummary": "\"List workspace files\""} Executed successfully {"questions": " {\"is multi select\":false,\"options\": \" Recommended Scaffold the AI Agent Loop documentation files AGENTS.md, ENGINEERING PLAYBOOK.md, PROGRESS.md, etc. and let's define the PRD for Slothreader together.\",\"I already have product requirements / a PRD for Slothreader that I want to share first.\",\"Set up a standard starter web app and the agent loop files simultaneously.\" ,\"question\":\"How would you like to kick off the Slothreader project with this AI Agent Loop framew Executed successfully Please go ahead and share your product requirements or PRD for Slothreader Once you provide it, we will kick off Step 12 "Build your own in 8 steps" from the guide: 1. PRD.md : Capture the product intent, scope, and target user experience. 2. ARCHITECTURE.md : Define the system components, technical structure, and locked decisions. 3. ENGINEERING PLAYBOOK.md : Set up the operating manual the 9-step loop, Ready/Done definitions, stop signs . 4. AGENTS.md : Create the concise entry door file with the 8 golden rules and document index. 5. BACKLOG.md : Organize the roadmap into incremental phases with small, testable slices and approval locks 🔒 . 6. PROGRESS.md : Establish the running memory log Status, Done, Next, Decisions Log, Notes . Whenever you're ready, paste the requirements or describe the details. ~.gemini\antigravity\scratch\slothreader\SLOTHREADER MASTER GUIDE.md { "AbsolutePath": "\"c:\\\\Users\\\\snigd\\\\.gemini\\\\antigravity\\\\scratch\\\\slothreader\\\\SLOTHREADER MASTER GUIDE.md\"", "EndLine": "800", "StartLine": "1", "toolAction": "\"Reading Slothreader master guide\"", "toolSummary": "\"View Slothreader master guide\"" } Executed successfully $ {"CommandLine": "\"Get-Content -Path \\\"C:\\\\Users\\\\snigd\\\\.gemini\\\\antigravity\\\\scratch\\\\slothreader\\\\SLOTHREADER MASTER GUIDE.md\\\" -Head 100\"", "Cwd": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\"", "WaitMsBeforeAsync": "5000", "toolAction": "\"Reading file from scratch directory\"", "toolSummary": "\"Read initial lines of SLOTHREADER MASTER GUIDE.md\""} Executed successfully $ {"CommandLine": "\"Get-Content -Path \\\"C:\\\\Users\\\\snigd\\\\.gemini\\\\antigravity\\\\scratch\\\\slothreader\\\\SLOTHREADER MASTER GUIDE.md\\\" -Skip 100 -Head 150\"", "Cwd": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\"", "WaitMsBeforeAsync": "5000", "toolAction": "\"Reading next chunk of master guide\"", "toolSummary": "\"Read SLOTHREADER MASTER GUIDE.md lines 101-250\""} Executed successfully $ {"CommandLine": "\"Get-Content -Path \\\"C:\\\\Users\\\\snigd\\\\.gemini\\\\antigravity\\\\scratch\\\\slothreader\\\\SLOTHREADER MASTER GUIDE.md\\\" | Select-Object -Skip 100 -First 150\"", "Cwd": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\"", "WaitMsBeforeAsync": "5000", "toolAction": "\"Reading lines 101 to 250\"", "toolSummary": "\"Read lines 101-250 of master guide\""} Executed successfully $ {"CommandLine": "\"Get-Content -Path \\\"C:\\\\Users\\\\snigd\\\\.gemini\\\\antigravity\\\\scratch\\\\slothreader\\\\SLOTHREADER MASTER GUIDE.md\\\" | Select-Object -Skip 230 -First 150\"", "Cwd": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\"", "WaitMsBeforeAsync": "5000", "toolAction": "\"Reading lines 231 to 380\"", "toolSummary": "\"Read SLOTHREADER MASTER GUIDE.md lines 231-380\""} Executed successfully $ {"CommandLine": "\"Get-Content -Path \\\"C:\\\\Users\\\\snigd\\\\.gemini\\\\antigravity\\\\scratch\\\\slothreader\\\\SLOTHREADER MASTER GUIDE.md\\\" | Select-Object -Skip 380 -First 180\"", "Cwd": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\"", "WaitMsBeforeAsync": "5000", "toolAction": "\"Reading lines 381 to 560\"", "toolSummary": "\"Read SLOTHREADER MASTER GUIDE.md lines 381 to end\""} Executed successfully $ {"CommandLine": "\"python --version; pip --version; ollama --version\"", "Cwd": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\"", "WaitMsBeforeAsync": "5000", "toolAction": "\"Checking Python and Ollama versions\"", "toolSummary": "\"Check environment tools\""} Executed successfully I've launched the environment check to verify Python and Ollama on your system, and will proceed as soon as the results are in. $ {"CommandLine": "\"ollama list\"", "Cwd": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\"", "WaitMsBeforeAsync": "5000", "toolAction": "\"Listing Ollama models\"", "toolSummary": "\"Check local Ollama models\""} Executed successfully {"CodeContent": "\" Product Requirements Document PRD \u2014 Slothreader\\n\\n Slothreader is the zero-effort, local-first morning gazette that rewards information laziness. \\n\\n---\\n\\n 1. Executive Summary & Vision\\n\\nDevelopers and technical knowledge workers face chronic newsletter debt : dozens of subscriptions accumulating thousands of unread emails. When major events happen e.g., a major framework release or security vulnerability , multiple newsletters cover the same st Executed successfully {"CodeContent": "\" Architecture & Technical Design \u2014 Slothreader\\n\\n Offline-first, privacy-preserving newsletter compiler powered by local Gemma 2 and Sentry Agent Tracing. \\n\\n---\\n\\n 1. System Overview\\n\\n text\\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2 Executed successfully {"CodeContent": "\" Engineering Playbook \u2014 Slothreader\\n\\n The Operating Manual and Engineering Manager for Slothreader. \\n This playbook governs how we build, how we test, when we stop, and how we preserve memory across sessions.\\n\\n---\\n\\n 1. The Three Roles\\n\\n| Role | Who | What They Own |\\n|---|---|---|\\n| Product Owner | You the Human | Priorities, approvals, scope changes, and anything risky, costly, or visible to the outside world. Final say on all tradeoffs Executed successfully {"CodeContent": "\" AGENTS.md \u2014 The Front Door\\n\\n Welcome to Slothreader . Read this document completely at the start of every session.\\n\\n---\\n\\n 1. Read the Playbook First\\nBefore undertaking any implementation, read ENGINEERING PLAYBOOK.md file:///~/OneDrive/Documents/Projects/Slothreader/ENGINEERING PLAYBOOK.md . It is your operating manual and engineering manager: it defines the 9-step loop, Ready/Done definitions, and stop signs.\\n\\n---\\n\\n 2. Wha Executed successfully php { "CodeContent": "\"< -- Automatically points to the front door AGENTS.md -- \\nSee AGENTS.md AGENTS.md for instructions, golden rules, architecture, and documentation map.\\n\"", "Description": "\"Create CLAUDE.md pointing directly to AGENTS.md\"", "Overwrite": "true", "TargetFile": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\\\\CLAUDE.md\"", "toolAction": "\"Creating CLAUDE.md\"", "toolSummary": "\"Create CLAUDE.md\"" } Executed successfully {"CodeContent": "\" Product Backlog \u2014 Slothreader\\n\\n Organized into phases with clear exit goals. Each task is a small, testable slice.\\n Items marked with \ud83d\udd12 require explicit Product Owner approval before proceeding.\\n\\n---\\n\\n Phase 1: Environment, Data Schemas & Fixtures\\n Exit Goal: Modern Python environment configured, Pydantic data schemas established, and 4 realistic sample newsletters created as test fixtures.\\n\\n- 1.1 Project Setup & Packaging: Executed successfully {"CodeContent": "\" Progress & Project Memory \u2014 Slothreader\\n\\n \\\"You don't carry memory between sessions. The docs do.\\\" \\n This file is updated at the conclusion of every slice and session.\\n\\n---\\n\\n 1. Current Status\\n\\n- Phase Active: Phase 1 Environment, Data Schemas & Fixtures \\n- Current Sprint: Kickoff & Documentation Scaffolding\\n- Build Status: Scaffolding complete; ready for implementation slices.\\n\\n---\\n\\n 2. What's Done\\n\\n 2026- Executed successfully {"CodeContent": "\" Documentation Index & Paper Trail \u2014 Slothreader\\n\\n This directory houses the formal paper trail for Slothreader as specified in the AI Agent Loop operating manual.\\n\\n---\\n\\n Directory Organization\\n\\n- adr/ adr/ : Architecture Decision Records ADRs . Documents why a particular architectural choice was made, the context, alternatives considered, and consequences.\\n- stories/ stories/ : Feature requirements and user stories linking PRD goa Executed successfully {"CodeContent": "\" ADR 001: Local-First Inference via Ollama\\n\\n Status\\nAccepted\\n\\n Context\\nDevelopers' email inboxes contain proprietary code snippets, password reset links, personal correspondence, and confidential work discussions. Conventional AI summarization products require sending this raw text to cloud APIs such as OpenAI or Anthropic , which introduces severe privacy risks, potential data leakage, and ongoing subscription costs.\\n\\n Decision\\nSlothreader will perfo Executed successfully {"CodeContent": "\" ADR 002: Deterministic Pre-Filtering for Fluff and Sponsors\\n\\n Status\\nAccepted\\n\\n Context\\nTechnical newsletters often contain 40% to 60% non-content: HTML navigation blocks, social share buttons, tracking pixels, unsubscribe links, and prominent sponsor advertisements Sponsor , Sponsored by... , etc. . Passing raw, uncleaned newsletter HTML directly into an LLM context window causes token bloat, increases inference latency, and risks the LLM mistakenly tre Executed successfully {"CodeContent": "\" Python\\n pycache /\\n .py cod \\n $py.class\\n .so\\n.Python\\nenv/\\nvenv/\\n.venv/\\nbuild/\\ndevelop-eggs/\\ndist/\\ndownloads/\\neggs/\\n.eggs/\\nlib/\\nlib64/\\nparts/\\nsdist/\\nvar/\\nwheels/\\n .egg-info/\\n.installed.cfg\\n .egg\\n\\n Secrets & Environment\\n.env\\n .pem\\n .key\\n\\n Generated outputs\\nGAZETTE- .md\\ngazette.html\\n\\n IDE & OS\\n.vscode/\\n.idea/\\n.DS Store\\nThumbs.db\\n\\n Test & coverage\\n.pytest cache/\\n.coverage\\nhtmlcov/\\n\"", " Executed successfully {"CodeContent": "\" Slothreader Environment Configuration\\n Copy this file to .env and adjust values as needed.\\n\\n Sentry Agent Tracing DSN Optional for local testing; telemetry is mocked safely if omitted \\nSENTRY DSN=\\\"\\\"\\n\\n Local Ollama Host & Model\\nOLLAMA HOST=\\\"http://localhost:11434\\\"\\nGEMMA MODEL=\\\"gemma2:2b\\\"\\n\\n Live IMAP Configuration Only required when using --live mode; NOT needed for --demo mode \\nIMAP SERVER=\\\"imap.gmail.com\\\"\\nIMAP PORT=\\\"99 Executed successfully {"CodeContent": "\" build-system \\nrequires = \\\"setuptools =61.0\\\" \\nbuild-backend = \\\"setuptools.build meta\\\"\\n\\n project \\nname = \\\"slothreader\\\"\\nversion = \\\"0.1.0\\\"\\ndescription = \\\"The zero-effort, local-first morning gazette that rewards information laziness.\\\"\\nreadme = \\\"README.md\\\"\\nrequires-python = \\\" =3.10\\\"\\nlicense = { text = \\\"Apache-2.0\\\" }\\nauthors = \\n { name = \\\"Slothreader Contributors\\\" }\\n \\ndependencies = \\n \\\"b Executed successfully $ {"CommandLine": "\"git status\"", "Cwd": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\"", "WaitMsBeforeAsync": "3000", "toolAction": "\"Checking git status\"", "toolSummary": "\"Check git status\""} Executed successfully $ {"CommandLine": "\"python -m pip list\"", "Cwd": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\"", "WaitMsBeforeAsync": "5000", "toolAction": "\"Checking installed Python packages\"", "toolSummary": "\"List installed Python packages\""} Executed successfully $ {"CommandLine": "\"python -m pip install beautifulsoup4 rich sentry-sdk requests pytest pydantic-settings\"", "Cwd": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\"", "WaitMsBeforeAsync": "5000", "toolAction": "\"Installing dependencies\"", "toolSummary": "\"Install Python dependencies\""} Executed successfully I've started installing the required Python packages beautifulsoup4 , rich , sentry-sdk , requests , pytest , pydantic-settings in the background. I'll update you as soon as installation completes. python $ {"CommandLine": "\"python -c \\\"import bs4, rich, sentry sdk, requests, pydantic, pydantic settings, pytest; print 'All core dependencies imported successfully ' \\\"\"", "Cwd": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\"", "WaitMsBeforeAsync": "5000", "toolAction": "\"Verifying dependency imports\"", "toolSummary": "\"Verify dependencies in Python\""} Executed successfully { "CodeContent": "\"\\\"\\\"\\\"Slothreader application package.\\\"\\\"\\\"\\n\\n version = \\\"0.1.0\\\"\\n\"", "Description": "\"Create app/ init .py\"", "Overwrite": "true", "TargetFile": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\\\\app\\\\ init .py\"", "toolAction": "\"Creating app/ init .py\"", "toolSummary": "\"Create app/ init .py\"" } Executed successfully { "CodeContent": "\"\\\"\\\"\\\"Parser and schema package for Slothreader.\\\"\\\"\\\"\\n\"", "Description": "\"Create app/parser/ init .py\"", "Overwrite": "true", "TargetFile": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\\\\app\\\\parser\\\\ init .py\"", "toolAction": "\"Creating app/parser/ init .py\"", "toolSummary": "\"Create app/parser/ init .py\"" } Executed successfully {"CodeContent": "\"\\\"\\\"\\\"Data schemas for Slothreader pipelines, articles, and gazettes.\\\"\\\"\\\"\\n\\nfrom typing import List, Optional\\nfrom pydantic import BaseModel, Field\\n\\n\\nclass RawEmail BaseModel :\\n \\\"\\\"\\\"Represents an unprocessed email fetched from IMAP or local mock fixtures.\\\"\\\"\\\"\\n id: str = Field description=\\\"Unique identifier for the raw email or fixture.\\\" \\n source: str = Field description=\\\"Newsletter publisher name, e.g. 'TLDR Tech Executed successfully python $ {"CommandLine": "\"python -c \\\"from app.parser.schemas import RawEmail, CleanedArticle, GazettePayload; print 'Schemas imported and valid ' \\\"\"", "Cwd": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\"", "WaitMsBeforeAsync": "5000", "toolAction": "\"Verifying schemas import\"", "toolSummary": "\"Verify schemas module\""} Executed successfully { "CodeContent": "\"\\\"\\\"\\\"Tests for Slothreader.\\\"\\\"\\\"\\n\"", "Description": "\"Create tests/ init .py\"", "Overwrite": "true", "TargetFile": "\"c:\\\\Users\\\\snigd\\\\OneDrive\\\\Documents\\\\Projects\\\\Slothreader\\\\tests\\\\ init .py\"", "toolAction": "\"Creating tests/ init .py\"", "toolSummary": "\"Create tests/ init .py\"" } Executed successfully {"CodeContent": "\"< DOCTYPE html \\n