<?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: season</title>
    <description>The latest articles on DEV Community by season (@tiantian_5ba41d50af4f8772).</description>
    <link>https://dev.to/tiantian_5ba41d50af4f8772</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%2F4195099%2Ff21e5d88-6f82-4959-84cf-2d484e80985e.jpg</url>
      <title>DEV Community: season</title>
      <link>https://dev.to/tiantian_5ba41d50af4f8772</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tiantian_5ba41d50af4f8772"/>
    <language>en</language>
    <item>
      <title>I fired myself as my own librarian: LazyScholar, an unattended knowledge butler powered by a local Gemma</title>
      <dc:creator>season</dc:creator>
      <pubDate>Sat, 24 Oct 2026 11:11:59 +0000</pubDate>
      <link>https://dev.to/tiantian_5ba41d50af4f8772/i-fired-myself-as-my-own-librarian-lazyscholar-an-unattended-knowledge-butler-powered-by-a-local-2ofi</link>
      <guid>https://dev.to/tiantian_5ba41d50af4f8772/i-fired-myself-as-my-own-librarian-lazyscholar-an-unattended-knowledge-butler-powered-by-a-local-2ofi</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;Every productivity tool I tried asked me to be more disciplined. So I built one that asks me for nothing.&lt;/p&gt;

&lt;p&gt;LazyScholar is a local knowledge butler for Windows — a Grammarly-style floating sidebar, a comfortable paper reader, and a &lt;strong&gt;local Gemma 3 4B (GGUF) running in llama.cpp&lt;/strong&gt;. No cloud model API, no Ollama, Obsidian optional. It ships as one packaged &lt;code&gt;LazyScholar.exe&lt;/code&gt; you can just double-click (you only need the Edge WebView2 Runtime; a model is only needed when you want notes generated, not for reading).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Download v1.0.0:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/lood31/lazyscholar/releases/tag/v1.0.0" rel="noopener noreferrer"&gt;https://github.com/lood31/lazyscholar/releases/tag/v1.0.0&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The queue: three ways in, reading first
&lt;/h3&gt;

&lt;p&gt;From the panel's queue tab you can add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an arXiv link or ID,&lt;/li&gt;
&lt;li&gt;a local PDF whose filename contains its arXiv ID, or&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;a saved static webpage — &lt;code&gt;.html&lt;/code&gt;/&lt;code&gt;.htm&lt;/code&gt; or &lt;code&gt;.mhtml&lt;/code&gt;/&lt;code&gt;.mht&lt;/code&gt; — no arXiv ID required.&lt;/strong&gt; Import reads only local/embedded resources: it keeps safe images, SVGs and native MathML, never executes the page's scripts, and never goes online to fetch missing pieces.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Processing can run immediately or at a scheduled time, with the model started and stopped automatically. But reading no longer waits for any of that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read now.&lt;/strong&gt; Click it on a queue item and you are reading — no model started, no note required. Reading and generation are decoupled; a missing note is shown as missing, it does not block the article, the PDF, or your annotations. Imported local PDFs read fully offline.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The note: the whole text, with receipts
&lt;/h3&gt;

&lt;p&gt;This is the part that changed most since my earlier drafts, so let me be precise. The desktop queue does &lt;strong&gt;not&lt;/strong&gt; summarize the abstract:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It reads the actual source text — arXiv HTML (or the complete PDF text layer when HTML is unavailable), the imported local PDF, or the imported webpage text. It never silently falls back to an abstract.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;All extractable text is processed in chunks.&lt;/strong&gt; For each chunk the model selects source-passage IDs; the application then retrieves the corresponding extracted text itself, so quotations come from the source, not from the model's memory.&lt;/li&gt;
&lt;li&gt;Those evidenced passages are merged &lt;strong&gt;hierarchically&lt;/strong&gt; into the final study note, and every final section must cite valid source IDs such as &lt;code&gt;[C0001]&lt;/code&gt;. The fingerprints and evidence are saved alongside the note, and the note discloses its actual source and limits.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Failure is explicit, by design: a source over the chunk limit or an invalid model result fails loudly — no dropped tail, no half-written note, and never overwriting an existing good note. A scanned PDF with no text layer cannot produce a text note, but its pages remain readable.&lt;/p&gt;

&lt;p&gt;One more small, deliberate detail: &lt;strong&gt;generated content follows the interface language saved when the task starts&lt;/strong&gt; (Chinese or English) — chunk analysis, intermediate merges and the final guide. Switching the UI language later does not translate or rewrite existing notes, and a running task keeps its starting language.&lt;/p&gt;

&lt;p&gt;Honesty boundary, stated in the release notes too: this is processing of extracted text, not an understanding of every figure, formula or page layout, and a valid source ID proves where evidence came from — not that the model's interpretation is correct. Check the key claims against the original. (The old command-line inbox path is retained as a separate entry point and still produces abstract-based notes; it is not the desktop queue described above.)&lt;/p&gt;

&lt;h3&gt;
  
  
  The reader: the original, comfortably
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In-app arXiv HTML reader&lt;/strong&gt;: the paper's original HTML is fetched and cached automatically, formulas render locally as MathML exactly as published — the model never gets to rewrite an equation. Font size is adjustable, wide formulas scroll horizontally, and figures and formulas open enlarged on click.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Highlighting with a partial eraser&lt;/strong&gt;: select text to highlight it, persistently. The eraser removes only the segment you select — erase the middle of a highlight and both ends stay. If two reader windows edit annotations at once, saves are revision-checked: on conflict the app re-reads and reapplies your change instead of overwriting the newer one, and a persistent conflict surfaces as an explicit retry error.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comfortable PDF reading&lt;/strong&gt;: the original PDF opens at &lt;strong&gt;150% by default&lt;/strong&gt;, with zoom, fit-width and horizontal scrolling; pages are rendered on demand (higher-resolution on high-DPI displays), and a &lt;strong&gt;Larger window&lt;/strong&gt; button opens a separate, resizable reader window that shares the same annotations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Deleting things, safely
&lt;/h3&gt;

&lt;p&gt;Delete works from the Notes or Queue toolbar for one paper at a time, behind a compact in-app confirmation. The note, its confirmed app-owned caches, annotations and evidence go to the &lt;strong&gt;Windows Recycle Bin&lt;/strong&gt; — never a permanent-delete fallback. External original files are untouched, one paper may produce several Recycle Bin entries, and partial success is reported as partial, with a metadata receipt (&lt;code&gt;paper_deletions.json&lt;/code&gt;, receipts only — no paper-content copies) so you can retry. Restore the items in Windows and the app verifies paths and fingerprints before restoring queue metadata. Stale requests from before a delete/restore/re-import are isolated by a reader lifecycle epoch, so a delayed write from an old window cannot mutate the restored state.&lt;/p&gt;

&lt;h3&gt;
  
  
  The shell around it all
&lt;/h3&gt;

&lt;p&gt;A small floating ball docks at the right edge of the screen — a frosted pill shape with the app icon, sliding only up and down along that edge — and opens the floating panel: model controls (start/stop/test inside the app), the queue, the reader and notes, and settings (theme, font, schedule, Chinese/English UI). The app lives in the system tray and is single-instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&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%2Fczwhre80f0quyji2z5r2.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%2Fczwhre80f0quyji2z5r2.png" alt="Floating ball docked at the right edge of the desktop" width="800" height="771"&gt;&lt;/a&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%2Fk9pmaxfkqf9wnq7jx3ob.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%2Fk9pmaxfkqf9wnq7jx3ob.png" alt="Panel open on the user's desktop with a real queue" width="800" height="792"&gt;&lt;/a&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%2Fk764fy82iwlh6o3dtetx.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%2Fk764fy82iwlh6o3dtetx.png" alt="Finished full-text study note, showing the hierarchical guide and its [C0001]-style source references" width="800" height="823"&gt;&lt;/a&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%2Frcsieuzx8a46tyg7b2mj.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%2Frcsieuzx8a46tyg7b2mj.png" alt="ArXiv HTML reader with a highlighted passage, the partial eraser, and a rendered formula" width="800" height="798"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Download v1.0.0 (EXE + SHA-256, manually verified build):&lt;br&gt;
&lt;a href="https://github.com/lood31/lazyscholar/releases/tag/v1.0.0" rel="noopener noreferrer"&gt;https://github.com/lood31/lazyscholar/releases/tag/v1.0.0&lt;/a&gt;&lt;/p&gt;

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

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

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

&lt;ul&gt;
&lt;li&gt;Python for the app and pipeline, llama.cpp serving Gemma 3 4B QAT GGUF locally (&lt;code&gt;llama serve&lt;/code&gt;, context 16384 by default), notes stored as plain Markdown files in a vault folder you choose.&lt;/li&gt;
&lt;li&gt;The desktop shell taught me the most. My first floating-ball attempt used a webview transparency flag that, I later found in the official docs, is simply &lt;strong&gt;not supported on Windows&lt;/strong&gt; — it rendered as a white square. The fix was to leave the webview for the ball: a native Win32 layered window with a Pillow-rendered ball image (per-pixel alpha, shadow baked in), &lt;code&gt;pystray&lt;/code&gt; for tray residency, a named mutex for single-instance, and DWM attributes for the panel's rounded corners and shadow.&lt;/li&gt;
&lt;li&gt;Because I cannot watch my own laptop screen while an AI agent codes on it, the repository has a GitHub Actions workflow: every push builds the .exe on a Windows runner, launches it, runs smoke and backend regression checks, and publishes QA screenshots to a &lt;code&gt;ci-qa&lt;/code&gt; branch. The agent reviews the screenshots itself — that loop is how the ball and panel were verified without me taking a single screenshot. (Known wart, visible in those very screenshots: raw.githubusercontent serves the ci-qa images with stale CDN caching, so I learned to check file hashes and the screenshot clock before trusting what I was looking at.)&lt;/li&gt;
&lt;li&gt;The process was deliberately engineering-first after an early version failed visual acceptance: research real implementations, write a spec (a single DESIGN.md as the source of truth), get it approved, then implement in increments, then verify against screenshots.&lt;/li&gt;
&lt;li&gt;The reader follows the same honesty rule as the note pipeline: fetch and cache the publisher's HTML, render MathML as-is, keep highlights as plain persisted data, and make the model cite passage IDs the application can check — no model in a position where it could silently corrupt the source.&lt;/li&gt;
&lt;li&gt;Deletion was built to the same standard: native Windows recycling via pywin32, receipts instead of copies, conflict-checked annotation saves, and explicit errors instead of fallbacks wherever "just delete it" would have been easier.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Everything here runs on open weights and open tools, and that is not decoration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy&lt;/strong&gt;: my reading notes and chat logs never leave my machine — there is no API to send them to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline&lt;/strong&gt;: reading works with the network cable pulled, and the whole generation pipeline is local too (arXiv fetching aside).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero marginal cost&lt;/strong&gt;: no per-token bill, so the butler can keep filing notes forever on a student budget.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hackability&lt;/strong&gt;: the note template is just a prompt in my own code; I changed it twice in one evening.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This project was pair-built with AI agents, honestly and sometimes painfully. An agent ran my laptop remotely over SSH while I was at swimming practice, set up the vault and model, and got the core pipeline working a day early. It also shipped a UI I rejected on sight (white-square ball, wall-sized panel, no tray icon) — which is what forced the research → spec → approval workflow above, and the CI screenshot loop.&lt;/p&gt;

&lt;p&gt;Development did not stop there. A second agent (running on the laptop) kept building on that foundation — the in-app reader and highlighting first, then the full-text pipeline with evidence checking, saved-webpage import, the comfortable PDF reader, Read-now, and the Recycle-Bin deletion lifecycle — while I reviewed deliveries against what was promised, and cut planned features rather than pretend they shipped. I then shipped &lt;strong&gt;v1.0.0&lt;/strong&gt; myself: the Release's &lt;code&gt;LazyScholar.exe&lt;/code&gt; is the manually verified build I accepted, published as-is with its SHA-256 — not a CI rebuild swapped in afterwards. What is in this post is what is in that release, nothing more.&lt;/p&gt;

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

&lt;p&gt;Before: finishing a paper meant ~15 minutes of manual note-taking I never actually kept up, then hunting through three apps to re-read the original — and any summary I did have was only ever about the abstract.&lt;br&gt;
After: I add a paper (or a saved webpage) to the queue and read it immediately, formulas intact, ready to highlight. When I want the guide, the local model reads the whole extractable text — chunk by chunk, with source references I can check — and files it for me. And when I clean up, deletion goes through the Windows Recycle Bin with a receipt, not into the void.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Overall&lt;/li&gt;
&lt;li&gt;Best Use of Gemma&lt;/li&gt;
&lt;/ul&gt;

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