DEV Community

Jitin Kumar
Jitin Kumar

Posted on

Sloth-Sorter: An Offline, CPU-Only File Organiser Powered by Local SLMs

Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady Submission 🦥

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady.

What I Built

sloth-sorter is a zero-dependency, offline daemon that automatically categorises and renames chaotic files in your Downloads directory using local Small Language Models (SLMs). Instead of letting files pile up as scan_0031 (2).pdf or final_v2_edited.docx, it inspects the file content and moves it into a structured Sorted/<category>/ directory with a deterministic, semantic filename like 2026-10-19-acme-invoice-42.pdf.

It is designed for developers who want an automated filesystem without sending personal documents to external APIs or burning GPU cycles. Because automated file operations carry inherent risk, the architecture prioritises safety:

  • Dry Run by Default: Previews the entire execution plan and proposed diffs before touching the filesystem.
  • Transactional Und o Log: Tracks every batch operation in SQLite, allowing instant, single-command rollbacks to restore original paths and filenames.
  • Declarative Config Rules: Uses plain-English routing rules in a local configuration file so you can adjust categorisation logic without modifying the source code.

Demo

sloth-sorter terminal execution

Code

GitHub logo Jitin2102 / HactoberFest-Challenges-Week-3

hactoberfest week 3 challenge

HactoberFest-Challenges-Week-3

🦥 sloth-sorter

A lazy, fully local file tidier. A small open-weight model (via Ollama) reads each new file in your Downloads folder, picks a category, gives it a sensible name, and files it away. Nothing leaves your machine. Every move is logged so you can undo it.

Setup (CPU-only is fine)

# 1. Install Ollama (https://ollama.com), then:
ollama pull qwen2.5:3b          # ~2 GB, runs on CPU. Try qwen2.5:1.5b if it's slow.
# 2. Optional, for PDF text:
pip install pypdf
# 3. Edit config.toml (folders, categories, plain-English rules)
Enter fullscreen mode Exit fullscreen mode

Needs Python 3.11+. No other dependencies.

Use

python sloth_sorter.py plan              # dry run (default), moves nothing
python sloth_sorter.py apply             # do it
python sloth_sorter.py undo              # reverse the last batch
python sloth_sorter.py watch --interval 600   # tidy every 10 minutes
python sloth_sorter.py bench --models qwen2.5:1.5b,qwen2.5:3b,llama3.2:3b
Enter fullscreen mode Exit fullscreen mode

How it stays safe

  • Dry run is the default; apply is explicit.
  • Skips hidden files, partial…

How I Built It

The core constraint was building a tool that runs reliably on a standard CPU-only laptop without bloating the Python environment.

  • Inference Engine: Runs ``locally via Ollama. At 3 billion parameters, it hits the sweet spot between CPU token generation speed and instruction-following accuracy for structured output.
  • Zero-Dependency Core: Built strictly on the Python standard library (urllib.request, sqlite3, pathlib, `), communicating directly with Ollama's local REST API (http://localhost:11434/api/generate`{% endraw %}). Optional PDF text extraction is supported if {% raw %}pypdf is present in the environment.
  • Execution Pipeline:
    1. Ingestion & Filtering: Scans the target directory while ignoring hidden dot-files, active browser .crdownload/.part buffers, and files with open write locks.
  • Context Extraction: Reads file metadata and extracts a bounded text header from plaintext, source code, .docx (via standard zipfile XML parsing), and PDFs.
  • Constrained Inference: Prompts the local model to return a strict JSON payload.
  • Validation & Sanitisation: Verifies the output against an allowed category whitelist, strips illegal filesystem characters, and resolves naming collisions automatically (-2, -3).
    1. Atomic Move & Logging: Executes the file transfer and commits the transaction ID, source path, and destination path to a local SQLite database.
  • Deterministic Guardrails: If the LLM hallucinates an invalid schema or Ollama times out, the pipeline degrades gracefully to a deterministic extension-based fallback router so a bad inference never crashes the batch run.
  • Built-in Benchmarking (bench): Includes a benchmarking CLI command that runs a test suite of files across multiple local models (qwen2.5:1.5b, qwen2.5:3b, llama3.2:3b) to measure latency per file and category agreement on your specific hardware.

Why Does Open Innovation Matter?

  • Strict Data Privacy: A folder is a goldmine of sensitive data—bank statements, tax forms, IDs, and private keys. Running open-weight models locally guarantees zero data exfiltration; not a single byte leaves.
  • Zero Marginal Cost: Cloud LLM APIs charge per token, which makes background system utilities economically impractical. Local inference turns file organisation into a free, background OS primitive that works completely offline.
  • Model Agnostic & Swappable: Relying on open weights prevents vendor lock-in. Using the bench command, I was able to empirically test different parameter sizes and quantisation levels (qwen2.5 vs. llama3.2) and select the exact model that matched my CPU's thermal and latency constraints.
  • Auditable & Hackable: Open-source tooling paired with local models means you control both the system prompt and the routing engine. Adding a custom rule like "Route receipts into /finance and prefix with the vendor name" takes one line of config rather than waiting on a SaaS feature request.

The Lazy Payoff

Rather than racing for sub-second cloud latency, 'sloth-sorter' embraces the "slow and steady" philosophy: it quietly processes files in the background on CPU threads while I focus on actual work.

In a test run across a cluttered directory of ** mixed files** (PDFs, code snippets, archives, and docs), it categorised and renamed the entire batch in ~3.5 minutes on CPU—saving ~20 minutes of manual inspection and renaming. When one ambiguous document was misclassified during testing, a single undo command cleanly reverted the batch, and a one-line tweak to the plain-English rules fixed the behaviour permanently.

Top comments (0)