<?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: atif-1402</title>
    <description>The latest articles on DEV Community by atif-1402 (@atif1402).</description>
    <link>https://dev.to/atif1402</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%2F4140339%2F6595579e-ffdd-412e-858f-67a613aca15f.png</url>
      <title>DEV Community: atif-1402</title>
      <link>https://dev.to/atif1402</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/atif1402"/>
    <language>en</language>
    <item>
      <title>Which Copy Do I Keep? Sloth-Powered Folder Tidying with a Local Gemma</title>
      <dc:creator>atif-1402</dc:creator>
      <pubDate>Tue, 20 Oct 2026 17:17:17 +0000</pubDate>
      <link>https://dev.to/atif1402/which-copy-do-i-keep-sloth-powered-folder-tidying-with-a-local-gemma-57c9</link>
      <guid>https://dev.to/atif1402/which-copy-do-i-keep-sloth-powered-folder-tidying-with-a-local-gemma-57c9</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;Somewhere in your files sit &lt;code&gt;contract.pdf&lt;/code&gt;, &lt;code&gt;contract_final.pdf&lt;/code&gt;, &lt;code&gt;contract_final_v2(1).pdf&lt;/code&gt;, and &lt;code&gt;contract_FINAL (copy).pdf&lt;/code&gt; — the same document, four times over. You know one of them is the real one. You don't know &lt;em&gt;which&lt;/em&gt; one. So you open all four, squint at the footer, find the signed copy, close three tabs — or worse, you pick wrong and sign the wrong version.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keeper answers that question for you.&lt;/strong&gt; Point it at a folder: it clusters version-clone files by &lt;em&gt;actual content&lt;/em&gt; (not filename), asks a local open-weight model which copy is the keeper and &lt;strong&gt;why&lt;/strong&gt;, and quarantines the rest. Dry-run by default. It never deletes a thing.&lt;/p&gt;

&lt;p&gt;That's the whole sloth move — a task you've been putting off for years, done by one command while you get a coffee.&lt;/p&gt;

&lt;p&gt;The model suggests; you keep the final say. All of this is in &lt;strong&gt;v0.1.6&lt;/strong&gt;, released Friday:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;--interactive&lt;/code&gt;&lt;/strong&gt; — Keeper walks each cluster in turn and asks you. Press Enter to accept the verdict, type a number to keep a different copy, &lt;code&gt;s&lt;/code&gt; to leave that cluster alone, &lt;code&gt;q&lt;/code&gt; to stop. It stays a dry run the whole way — nothing moves without &lt;code&gt;--apply&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;--only 1,3,5&lt;/code&gt; / &lt;code&gt;--skip 2&lt;/code&gt;&lt;/strong&gt; — act on a subset of clusters (ranges work too: &lt;code&gt;2-4&lt;/code&gt;). Numbering is stable across runs, so &lt;code&gt;--only 7&lt;/code&gt; still reads as cluster 7 in the table, the JSON and the Markdown report.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Targeting&lt;/strong&gt; — &lt;code&gt;--ext pdf,jpg&lt;/code&gt;, &lt;code&gt;--min-size 10k&lt;/code&gt;, &lt;code&gt;--include 'rental*'&lt;/code&gt;, &lt;code&gt;--exclude 'reports/*'&lt;/code&gt;. The filters run during the walk, so a file you excluded is never hashed and never read.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;--max-hash-mb 512&lt;/code&gt;&lt;/strong&gt; — the byte-identical pass used to stop at 64 MB, which quietly hid the big files: a re-downloaded installer, two copies of the same video. The default is now 512 MB; &lt;code&gt;0&lt;/code&gt; means no limit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;--quiet&lt;/code&gt;&lt;/strong&gt; — nothing but errors, for cron and CI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;--fail-on-clutter&lt;/code&gt;&lt;/strong&gt; — exits &lt;code&gt;3&lt;/code&gt; when there's work to do and &lt;code&gt;0&lt;/code&gt; when the folder is tidy, so a script can tell "findings" apart from "it broke".&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  If you disagree with it
&lt;/h3&gt;

&lt;p&gt;Real output from a small test folder — the model and the rules both preferred &lt;code&gt;report_v2.txt&lt;/code&gt;, I didn't:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;keeper client-docs &lt;span class="nt"&gt;--interactive&lt;/span&gt;
&lt;span class="go"&gt;Cluster 1 of 4 — 3 copies
  1. [loser] report.txt  (73 B)
  2. [loser] report_final.txt  (92 B)
  3. [keep] report_v2.txt  (109 B)
  why: newest signed copy  [rule, confidence 0.60]
&lt;/span&gt;&lt;span class="gp"&gt;  [Enter] accept · [number] keep that copy · [s] skip · [q] stop &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;1
&lt;span class="go"&gt;  keeper is now report.txt

Cluster 2 of 4 — 2 copies
  1. [loser] data.bin  (4.0 KB)
  2. [keep] data.bin.bak  (4.0 KB)
&lt;/span&gt;&lt;span class="gp"&gt;  why: all copies are byte-identical;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kept the newest timestamp  &lt;span class="o"&gt;[&lt;/span&gt;identical, confidence 1.00]
&lt;span class="gp"&gt;  [Enter] accept · [number] keep that copy · [s] skip · [q] stop &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;q
&lt;span class="go"&gt;
  Review stopped — 2 cluster(s) after this one will not be touched.

DRY RUN — nothing was moved (2 loser(s) would be quarantined · 201 B of duplicate clutter).
Run again with --apply to quarantine them, or --restore to undo.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That row comes back in the table as &lt;code&gt;◆ you — you chose copy 1&lt;/code&gt;. You were looking at the actual files, size and name in front of you, instead of a confidence score — and the override still went through the same dry run, manifest and &lt;code&gt;--restore&lt;/code&gt; as every other verdict. Quit early and the clusters you never reviewed are left alone, not swept up.&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/https%3A%2F%2Fraw.githubusercontent.com%2Fatif-1402%2Fkeeper%2Fmain%2Fassets%2Fdemo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fatif-1402%2Fkeeper%2Fmain%2Fassets%2Fdemo.gif" alt="Keeper scanning ~/keeper-testing: spinner, verdict table, quarantine" width="559" height="305"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  In my case it takes time — I'm on a low-end device, and local LLMs are heavy. Sorry for the bad quality!
&lt;/p&gt;

&lt;p&gt;A full run on my test folder: scan → spinner with a self-measured ETA → verdict table → &lt;code&gt;--apply&lt;/code&gt; quarantines the 8 losers. Nothing was deleted.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/atif-1402" rel="noopener noreferrer"&gt;
        atif-1402
      &lt;/a&gt; / &lt;a href="https://github.com/atif-1402/keeper" rel="noopener noreferrer"&gt;
        keeper
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Which file do I keep? Finds version-clone files in a folder and asks a local open-weight model (Ollama + Gemma) which copy wins — and why. Dry-run by default, never deletes, fully reversible.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/atif-1402/keeper/assets/keeper-header.svg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fatif-1402%2Fkeeper%2FHEAD%2Fassets%2Fkeeper-header.svg" alt="keeper — which copy do I keep?" width="800"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
  Finds version-clone files in any folder, asks a local open-weight model which copy to keep, and quarantines the rest — dry-run by default, 100% offline
&lt;/p&gt;
&lt;p&gt;
  &lt;a href="https://github.com/atif-1402/keeper/blob/main/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/fcc14f525b15b21cb526d6775b9db3c48b85104da1f4d854958c30e383539a31/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d336662393530" alt="MIT license"&gt;&lt;/a&gt;
  &lt;a href="https://www.python.org/downloads/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e505dd129e5fd79ff891f4261a8616edc1b5d5749937343af8e3116fe449b801/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f707974686f6e2d332e31312532422d344238424245" alt="Python 3.11+"&gt;&lt;/a&gt;
  &lt;a href="https://ollama.com/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e21bad39106852588f3fb65a134e00bc5b2f889b77c72b58b49cec6a663bef1b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4f6c6c616d612d47656d6d612d366364343462" alt="Ollama + Gemma"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/6179fa2d8432b8960307a9da1086c93adc6efcad79e87fac6b1fbca00ec903ed/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f706c6174666f726d2d4c696e75782532302537432532306d61634f5325323025374325323057696e646f77732d6c6967687467726579"&gt;&lt;img src="https://camo.githubusercontent.com/6179fa2d8432b8960307a9da1086c93adc6efcad79e87fac6b1fbca00ec903ed/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f706c6174666f726d2d4c696e75782532302537432532306d61634f5325323025374325323057696e646f77732d6c6967687467726579" alt="Linux, macOS, Windows"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/atif-1402/keeper/actions/workflows/release.yml" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a9818bb7180e681a995ecc7cbc6e765b1d60b77365ada2b8fffa8b4a12acd282/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772d7374617475732f617469662d313430322f6b65657065722f72656c656173652e796d6c3f6272616e63683d6d61696e266c6162656c3d6275696c64" alt="CI status"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/atif-1402/keeper/releases" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b7430da7190e29fdcf4a36762d463870de57bd59f9d4dc9142d79377182a1ba5/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f617469662d313430322f6b65657065723f696e636c7564655f70726572656c656173657326736f72743d73656d766572" alt="Latest release"&gt;&lt;/a&gt;
  &lt;a href="https://ko-fi.com/anom538" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7469651440aeeba98f528b7da39563d0b569aee521519528ce9e126241e32fa7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4b6f2d2d66692d537570706f72742532306d652d6666356635663f6c6f676f3d6b6f2d6669266c6f676f436f6c6f723d7768697465" alt="Support on Ko-fi"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
  &lt;a href="https://github.com/atif-1402/keeper#demo" rel="noopener noreferrer"&gt;Demo&lt;/a&gt; ·
  &lt;a href="https://github.com/atif-1402/keeper#install" rel="noopener noreferrer"&gt;Install&lt;/a&gt; ·
  &lt;a href="https://github.com/atif-1402/keeper#how-it-works" rel="noopener noreferrer"&gt;How it works&lt;/a&gt; ·
  &lt;a href="https://github.com/atif-1402/keeper#safety-model" rel="noopener noreferrer"&gt;Safety model&lt;/a&gt; ·
  &lt;a href="https://github.com/atif-1402/keeper#cli" rel="noopener noreferrer"&gt;CLI&lt;/a&gt; ·
  &lt;a href="https://github.com/atif-1402/keeper#why-open-innovation-matters-here" rel="noopener noreferrer"&gt;Why open weights&lt;/a&gt;
&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Demo&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/atif-1402/keeper/assets/demo.gif"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fatif-1402%2Fkeeper%2FHEAD%2Fassets%2Fdemo.gif" alt="Keeper scanning ~/keeper-testing: spinner, verdict table, quarantine" width="820"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;i&gt;In my case it takes time — I'm on a low-end device, and local LLMs are heavy. Sorry for the bad quality!&lt;/i&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why this exists&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Duplicate finders tell you files are identical. Diff tools make you pick the two files to compare by hand. Neither one answers the question you actually have: &lt;strong&gt;"I have five versions of the same document — which one do I keep?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Keeper walks the folder itself, clusters the versions, and gives you a colored verdict table with a one-line reason per cluster. While it works you get a live spinner — one line that updates itself (&lt;code&gt;hashing files&lt;/code&gt; → &lt;code&gt;extracting text&lt;/code&gt; →…&lt;/p&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/atif-1402/keeper" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;&lt;br&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/atif-1402/keeper/main/install.sh | bash

ollama pull gemma3:1b  &lt;span class="c"&gt;# ~800 MB, runs on 4 GB RAM&lt;/span&gt;
keeper ~/Documents  &lt;span class="c"&gt;# dry run — moves nothing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Windows runs it today via &lt;code&gt;pipx install git+https://github.com/atif-1402/keeper&lt;/code&gt;; &lt;a href="https://github.com/atif-1402/keeper/releases/tag/v0.1.6" rel="noopener noreferrer"&gt;release v0.1.6&lt;/a&gt; ships standalone binaries for Linux (x64/arm64), macOS and Windows. No Ollama? Keeper falls back to its rule engine and tells you so.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/atif-1402/keeper" rel="noopener noreferrer"&gt;github.com/atif-1402/keeper&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Release:&lt;/strong&gt; &lt;a href="https://github.com/atif-1402/keeper/releases/tag/v0.1.6" rel="noopener noreferrer"&gt;v0.1.6&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;This challenge:&lt;/strong&gt; &lt;a href="https://dev.to/challenges/hf26"&gt;Slow and Steady on the HF26 hub&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;&lt;code&gt;gemma3:1b&lt;/code&gt; through local Ollama&lt;/strong&gt; — an ~800 MB open-weight model that runs in 4 GB RAM. No API keys, no cloud, no ML framework in the codebase: grouping is TF-IDF cosine similarity over filename tokens and extracted text, image matching is a 64-bit perceptual hash, and everything is pure Python.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;folder ─▶ scan (hash + metadata) ─▶ extract (txt/md/csv/pdf/docx)
  ─▶ group (filename tokens + TF-IDF cosine) ─▶ decide ─▶ report
  │
  `--apply` ─▶ _keeper_quarantine/ + manifest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scan&lt;/strong&gt; — walks the folder (skipping &lt;code&gt;.git&lt;/code&gt;, &lt;code&gt;node_modules&lt;/code&gt;, and its own quarantine), records size, mtime, sha256.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extract&lt;/strong&gt; — pulls text from documents; images, video and archives are recognized as media up front so their bytes are never decoded into garbage "text". A scanned PDF with no text layer is honestly flagged instead of treated as empty.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Group&lt;/strong&gt; — byte-identical files cluster by hash; near-duplicates cluster by filename-token overlap (browser &lt;code&gt;notes (1).md&lt;/code&gt; suffixes stripped) and content similarity — and since v0.1.5, visually near-identical images cluster by &lt;strong&gt;perceptual hash&lt;/strong&gt;: a screenshot saved as &lt;code&gt;photo.png&lt;/code&gt; and re-exported as &lt;code&gt;photo.jpg&lt;/code&gt; is the same picture with different bytes, and a 64-bit difference hash sees it. Names carrying &lt;em&gt;different&lt;/em&gt; identity numbers (&lt;code&gt;S01E01&lt;/code&gt; vs &lt;code&gt;S01E02&lt;/code&gt;, &lt;code&gt;Lesson13&lt;/code&gt; vs &lt;code&gt;Lesson14&lt;/code&gt;) are never merged — episodes and numbered lessons stay apart.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decide&lt;/strong&gt; — only clusters with readable text ever reach the model. Byte-identical clusters and unreadable ones (zips, images, videos) are settled instantly from metadata, so a low-end machine runs Gemma only when it actually matters. Each call is temperature 0, capped output, with a server-side JSON schema — the model &lt;em&gt;structurally cannot&lt;/em&gt; answer in any other shape than &lt;code&gt;{keep, reason, confidence}&lt;/code&gt;. A verdict it isn't confident about gets one richer second look (more copies, longer excerpts); still unsure, Keeper says "the model was unsure after two looks" and the rules decide. An agent that knows when it doesn't know.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quarantine&lt;/strong&gt; — &lt;code&gt;--apply&lt;/code&gt; moves losers into &lt;code&gt;_keeper_quarantine/&amp;lt;group&amp;gt;/&lt;/code&gt; with a &lt;code&gt;manifest.json&lt;/code&gt; and a portable &lt;code&gt;restore.sh&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The safety net
&lt;/h3&gt;

&lt;p&gt;If the model's pick contradicts hard evidence — the signed copy, the newest timestamp — a transparent rule engine overrules it. Look at row 3 in the demo: the model disagreed on the contract, and the newest copy won on metadata, with the override stated plainly in the table (&lt;code&gt;◐ rule — model disagreed&lt;/code&gt;). I'd rather ship a tool that's &lt;em&gt;right&lt;/em&gt; than one that's confidently wrong. Rule modes are yours too: &lt;code&gt;--no-model&lt;/code&gt; (rules only, instant) and &lt;code&gt;--model-only&lt;/code&gt; (hard-error if Ollama is down).&lt;/p&gt;

&lt;p&gt;And the three guarantees everything else rests on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dry-run by default&lt;/strong&gt; — nothing moves without &lt;code&gt;--apply&lt;/code&gt;, including after an &lt;code&gt;--interactive&lt;/code&gt; review.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never deletes&lt;/strong&gt; — losers are &lt;em&gt;moved&lt;/em&gt; into &lt;code&gt;_keeper_quarantine/&amp;lt;group&amp;gt;/&lt;/code&gt;; the manifest records origin, size and SHA-256 for every one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fully reversible&lt;/strong&gt; — &lt;code&gt;keeper &amp;lt;folder&amp;gt; --restore&lt;/code&gt; returns the folder to its exact prior state, verified byte-for-byte by tests (95 of them).&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The files Keeper reads are contracts, passports, medical letters, tax returns. Shipping filenames and text excerpts to a closed cloud model is exactly the wrong default for this job. &lt;code&gt;gemma3:1b&lt;/code&gt; (~800 MB, runs in 4 GB RAM) reads your lease agreement &lt;strong&gt;on your laptop&lt;/strong&gt; and forgets it when the process exits — no API keys, no telemetry, no network calls beyond &lt;code&gt;localhost:11434&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's what an open-weight model buys you: a private assistant with no exfiltration surface and no vendor who can change the terms next quarter. And the whole reasoning pipeline — grouping, prompting, fallback rules — is in one repo, auditable in an afternoon.&lt;/p&gt;

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

&lt;p&gt;Honest numbers from my own machine — a 4-core low-end box:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A real 211-file folder of mine&lt;/strong&gt; → 35 duplicate clusters, &lt;strong&gt;92 losing copies identified&lt;/strong&gt;, in about a minute. Only &lt;strong&gt;9 clusters&lt;/strong&gt; called the model; everything else was decided instantly from metadata.&lt;/li&gt;
&lt;li&gt;Doing that by hand means opening 92 files, comparing them, deciding. That's an afternoon I'm never getting back. Keeper: one command.&lt;/li&gt;
&lt;li&gt;Every run ends with the weight: &lt;code&gt;8 loser(s) would be quarantined · 37.3 KB of duplicate clutter&lt;/code&gt; — one number that says how much you've been carrying.&lt;/li&gt;
&lt;li&gt;On a fast machine the model calls take seconds; on mine the spinner honestly shows minutes (&lt;code&gt;[3/9] · about 40s left&lt;/code&gt;) — measured throughput, no fake progress bar.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Best Use of Gemma&lt;/strong&gt; — featured category.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gemma3:1b&lt;/code&gt; is Keeper's default model, run through local Ollama. Every cluster the hash and the metadata can't settle goes to Gemma, which returns &lt;code&gt;{keep, reason, confidence}&lt;/code&gt; through a server-side JSON schema and writes the one-line explanation you read in the verdict table — the "newest signed copy" style reasons are its words, not a template. &lt;code&gt;--model gemma3:4b&lt;/code&gt; swaps in the larger Gemma for a second opinion. No cloud model is involved at any point.&lt;/p&gt;

&lt;p&gt;Thanks for reading — point it at the folder you keep meaning to sort, and enjoy International Sloth Day.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Disclosure: this article was created with the help of AI.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>gemma</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I created parse to solve the problem of messy cli outputs</title>
      <dc:creator>atif-1402</dc:creator>
      <pubDate>Thu, 08 Oct 2026 06:06:46 +0000</pubDate>
      <link>https://dev.to/atif1402/i-created-parse-to-solve-the-problem-of-messy-cli-outputs-5g7k</link>
      <guid>https://dev.to/atif1402/i-created-parse-to-solve-the-problem-of-messy-cli-outputs-5g7k</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fatif-1402%2Fparse%2Fmain%2Fassets%2Fpreview.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fatif-1402%2Fparse%2Fmain%2Fassets%2Fpreview.gif" alt="parse demo" width="560" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I create parse to solve the problem of messy and non-understandable outputs. Parse make the outputs of the currently supported commands into easily understandable and format.&lt;/p&gt;

&lt;p&gt;It is single go binary and standard library only.&lt;/p&gt;

&lt;p&gt;We can use it like &lt;code&gt;parse COMMAND&lt;/code&gt; or &lt;code&gt;COMMAND | parse&lt;/code&gt; . You can install it by&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go install github.com/atif-1402/parse@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Would love to hear peoples feedback on this project - &lt;a href="https://github.com/atif-1402/parse" rel="noopener noreferrer"&gt;https://github.com/atif-1402/parse&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>terminal</category>
      <category>cli</category>
      <category>linux</category>
    </item>
    <item>
      <title>Termai - Created a Simple AI agent in Bash</title>
      <dc:creator>atif-1402</dc:creator>
      <pubDate>Thu, 24 Sep 2026 04:06:40 +0000</pubDate>
      <link>https://dev.to/atif1402/termai-create-a-simple-ai-agent-in-bash-51oc</link>
      <guid>https://dev.to/atif1402/termai-create-a-simple-ai-agent-in-bash-51oc</guid>
      <description>&lt;p&gt;No Python. No Node. Just Bash and jq.&lt;/p&gt;

&lt;p&gt;an AI assistant that runs in your terminal, chats with an LLM, and can search the web, check the weather, fetch URLs and run commands.&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%2Fp5v7xo7zilnj8eh28mtu.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%2Fp5v7xo7zilnj8eh28mtu.png" alt=" " width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tool calling turned out to be just a case statement: the model picks a tool, Bash runs it, the result goes back to the model.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>bash</category>
      <category>linux</category>
    </item>
  </channel>
</rss>
