All projects
● CompletePrivate source

d-Organizer

Undo designed in before anything got fast. Duplicates found by hash, since names lie.

Sole developer · Apr 2026 – May 2026

The problem is narrow: a Downloads folder holding the same PDF five times under five names, where nothing about the names tells you they match. Content hashes do. The harder half was trust — a tool that relocates thousands of a person’s files earns it by being reversible, so the journal and the undo command came before any of the work that made repeat scans fast.

221
Tests across 16 files
36
Tracked files in the whole repo
0
Network calls, by design

How it works

A scan walks the tree, hashes each file with SHA256, and records path, size, modified time, extension, and category in a SQLite manifest. Later scans compare the cheap metadata first and skip rehashing anything unchanged, which is what makes running it weekly over a large directory reasonable rather than punishing. Classification maps file extensions onto a preset category tree. Moves are two-phase: the intent is journaled, the move happens, then the entry is marked complete. An interrupted run is therefore still recoverable, and undo replays the journal in reverse. The read-only commands are separated from the single command that touches files, and that one refuses to run without an explicit confirmation flag. Destination collisions get a numeric suffix instead of an overwrite, path traversal is rejected before any I/O, and Windows long paths are handled.

Why the test count looks wrong

221 tests across 16 files, against 36 tracked files in the entire repo. The ratio is deliberate. Classification, deduplication, the journal, the manifest, the scanner, the safety rules, and the CLI each get their own test file, because the failure mode for this tool is someone’s files sitting in the wrong place with no obvious way back. The rest of the discipline is in what it refuses to do. One runtime dependency, no network, no telemetry, no account. It does one job and stops, which is why it is the only thing I have built that has an ending instead of a backlog.

Built with

Python 3.11TyperSQLiteSHA256pytestsetuptools