<?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: Sana Saifi</title>
    <description>The latest articles on DEV Community by Sana Saifi (@sanasaifi).</description>
    <link>https://dev.to/sanasaifi</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%2F4194649%2Ff79c47d1-61d1-435a-8a22-d2c48c935136.png</url>
      <title>DEV Community: Sana Saifi</title>
      <link>https://dev.to/sanasaifi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sanasaifi"/>
    <language>en</language>
    <item>
      <title>SlothSort: a local Gemma 3 model that tidies my Downloads folder (and can undo everything)</title>
      <dc:creator>Sana Saifi</dc:creator>
      <pubDate>Sun, 25 Oct 2026 18:14:30 +0000</pubDate>
      <link>https://dev.to/sanasaifi/slothsort-a-local-gemma-3-model-that-tidies-my-downloads-folder-and-can-undo-everything-5di5</link>
      <guid>https://dev.to/sanasaifi/slothsort-a-local-gemma-3-model-that-tidies-my-downloads-folder-and-can-undo-everything-5di5</guid>
      <description>&lt;p&gt;What I Built&lt;/p&gt;

&lt;p&gt;My Downloads folder is a mess. It is full of names like Airtel_bill_oct(3).pdf, DS_unit3_notes_final.pdf and resume_v7_updated_final.docx, and sorting them by hand is a job I keep putting off.&lt;/p&gt;

&lt;p&gt;SlothSort is a command-line tool that does it for me. You point it at a folder and it shows a plan: where each file should go and what it should be called. Nothing is moved until you add --apply. If you change your mind, one undo command puts every file back.&lt;/p&gt;

&lt;p&gt;Examples of what it does:&lt;/p&gt;

&lt;p&gt;Messy file    to      Where it goes&lt;br&gt;
Airtel_bill_oct(3).pdf to    Bills/2026-10 Airtel Broadband Bill.pdf&lt;br&gt;
DS_unit3_notes_final.pdf to Study/Data Structures Unit 3 Notes.pdf&lt;br&gt;
IMG_2231.jpg      to       Photos/IMG_2231.jpg&lt;br&gt;
vscode_setup_x64.exe    to Installers/vscode_setup_x64.exe&lt;/p&gt;

&lt;p&gt;The effort it saves: I run one command, look at the preview once, approve it, and I'm done. I don't have to open files to see what they are, think of names, or drag anything.&lt;/p&gt;

&lt;p&gt;I know local AI file organizers already exist. I focused on making this one safe to trust (preview first, undo, never delete) and on measuring how well it actually works.&lt;/p&gt;

&lt;p&gt;Demo -&lt;br&gt;
1: messy folder and empty terminal&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%2Fsc6xyuha7j60rhfl97w5.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%2Fsc6xyuha7j60rhfl97w5.png" alt=" " width="800" height="333"&gt;&lt;/a&gt;&lt;br&gt;
2: running the command (“Scanning and analyzing files...”)&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%2F0isqlih1z0oe7ft6lrxk.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%2F0isqlih1z0oe7ft6lrxk.png" alt=" " width="800" height="338"&gt;&lt;/a&gt;&lt;br&gt;
3: The plan table&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%2Fsifm4h4j5516obfdey9k.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%2Fsifm4h4j5516obfdey9k.png" alt=" " width="800" height="351"&gt;&lt;/a&gt;&lt;br&gt;
4: --apply and the success message&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%2F8f5o8pcryyiyjulyn989.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%2F8f5o8pcryyiyjulyn989.png" alt=" " width="800" height="416"&gt;&lt;/a&gt;&lt;br&gt;
5:Undo and Successfully restored files to their original locations!&lt;br&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%2Fq9ki0f5v51vbdxd2u6lp.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%2Fq9ki0f5v51vbdxd2u6lp.png" alt=" " width="799" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also try it yourself without touching your real files. The repo has a script that builds a fake messy folder:&lt;/p&gt;

&lt;p&gt;powershell&lt;br&gt;
python scripts/make_test_folder.py&lt;br&gt;
python -m slothsort test_downloads --ignore-recent          # preview only&lt;br&gt;
python -m slothsort test_downloads --ignore-recent --apply  # do it&lt;br&gt;
python -m slothsort undo test_downloads                     # put everything back&lt;/p&gt;

&lt;p&gt;Code - &lt;br&gt;
&lt;a href="https://github.com/Sanasaifi786/SlothSort" rel="noopener noreferrer"&gt;https://github.com/Sanasaifi786/SlothSort&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Stack: Python, Ollama running Gemma 3 4B locally, pypdf and python-docx to read the start of documents, rich for the terminal tables, and pytest for tests.&lt;/p&gt;

&lt;p&gt;The pipeline:&lt;/p&gt;

&lt;p&gt;Scan the folder (top level only). Skip temporary files like .crdownload and anything modified in the last 10 minutes.&lt;br&gt;
Rules first: extensions like .jpg, .exe and .zip are sorted instantly with plain rules. No AI needed.&lt;br&gt;
AI only for unclear files: for PDFs, Word files and text files, I read the first ~500 characters and ask Gemma for a category and a clean name as JSON.&lt;br&gt;
Validate the answer, build a plan, and show it as a table.&lt;br&gt;
With --apply, move the files and write slothsort_undo.json so everything can be reversed.&lt;/p&gt;

&lt;p&gt;Why hybrid: asking a 4B model what photo.jpg is wastes time. Rules handle the obvious files and the model handles the ones where the content matters.&lt;/p&gt;

&lt;p&gt;I don't trust the model's output. The category must be in my allowed list, otherwise it becomes "Other". Broken JSON falls back safely. File names are cleaned of Windows-illegal characters, and name clashes become file (2).pdf. SlothSort never deletes or overwrites anything.&lt;/p&gt;

&lt;p&gt;There are 33 automated tests covering file-name cleaning, name clashes, scanning rules, PDF and DOCX reading, AI output parsing, moving files and undo. They all pass.&lt;/p&gt;

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

&lt;p&gt;Files in a Downloads folder are often the most private things on a computer: bills, bank statements, tax forms, resumes, ID scans. Sending those to a cloud API just to get a file renamed felt wrong to me.&lt;/p&gt;

&lt;p&gt;Running an open-weight model locally gave me:&lt;/p&gt;

&lt;p&gt;Privacy: the file contents never leave my laptop.&lt;br&gt;
Offline use: it needs no internet once the model is downloaded.&lt;br&gt;
No ongoing cost: no API key, no per-file charge.&lt;br&gt;
Swappable models: --model gemma3:4b or another model, with no code change.&lt;br&gt;
Control: the categories live in a plain categories.json file that I can edit.&lt;/p&gt;

&lt;p&gt;Where a closed model would be better: it would almost certainly be faster and more accurate. A small local model on a laptop CPU is slow and makes mistakes (see below). For this particular task I accepted that trade for privacy.&lt;/p&gt;

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

&lt;p&gt;I built a small benchmark (scripts/benchmark.py) on a test folder of 35 files with known correct categories.&lt;/p&gt;

&lt;p&gt;Mode    Correct Accuracy    Time&lt;br&gt;
Rules only (--no-ai)    19 / 35 54.3%   0.00 s&lt;br&gt;
Rules + Gemma 3 4B  32 / 35 91.4%   155.89 s&lt;br&gt;
By hand 35 / 35 100%    about 120 s (my estimate, not a stopwatch run)&lt;/p&gt;

&lt;p&gt;What I take from this, honestly:&lt;/p&gt;

&lt;p&gt;The AI added 13 correct files on top of the rules (19 → 32). Documents with unhelpful names are exactly where rules fail.&lt;br&gt;
It is not faster than doing it myself. On my laptop the hybrid run took about 2.5 minutes, slightly longer than my rough manual estimate. The saving is attention, not clock time: I can start it and walk away.&lt;/p&gt;

&lt;p&gt;The test folder is small and I created it myself, so 91.4% is an indication, not a general accuracy claim. Real folders will be messier.&lt;br&gt;
Limitations: scanned PDFs without a text layer have no text to read, so SlothSort falls back to the file name. It only processes the top level of a folder. CPU speed depends on your laptop (mine is a Windows laptop with 16 GB RAM).&lt;/p&gt;

&lt;p&gt;Next steps: a watch mode that tidies files as they finish downloading, OCR for scanned documents, and remembering my corrections.&lt;/p&gt;

&lt;p&gt;Best Use of Gemma: I ran Gemma 3 4B locally through Ollama as the classifier for every ambiguous file.&lt;/p&gt;

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